#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;
}
}