@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(0);
}

void setup () {

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

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

    if (!Rtc.IsDateTimeValid()) {
        // Common Causes: 1) first time you ran and the device wasn't running yet 2) the battery on the device is low or even missing
        Serial.println("RTC lost confidence in the DateTime!");
        Rtc.SetDateTime(compiled);
    }

    if (Rtc.GetIsWriteProtected()) {
        Serial.println("RTC was write protected, enabling writing now");
        Rtc.SetIsWriteProtected(false);
    }

    if (!Rtc.GetIsRunning()) {
        Serial.println("RTC was not actively running, starting now");
        Rtc.SetIsRunning(true);
    }

    RtcDateTime now = Rtc.GetDateTime();
    if (now < compiled) {
        Serial.println("RTC is older than compile time!  (Updating DateTime)");
        Rtc.SetDateTime(compiled);
    }
    else if (now > compiled)
        Serial.println("RTC is newer than compile time. (this is expected)");
    else
        Serial.println("RTC is the same as compile time! (not expected but all is fine)");
}

void loop () {
    RtcDateTime now = Rtc.GetDateTime();
    printDateTime(now);
    if (!now.IsValid()) {
        // Common Causes: 1) the battery on the device is low or even missing and the power line was disconnected
        lcd.print("RTC lost confidence in the DateTime!");
    }
  
    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);
}

  • Вопрос задан
  • 140 просмотров
Решения вопроса 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;
    }
}
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 2
Daemon23RUS
@Daemon23RUS
Посмотрите библиотеки здесь https://www.arduino.cc/reference/en/libraries/
Возможно найдете что то подходящее под Ваши цели.
Ответ написан
@kalapanga
Тут пока нечему криво работать - кода установки времени ещё совсем нет.
Выводите на экран например текущее время из часов. Ставите курсор на первую цифру. Дальше разбираете нажатия кнопок. Вверх и вниз пусть меняют выбранную цифру (контролируете значения), влево и вправо пусть будут переходом к другой цифре. Селект пусть завершает ввод и записывает получившееся значение в часы. Очень кратко если, то как-то так.
При нежелании самому придумывать можно найти готовые примеры кода. Уж часов на ардуино понаделана масса!
Совсем по феньшую будет освоить конечные автоматы.
Ответ написан
Комментировать
Ваш ответ на вопрос

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

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