Задать вопрос
@SleepyBear09
Программист, со словарем

Как сделать так, чтобы при нажатии кнопки, на дисплее LCD перестало отображаться время, а заходил в контекстное меню?

Я написал код, при котором на дисплее показывает текущие время. Теперь нужно прописать, что при нажатии кнопки на LCD на дисплее мы переходили в контекстное меню, с последующей установкой времени и записью в память.
Распознавание кнопки я сделал, и даже отображение, что мы находимся в меню тоже но сразу же снова показывает текущие время. Не пойму как это сделать.
Мой код:
#include <ThreeWire.h>  
#include <RtcDS1302.h>
#include <LiquidCrystal.h>

ThreeWire myWire(10,11,12); // IO, SCLK, CE
RtcDS1302<ThreeWire> Rtc(myWire);

LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

#define BTN_UP   1
#define BTN_DOWN 2
#define BTN_LEFT 3
#define BTN_RIGHT 4
#define BTN_SELECT 5
#define BTN_NONE 10
bool setTimeMode = false;

int detectButton() {
  int keyAnalog =  analogRead(A0);
  if (keyAnalog < 100) {
    // Значение меньше 100 – нажата кнопка right
    return BTN_RIGHT;
  } else if (keyAnalog < 200) {
    // Значение больше 100 (иначе мы бы вошли в предыдущий блок результата сравнения, но меньше 200 – нажата кнопка UP
    return BTN_UP;
  } else if (keyAnalog < 400) {
    // Значение больше 200, но меньше 400 – нажата кнопка DOWN
    return BTN_DOWN;
  } else if (keyAnalog < 600) {
    // Значение больше 400, но меньше 600 – нажата кнопка LEFT
    return BTN_LEFT;
  } else if (keyAnalog < 800) {
    // Значение больше 600, но меньше 800 – нажата кнопка SELECT
    return BTN_SELECT;
  } else {
    // Все остальные значения (до 1023) будут означать, что нажатий не было
    return BTN_NONE;
  }
}

void clearLine(int line){
  lcd.setCursor(0, 1);
  lcd.print("                ");
}

void printDisplay(String message){
  lcd.setCursor(0, 1);
  lcd.print(message);
  delay(1000);
  clearLine(0);
  clearLine(1);
}

void setup () {

    lcd.begin(16, 2);
    lcd.setCursor(0, 0);
    printDisplay("compiled: ");
    printDisplay(__DATE__);

    Rtc.Begin();
    RtcDateTime compiled = RtcDateTime(__TIME__);
}

void loop () {
    RtcDateTime now = Rtc.GetDateTime();
    printDateTime(now);
  
    int button = detectButton();

    if (button == BTN_SELECT) {
        setTimeMode = !setTimeMode; // Переключение режима установки времени
        clearLine(0);
        if (setTimeMode) {
            printDisplay("Set Time Mode");
        } else {
            printDisplay("                "); // Очистка строки после выхода из режима установки времени
        }
        delay(500); // Задержка для избежания множественных обнаружений при удержании кнопки
    }  
}

#define countof(a) (sizeof(a) / sizeof(a[0]))

void printDateTime(const RtcDateTime& dt) {
    char datestring[9];
    snprintf_P(datestring, 
            countof(datestring),
            PSTR("%02u:%02u:%02u"),
            dt.Hour(), dt.Minute(), dt.Second() );
    printDisplay(datestring);
}
  • Вопрос задан
  • 91 просмотр
Подписаться 1 Средний 3 комментария
Решения вопроса 1
@SleepyBear09 Автор вопроса
Программист, со словарем
Закончил, использовал для этого функцию currentState. Получилось не совсем идеально, но свое предназначение исполняет хорошо.

Итоговый код
#include <ThreeWire.h>
#include <RtcDS1302.h>
#include <LiquidCrystal.h>
#include <EEPROM.h>

ThreeWire myWire(10, 11, 12); // IO, SCLK, CE
RtcDS1302<ThreeWire> Rtc(myWire);

LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

RtcDateTime now;

int selectedField = 0; // 0 - часы, 1 - минуты

const int relayPin = 2;

int hour = 11;
int minute = 33;

#define BTN_UP     1
#define BTN_DOWN   2
#define BTN_LEFT   3
#define BTN_RIGHT  4
#define BTN_SELECT 5
#define BTN_NONE   10

// Адреса в EEPROM для хранения времени
#define ADDR_HOUR   0
#define ADDR_MINUTE 1

