Доброго дня друзья. Прошу совета.. разрабатываю контроллер температуры для сауны. На данном этапе уже проведены работы по добавлению необходимых библиотек, определение всех переменных для работы, в setuoвывод стартовой информации температуры считанной с датчика, сохранённых установок с eeprom температуры, гистерезиса, режима поддержания температуры в паузах между работой таймеров, вывод сохранённых данных с таймера( пока он один). В loop сделан отрисовка статического интерфейса, работа динамического интерфейса, вывод часов реального времени аналоговые и цифровые указатели температуры и влажности, осталось сделать навигацию по режимам работы. Вход в меню по длительному удержанию кнопки энкодера, навигация по меню, переключение между пунктами установки текущего времени, температурного режима, гистерезиса, режима поддержания температуры, и пока реализована одна функция установки значения таймера для включения и выключения. И проблема собственно заключается вот в чем: при навигации по меню настроек при вращении энкодера для перехода между пунктами меню нет ни каких пропусков при вращении энкодера, так же энкодер четко откликается в меню настройки текущего времени, установки температуры, установки гистерезиса, и режима поддержания температуры. А вот с меню настройки таймеров дико тупит в плане пропуска шагов при его вращении даже в навигации этого меню, единственное что заметил если поворачивать энкодер на один шаг с паузой в 1-2 секунды тогда навигация по меню настроек таймера вполне себя хорошо ведёт но примерно 9 из 10 шагов энкодера, такой же эффект наблюдается при входе в пункт редактирования установки времени работы таймера. Подскажите пожалуйста как можно решить проблему без грубого вмешательства в готовый уже скетч.
Спасибо за ранее всем откликнувшимся.
Спасибо за ранее всем откликнувшимся.
"SET_TIMER_1_PAGE":
// --- ЛОГИКА СТРАНИЦЫ УСТАНОВКИ ТАЙМЕР 1 (SET_TIMER_1_PAGE) ---
if (currentPage == "SET_TIMER_1_PAGE") {
// ИНИЦИАЛИЗАЦИЯ ТАЙМЕРА ПРИ ВХОДЕ НА СТРАНИЦУ
// --- ПРОВЕРКА БЕЗДЕЙСТВИЯ (10 сек) ---
if (millis() - timerInactivityTimer > inactivityTime) {
tft->fillScreen(COLOR_BACKGROUND);
t1HourON1 = EEPROM.read(4);
t2MinuteON1 = EEPROM.read(5);
t3HourOFF1 = EEPROM.read(6);
t4MinuteOFF1 = EEPROM.read(7);
currentPage = "SET_PAGE";
isStaticDrawn = false;
isSetPageDrawn = false;
isSetTimePageDrawn = false;
isSetTempPageDrawn = false;
isSetFrostPageDrawn = false;
isSetHystPageDrawn = false;
isSetTimerPageDrawn = false;
mainInactivityTimer = millis(); // Сбрасываем таймер MAIN_PAGE
tempInactivityTimer = millis(); // Сбрасываем таймер для новой страницы
setInactivityTimer = millis(); // Сбрасываем таймер SET_PAGE при возврате
timeInactivityTimer = millis();
hystInactivityTimer = millis();
frostInactivityTimer = millis();
timerInactivityTimer = millis();
return;
}
// --- ЗАГРУЖАЕМ СТРАНИЦУ SetTimerpage ЕСЛИ ОНА НЕ ЗАГРУЖЕНА ---
if (!isSetTimerPageDrawn) {
drawSetTimerpage();
t1HourON1 = EEPROM.read(4);
t2MinuteON1 = EEPROM.read(5);
t3HourOFF1 = EEPROM.read(6);
t4MinuteOFF1 = EEPROM.read(7);
tft->setTextSize(2);
tft->setTextColor(COLOR_WHITE);
tft->setCursor(200, 20);
tft->print(" " );
tft->print(activeTimerNumber);
tft->print(" >");
/* tft->setCursor(189, 90);
if (t1HourON1 >= 0 && t1HourON1 <= 23) {
tft->print(t1HourON1);
} else {
tft->print("--");}
tft->setCursor(240, 90);
if (t2MinuteON1 >= 0 && t2MinuteON1 <= 59) {
tft->print(t2MinuteON1);
} else {
tft->print("--");}
/*tft->setCursor(195, 140);
if (t3HourOFF1 >= 0 && t3HourOFF1 <= 23) {
tft->print(t3HourOFF1);
} else {
tft->print("--");}
tft->setCursor(232, 140);
if (t4MinuteOFF1 >= 0 && t4MinuteOFF1 <= 59) {
tft->print(t4MinuteOFF1);
} else {
tft->print("--");}
*/
isSetTimerPageDrawn = true;
}
// временные переменные для хранения установленного времени включения и выключения
static byte lastt1HourON1 = -1; // Временные часы включения
static byte lastt2MinuteON1 = -1; // Временные минуты включения
static byte lastt3HourOFF1 = -1; // Временные часы выключения
static byte lastt4MinuteOFF1 = -1; // Временные минуты выключения
// приравниваем временные значения к установленным
lastt1HourON1 = t1HourON1;
lastt2MinuteON1 = t2MinuteON1;
lastt3HourOFF1 = t3HourOFF1;
lastt4MinuteOFF1 = t4MinuteOFF1;
// --- ЕСЛИ МЫ В РЕЖИМЕ НАВИГАЦИИ (МЕНЯЕМ ВЫДЕЛЕНИЕ) ---
if (timerMenuState == TIMER_NAVIGATING) {
static unsigned long lastNavTime = 0; // Переменная для хранения времени последнего шага
const unsigned long navDelay = 150; // Задержка между шагами (150 миллисекунд)
byte prevItem = selectedTimerItem;
if (enc1.isRight()/[I]&& (millis() - lastNavTime > navDelay)[/I]/) {
/[I]lastNavTime = millis();[/I]/
timerInactivityTimer = millis();
selectedTimerItem++;
if (selectedTimerItem > TIMER_EXIT) selectedTimerItem = TIMER_H_ON;
updateSetTimerItem(prevItem, false);
updateSetTimerItem(selectedTimerItem, true);}
if (enc1.isLeft()/[I]&& (millis() - lastNavTime > navDelay)[/I]/) {
/[I]lastNavTime = millis();[/I]/
timerInactivityTimer = millis();
selectedTimerItem--;
if (selectedTimerItem < TIMER_H_ON) selectedTimerItem = TIMER_EXIT;
updateSetTimerItem(prevItem, false);
updateSetTimerItem(selectedTimerItem, true);}
}
// --- ЛОГИКА КЛИКА ПО КНОПКЕ ---
if (enc1.isClick()) {
timerInactivityTimer = millis();
// --- ВЫХОД ПО ПУНКТУ "EXIT" ---
if (selectedTimerItem == TIMER_EXIT) {
tft->fillScreen(COLOR_BACKGROUND);
currentPage = "SET_PAGE";
isStaticDrawn = false;
isSetPageDrawn = false;
isSetTimePageDrawn = false;
isSetTempPageDrawn = false;
isSetFrostPageDrawn = false;
isSetHystPageDrawn = false;
isSetTimerPageDrawn = false;
mainInactivityTimer = millis(); // Сбрасываем таймер MAIN_PAGE
tempInactivityTimer = millis(); // Сбрасываем таймер для новой страницы
setInactivityTimer = millis(); // Сбрасываем таймер SET_PAGE при возврате
timeInactivityTimer = millis();
hystInactivityTimer = millis();
frostInactivityTimer = millis();
timerInactivityTimer = millis();
return;}
// --- ПУНКТ "SAVE" ---
if (selectedTimerItem == TIMER_SAVE) {
timerInactivityTimer = millis();
// --- ПРОВЕРКА ЦЕЛОСТНОСТИ ДАННЫХ ---
// Проверяем, что и время ВКЛЮЧЕНИЯ, и время ВЫКЛЮЧЕНИЯ установлены (валидны)
bool isOnTimeValid = (t1HourON1 >= 0 && t1HourON1 <= 23) && (t2MinuteON1 >= 0 && t2MinuteON1 <= 59);
bool isOffTimeValid = (t3HourOFF1 >= 0 && t3HourOFF1 <= 23) && (t4MinuteOFF1 >= 0 && t4MinuteOFF1 <= 59);
if (isOnTimeValid && isOffTimeValid) {
// --- ЕСЛИ ДАННЫЕ ВАЛИДНЫ: СОХРАНЯЕМ В EEPROM ---
EEPROM.update(4, t1HourON1);
EEPROM.update(5, t2MinuteON1);
EEPROM.update(6, t3HourOFF1);
EEPROM.update(7, t4MinuteOFF1);
// --- ВИЗУАЛЬНАЯ ПОДТВЕРЖДЕНИЕ (ТВОЯ ИДЕЯ) ---
// Сбрасываем таймер для смены цвета надписи "SAVE"
saveColorTimer = millis();
} else {
// --- ЕСЛИ ДАННЫЕ НЕВАЛИДНЫ: СБРАСЫВАЕМ В ПАМЯТИ В 255 ---
// если таймер настроен криво, мы стираем его из памяти
EEPROM.update(4, 255);
EEPROM.update(5, 255);
EEPROM.update(6, 255);
EEPROM.update(7, 255);
}
return; // Выходим из блока клика
}
// --- ПУНКТ "CLEAR" ---
if (selectedTimerItem == TIMER_CLEAR) {
timerInactivityTimer = millis();
clearColorTimer = millis();
EEPROM.update(4, 255);
EEPROM.update(5, 255);
EEPROM.update(6, 255);
EEPROM.update(7, 255);
t1HourON1 = 255;
t2MinuteON1 = 255;
t3HourOFF1 = 255;
t4MinuteOFF1 = 255;
isSetTimerPageDrawn = false;
return;
}
// --- ВХОД/ВЫХОД ИЗ РЕЖИМА РЕДАКТИРОВАНИЯ ---
// Проверяем клик на часы или минуты (ВКЛ или ВЫКЛ)
if (selectedTimerItem == TIMER_H_ON || selectedTimerItem == TIMER_M_ON ||
selectedTimerItem == TIMER_H_OFF || selectedTimerItem == TIMER_M_OFF) {
// --- ВХОД В РЕЖИМ РЕДАКТИРОВАНИЯ ---
// Если мы сейчас в режиме навигации, то входим в редактирование
if (timerMenuState == TIMER_NAVIGATING) {
// Входим в режим редактирования того пункта, на который кликнули
if (selectedTimerItem == TIMER_H_ON) {
timerMenuState = TIMER_ON_EDITING_H;
// Проверяем, является ли текущее значение валидным для часов включения (0-23)
if (lastt1HourON1 < 0 || lastt1HourON1 > 23) {
// Если значение НЕВАЛИДНО (больше 23), то присваиваем 0
lastt1HourON1 = 0;}
} else if (selectedTimerItem == TIMER_M_ON) {
timerMenuState = TIMER_ON_EDITING_M;
// Проверяем, является ли текущее значение валидным для минут включения (0-59)
if (lastt2MinuteON1 < 0 || lastt2MinuteON1 > 59) {
// Если значение НЕВАЛИДНО (больше 59), то присваиваем 0
lastt2MinuteON1 = 0;}
} else if (selectedTimerItem == TIMER_H_OFF) {
timerMenuState = TIMER_OFF_EDITING_H;
// Проверяем, является ли текущее значение валидным для часов выключения (0-23)
if (lastt3HourOFF1 < 0 || lastt3HourOFF1 > 23) {
lastt3HourOFF1 = 0;}
} else if (selectedTimerItem == TIMER_M_OFF) {
timerMenuState = TIMER_OFF_EDITING_M;
// Проверяем, является ли текущее значение валидным для минут выключения (0-59)
if (lastt4MinuteOFF1 < 0 || lastt4MinuteOFF1 > 59) {
lastt4MinuteOFF1 = 0;}
}
}
// --- ВЫХОД ИЗ РЕЖИМА РЕДАКТИРОВАНИЯ ---
// Если мы УЖЕ находимся в режиме редактирования этого же пункта, выходим
else if ((selectedTimerItem == TIMER_H_ON && timerMenuState == TIMER_ON_EDITING_H) ||
(selectedTimerItem == TIMER_M_ON && timerMenuState == TIMER_ON_EDITING_M) ||
(selectedTimerItem == TIMER_H_OFF && timerMenuState == TIMER_OFF_EDITING_H) ||
(selectedTimerItem == TIMER_M_OFF && timerMenuState == TIMER_OFF_EDITING_M)) {
// Выходим из режима редактирования
timerMenuState = TIMER_NAVIGATING; }
}
}
// --- ЛОГИКА ВРАЩЕНИЯ ЭНКОДЕРА В РЕЖИМЕ РЕДАКТИРОВАНИЯ ЧАСОВ ВКЛЮЧЕНИЯ ---
else if (timerMenuState == TIMER_ON_EDITING_H) {
// Проверяем вращение ВПРАВО
if (enc1.isRight()) {
timerInactivityTimer = millis(); // Сбрасываем таймер
// Увеличиваем значение, но не более 23
if (lastt1HourON1 < 23) {
lastt1HourON1++; }
}
// Проверяем вращение ВЛЕВО
if (enc1.isLeft()) {
timerInactivityTimer = millis(); // Сбрасываем таймер
// Уменьшаем значение, но не менее 0
if (lastt1HourON1 > 0) {
lastt1HourON1--;}
}
}
// --- ЛОГИКА ВРАЩЕНИЯ ЭНКОДЕРА В РЕЖИМЕ РЕДАКТИРОВАНИЯ МИНУТ ВКЛЮЧЕНИЯ ---
else if (timerMenuState == TIMER_ON_EDITING_M) {
// Проверяем вращение ВПРАВО
if (enc1.isRight()) {
timerInactivityTimer = millis(); // Сбрасываем таймер
// Увеличиваем значение, но не более 59
if (lastt2MinuteON1 < 59) {
lastt2MinuteON1++;}
}
// Проверяем вращение ВЛЕВО
if (enc1.isLeft()) {
timerInactivityTimer = millis(); // Сбрасываем таймер
// Уменьшаем значение, но не менее 0
if (lastt2MinuteON1 > 0) {
lastt2MinuteON1--;}
}
}
//----------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------
// --- ЛОГИКА ВРАЩЕНИЯ ЭНКОДЕРА В РЕЖИМЕ РЕДАКТИРОВАНИЯ ЧАСОВ ВЫКЛЮЧЕНИЯ ---
else if (timerMenuState == TIMER_OFF_EDITING_H) {
// Проверяем вращение ВПРАВО
if (enc1.isRight()) {
timerInactivityTimer = millis(); // Сбрасываем таймер
// Увеличиваем значение, но не более 23
if (lastt3HourOFF1 < 23) {
lastt3HourOFF1++; }
}
// Проверяем вращение ВЛЕВО
if (enc1.isLeft()) {
timerInactivityTimer = millis(); // Сбрасываем таймер
// Уменьшаем значение, но не менее 0
if (lastt3HourOFF1 > 0) {
lastt3HourOFF1--;}
}
}
// --- ЛОГИКА ВРАЩЕНИЯ ЭНКОДЕРА В РЕЖИМЕ РЕДАКТИРОВАНИЯ МИНУТ ВЫКЛЮЧЕНИЯ ---
else if (timerMenuState == TIMER_OFF_EDITING_M) {
// Проверяем вращение ВПРАВО
if (enc1.isRight()) {
timerInactivityTimer = millis(); // Сбрасываем таймер
// Увеличиваем значение, но не более 59
if (lastt4MinuteOFF1 < 59) {
lastt4MinuteOFF1++;}
}
// Проверяем вращение ВЛЕВО
if (enc1.isLeft()) {
timerInactivityTimer = millis(); // Сбрасываем таймер
// Уменьшаем значение, но не менее 0
if (lastt4MinuteOFF1 > 0) {
lastt4MinuteOFF1--;}
}
}
//------------------------------------------------------------------------------------------------------
//--- Логика отрисовки установки часов таймера включения
tft->setTextSize(2);
tft->setTextColor( (timerMenuState == TIMER_ON_EDITING_H) ? COLOR_YELLOW : COLOR_WHITE );
tft->setCursor(189, 90);
if (lastt1HourON1 >= 0 && lastt1HourON1 <= 23) {
if (lastt1HourON1 < 10) tft->print("0");
tft->print(lastt1HourON1);
} else {
tft->setCursor(189, 90);
tft->print("--");}
if (t1HourON1 != lastt1HourON1) {
// СТИРАЕМ СТАРЫЕ значения цветом фона
tft->setTextSize(2);
tft->setTextColor(COLOR_BACKGROUND);
tft->setCursor(189, 90);
tft->print("--");
tft->setCursor(189, 90);
if (t1HourON1 < 10) tft->print("0");
tft->print(t1HourON1);
// РИСУЕМ НОВЫЕ ЧАСЫ. Цвет зависит от режима.
/* tft->setTextSize(2);
tft->setTextColor( (timerMenuState == TIMER_ON_EDITING_H) ? COLOR_YELLOW : COLOR_WHITE );
tft->setCursor(189, 90);
if (t1HourON1 >= 0 && t1HourON1 <= 23) {
if (t1HourON1 < 10) tft->print("0");
tft->print(t1HourON1);
} else {
tft->setCursor(189, 90);
tft->print("--");}*/
t1HourON1 = lastt1HourON1; // Обновляем для следующего сравнения
}
// --- ЛОГИКА ДЛЯ установки МИНУТ таймера включения ---
tft->setTextSize(2);
tft->setTextColor( (timerMenuState == TIMER_ON_EDITING_M) ? COLOR_YELLOW : COLOR_WHITE );
tft->setCursor(240, 90);
if (lastt2MinuteON1 >= 0 && lastt2MinuteON1 <= 59) {
if (lastt2MinuteON1 < 10) tft->print("0");
tft->print(lastt2MinuteON1);
} else {
tft->setCursor(240, 90);
tft->print("--");}
if (t2MinuteON1 != lastt2MinuteON1) {
// СТИРАЕМ СТАРЫЕ МИНУТЫ
tft->setTextSize(2);
tft->setTextColor(COLOR_BACKGROUND);
tft->setCursor(240, 90);
tft->print("--");
tft->setCursor(240, 90);
if (t2MinuteON1 < 10) tft->print("0");
tft->print(t2MinuteON1);
// РИСУЕМ НОВЫЕ МИНУТЫ. Цвет зависит от режима.
/*tft->setTextSize(2);
tft->setTextColor( (timerMenuState == TIMER_ON_EDITING_M) ? COLOR_YELLOW : COLOR_WHITE );
tft->setCursor(240, 90);
if (t2MinuteON1 >= 0 && t2MinuteON1 <= 59) {
if (t2MinuteON1 < 10) tft->print("0");
tft->print(t2MinuteON1);
} else {
tft->setCursor(240, 90);
tft->print("--");}*/
t2MinuteON1 = lastt2MinuteON1;
}
//------------------------------------------------------------------------------------------------------
//--- Логика отрисовки установки часов таймера вЫключения
tft->setTextSize(2);
tft->setTextColor( (timerMenuState == TIMER_OFF_EDITING_H) ? COLOR_YELLOW : COLOR_WHITE );
tft->setCursor(189, 140);
if (lastt3HourOFF1 >= 0 && lastt3HourOFF1 <= 23) {
if (lastt3HourOFF1 < 10) tft->print("0");
tft->print(lastt3HourOFF1);
} else {
tft->setCursor(189, 140);
tft->print("--");}
if (t3HourOFF1 != lastt3HourOFF1) {
// СТИРАЕМ СТАРЫЕ значения цветом фона
tft->setTextSize(2);
tft->setTextColor(COLOR_BACKGROUND);
tft->setCursor(189, 140);
tft->print("--");
tft->setCursor(189, 140);
if (t3HourOFF1 < 10) tft->print("0");
tft->print(t3HourOFF1);
// РИСУЕМ НОВЫЕ ЧАСЫ. Цвет зависит от режима.
/* tft->setTextSize(2);
tft->setTextColor( (timerMenuState == TIMER_OFF_EDITING_H) ? COLOR_YELLOW : COLOR_WHITE );
tft->setCursor(189, 140);
if (t3HourOFF1 >= 0 && t3HourOFF1 <= 23) {
if (t3HourOFF1 < 10) tft->print("0");
tft->print(t3HourOFF1);
} else {
tft->setCursor(189, 140);
tft->print("--");}*/
t3HourOFF1 = lastt3HourOFF1; // Обновляем для следующего сравнения
}
// --- ЛОГИКА ДЛЯ установки МИНУТ таймера вЫключения ---
tft->setTextSize(2);
tft->setTextColor( (timerMenuState == TIMER_OFF_EDITING_M) ? COLOR_YELLOW : COLOR_WHITE );
tft->setCursor(240, 140);
if (lastt4MinuteOFF1 >= 0 && lastt4MinuteOFF1 <= 59) {
if (lastt4MinuteOFF1 < 10) tft->print("0");
tft->print(lastt4MinuteOFF1);
} else {
tft->setCursor(240, 140);
tft->print("--");}
if (t4MinuteOFF1 != lastt4MinuteOFF1) {
// СТИРАЕМ СТАРЫЕ МИНУТЫ
tft->setTextSize(2);
tft->setTextColor(COLOR_BACKGROUND);
tft->setCursor(240, 140);
tft->print("--");
tft->setCursor(240, 140);
if (t4MinuteOFF1 < 10) tft->print("0");
tft->print(t4MinuteOFF1);
// РИСУЕМ НОВЫЕ МИНУТЫ. Цвет зависит от режима.
/* tft->setTextSize(2);
tft->setTextColor( (timerMenuState == TIMER_OFF_EDITING_M) ? COLOR_YELLOW : COLOR_WHITE );
tft->setCursor(240, 140);
if (t4MinuteOFF1 >= 0 && t4MinuteOFF1 <= 59) {
if (t4MinuteOFF1 < 10) tft->print("0");
tft->print(t4MinuteOFF1);
} else {
tft->setCursor(240, 140);
tft->print("--");}*/
t4MinuteOFF1 = lastt4MinuteOFF1;
}
//-----------------------------------------------------------------------------------
// --- ДИНАМИЧЕСКАЯ ОТРИСОВКА ПУНКТА "SAVE" ---
// Этот код выполняется в каждом цикле loop() для этой страницы
// Устанавливаем параметры текста
tft->setTextSize(2);
tft->setCursor(30, 203); // Координаты кнопки "SAVE"
// Проверяем, активен ли таймер смены цвета
// (Если с момента клика прошло меньше 2 секунды)
if (millis() - saveColorTimer < colorDuration) {
// Если ДА, рисуем ЗЕЛЕНЫМ
tft->setTextColor(COLOR_GREEN);
} else {
// Если НЕТ, рисуем БЕЛЫМ
tft->setTextColor(COLOR_WHITE);
}
// Печатаем саму надпись
tft->print("SAVE");
//----------------------------------------------------------------------------------------------------
// --- ДИНАМИЧЕСКАЯ ОТРИСОВКА ПУНКТА "CLEAR" ---
tft->setTextSize(2);
tft->setCursor(128, 203); // Координаты кнопки "CLEAR"
// Проверяем, активен ли таймер для кнопки CLEAR
if (millis() - clearColorTimer < colorDuration) {
// Если ДА, рисуем КРАСНЫМ
tft->setTextColor(COLOR_RED);
} else {
// Если НЕТ, рисуем БЕЛЫМ
tft->setTextColor(COLOR_WHITE);
}
tft->print("CLEAR");
//=====================================================================================================
// Небольшая задержка для работы страницы
static unsigned long lastSetTimerLoopTime = 0;
if (millis() - lastSetTimerLoopTime < 100){
return;}
lastSetTimerLoopTime = millis();
} // Скобка закрытия if (currentPage == "SET_TIMER_1_PAGE")