void saveTimeToEEPROM(uint8_t hour, uint8_t minute) {
    EEPROM.write(ADDR_HOUR, hour);
    EEPROM.write(ADDR_MINUTE, minute);
}

void loadTimeFromEEPROM(uint8_t &hour, uint8_t &minute) {
    hour = EEPROM.read(ADDR_HOUR);
    minute = EEPROM.read(ADDR_MINUTE);
}

enum State {
    DISPLAY_TIME,
    SET_TIME_MENU,
    SET_HOUR,
    SET_MINUTE
};

State currentState = DISPLAY_TIME;

void clearLine(int line) {
    lcd.setCursor(0, line);
    lcd.print("                ");
}

void printDisplay(String message) {
    lcd.setCursor(0, 0);
    lcd.print(message);
    delay(1000);
    clearLine(0);
    clearLine(1);
}

int detectButton() {
  int keyAnalog =  analogRead(A0);
  if (keyAnalog < 100) {
    // Значение меньше 100 – нажата кнопка right
    return BTN_RIGHT;
  } else if (keyAnalog < 200) {
    // Значение больше 100 (иначе мы бы вошли в предыдущий блок результата сравнения, но меньше 200 – нажата кнопка UP
    return BTN_UP;
  } else if (keyAnalog < 400) {
    // Значение больше 200, но меньше 400 – нажата кнопка DOWN
    return BTN_DOWN;
  } else if (keyAnalog < 600) {
    // Значение больше 400, но меньше 600 – нажата кнопка LEFT
    return BTN_LEFT;
  } else if (keyAnalog < 800) {
    // Значение больше 600, но меньше 800 – нажата кнопка SELECT
    return BTN_SELECT;
  } else {
    // Все остальные значения (до 1023) будут означать, что нажатий не было
    return BTN_NONE;
  }
}

void updateDisplay() {
    RtcDateTime now = Rtc.GetDateTime();
    char timeString[16]; // формат времени "hh:mm:ss"

    // Форматируем строку времени в зависимости от текущего режима
    switch (currentState) {
        case SET_HOUR:
            snprintf_P(timeString, countof(timeString), PSTR("Set Hour: %02u"), hour);
            break;
        case SET_MINUTE:
            snprintf_P(timeString, countof(timeString), PSTR("Set Minute: %02u"), minute);
            break;
        default:
            snprintf_P(timeString, countof(timeString), PSTR("%02u:%02u:%02u"), now.Hour(), now.Minute(), now.Second());
            break;
    }

    // Обновляем дисплей
    lcd.setCursor(0, 0);
    lcd.print(timeString);
}

void handleTimeSetting(int button) {
    switch (currentState) {
        case DISPLAY_TIME:
            if (button == BTN_SELECT) {
                currentState = SET_TIME_MENU;
                clearLine(0);
                clearLine(1);
                printDisplay("Set Time Menu");
            }
            break;
        case SET_TIME_MENU:
            switch (button) {
                case BTN_NONE:
                    clearLine(0);
                    clearLine(1);
                    printDisplay("Set Time Mode");
                case BTN_UP:
                    currentState = SET_HOUR;
                    clearLine(0);
                    clearLine(1);
                    printDisplay("Set Hour");
                    break;
                case BTN_DOWN:
                    currentState = SET_MINUTE;
                    clearLine(0);
                    clearLine(1);
                    printDisplay("Set Minute");
                    break;
                case BTN_RIGHT:
                    currentState = DISPLAY_TIME;
                    clearLine(0);
                    clearLine(1);
                    printDisplay("Display Time");
                    clearLine(0);
                    clearLine(1);
                    break;
                // Добавьте обработку других кнопок при необходимости
            }
            break;
        case SET_HOUR:
        selectedField = 0;
           switch (button) {
                case BTN_UP:
                    currentState = SET_HOUR;
                    incrementSelectedField();
                    clearLine(0);
                    clearLine(1);
                    printDisplay("Set Hour");
                    break;
                case BTN_DOWN:
                    currentState = SET_HOUR;
                    decrementSelectedField();
                    clearLine(0);
                    clearLine(1);
                    printDisplay("Set Hour");
                    break;
                case BTN_RIGHT:
                    currentState = DISPLAY_TIME;
                    clearLine(0);
                    clearLine(1);
                    printDisplay("Display Time");
                    clearLine(0);
                    clearLine(1);
                    break;
                case BTN_LEFT:
                    currentState = SET_TIME_MENU;
                    clearLine(0);
                    clearLine(1);
                    printDisplay("Set Time Menu");
                    break;
                // Добавьте обработку других кнопок при необходимости
            }
            break; // Обработка установки часов, аналогично предыдущим примерам
            // Пример: при нажатии кнопки "Select" сохраняем часы и переходим обратно в меню
            if (button == BTN_SELECT) {
                saveTimeToEEPROM(hour, minute);
                currentState = SET_TIME_MENU;
                clearLine(0);
                clearLine(1);
                printDisplay("Display Time");
            }
            break;
        case SET_MINUTE:
           selectedField = 1;
           switch (button) {
                case BTN_UP:
                    currentState = SET_MINUTE;
                    incrementSelectedField();
                    clearLine(0);
                    clearLine(1);
                    printDisplay("Set Minute");
                  break;
                case BTN_DOWN:
                    currentState = SET_MINUTE;
                    decrementSelectedField();
                    clearLine(0);
                    clearLine(1);
                    printDisplay("Set Minute");
                break;
                case BTN_RIGHT:
                    currentState = DISPLAY_TIME;
                    clearLine(0);
                    clearLine(1);
                    printDisplay("Display Time");
                    clearLine(0);
                    clearLine(1);
                  break;
                case BTN_LEFT:
                    currentState = SET_TIME_MENU;
                    clearLine(0);
                    clearLine(1);
                    printDisplay("Set Time Menu");
                  break;
                // Добавьте обработку других кнопок при необходимости
            } // Обработка установки минут, аналогично предыдущим примерам
             // Пример: при нажатии кнопки "Select" сохраняем минуты и переходим обратно в меню
            if (button == BTN_SELECT) {
                saveTimeToEEPROM(now.Hour(), now.Minute());
                currentState = DISPLAY_TIME;
                clearLine(0);
                printDisplay("Display Time");
            }
            break;
    }
}

void setup() {
    Serial.begin(9600);
    lcd.begin(16, 2);
    lcd.setCursor(0, 0);
    printDisplay("compiled: ");
    printDisplay(__DATE__);
    pinMode(2, OUTPUT);

    Rtc.Begin();
    RtcDateTime compiled = RtcDateTime(__TIME__);

    // Загрузим время из EEPROM при старте программы
    uint8_t storedHour, storedMinute;
    loadTimeFromEEPROM(storedHour, storedMinute);

    // Выведем время из EEPROM
    lcd.setCursor(0, 0);
    lcd.print("Set time: ");
    char storedTimeString[16];
    snprintf_P(storedTimeString, countof(storedTimeString), PSTR("%02u:%02u"), hour, minute);
    lcd.print(storedTimeString);
    delay(2000);
    clearLine(0);
    clearLine(1);
}

void loop() {
    RtcDateTime now = Rtc.GetDateTime(); // Объявим переменную now здесь
    handleTimeSetting(detectButton());
    updateDisplay();

    if (!now.IsValid()) {
        lcd.print("RTC lost confidence in the DateTime!");
    }
  if (now.Hour() == hour && now.Minute() == minute && now.Second() == 0) {
    // Включаем реле на 3 секунды
    digitalWrite(relayPin, HIGH);
    delay(3000);
    digitalWrite(relayPin, LOW);
  }
}

#define countof(a) (sizeof(a) / sizeof(a[0]))

void setHour(uint8_t hour) {
    now = Rtc.GetDateTime();
    now = RtcDateTime(now.Year(), now.Month(), now.Day(), hour, now.Minute(), now.Second());
    Rtc.SetDateTime(now);
}

void setMinute(uint8_t minute) {
    now = Rtc.GetDateTime();
    now = RtcDateTime(now.Year(), now.Month(), now.Day(), now.Hour(), minute, now.Second());
    Rtc.SetDateTime(now);
}

void incrementSelectedField() {
    switch (selectedField) {
        case 0:
            hour = hour + 1;
            break;
        case 1:
            minute = minute + 1;
            break;
    }
}
void decrementSelectedField() {
    switch (selectedField) {
        case 0:
            hour = hour - 1;
            break;
        case 1:
            minute = minute - 1;
            break;
    }
}
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
Daemon23RUS
@Daemon23RUS
printDateTime(now);
В этом фрагменте надо добавить условие завязанное на setTimeMode
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы