#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <RTClib.h>
LiquidCrystal_I2C lcd(0x27, 20, 4); // Адреса I2C і розмір LCD
RTC_DS1307 rtc;
const int relayPin = 7; // Пін для підключення реле
const int buttonK1 = 2;
const int buttonK2 = 3;
const int buttonK3 = 4;
// змінні для встановлення інтервалу
unsigned long currentTime, previousTime = 0, previousTimerTime = 0;
int timerInterval = 1000;
// змінні для обчислення тривалості натиснення кнопок
unsigned long previousBtnK1Time = 0 , previousBtn2Time = 0, previousBtn3Time = 0;
// змінні для визначення режиму роботи
boolean mainTimerMode = true, timerScreenMode = false, changeTimeMode = false;
boolean blinkHour = false;
boolean changeTimeK2 = false, changeTimeK3 = false; // чи змінювати час
boolean isBtnShortClicked = false, isBtnLongClicked = false;
boolean isHours = true, isMinutes = false, isSeconds = false, timer = true; // який час змінювати
boolean wasBtnPressed = false;
boolean blink = false;
unsigned long btnPressedTime = 1000, btnInterval = 10000;
int lastButtonK1State = HIGH, lastButtonK2State = HIGH, lastButtonK3State = HIGH;
unsigned long lastDebounceTimeK1 = 0, lastDebounceTimeK2 = 0, lastDebounceTimeK3 = 0, lastDebounceTime = 0;
unsigned long debounceDelay = 50;
DateTime timerON;
DateTime timerOFF;
void setup() {
lcd.begin(20, 4);
if (!rtc.begin()) {
lcd.print("Couldn't find RTC");
while (1);
}
if (!rtc.isrunning()) {
lcd.print("RTC is NOT running!");
}
pinMode(relayPin, OUTPUT);
pinMode(buttonK1, INPUT_PULLUP);
pinMode(buttonK2, INPUT_PULLUP);
pinMode(buttonK3, INPUT_PULLUP);
timerON = rtc.now();
timerOFF = rtc.now();
}
void displayTimer(DateTime now) {
lcd.clear();
lcd.setCursor(0,0);
lcd.print(now.hour(), DEC);
lcd.print(':');
lcd.print(now.minute(), DEC);
lcd.print(':');
lcd.print(now.second(), DEC);
}
void displayTimerScreen() {
String tON = "T.ON=";
String tOFF = "T.OFF=";
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(tON);
lcd.print(timerON.hour(), DEC);
lcd.print(':');
lcd.print(timerON.minute(), DEC);
lcd.print(':');
lcd.print(timerON.second(), DEC);
lcd.setCursor(0, 1);
lcd.print(tOFF);
lcd.print(timerOFF.hour(), DEC);
lcd.print(':');
lcd.print(timerOFF.minute(), DEC);
lcd.print(':');
lcd.print(timerOFF.second(), DEC);
if (blinkHour) {
int row = timer ? 0 : 1;
int add = timer ? tON.length() : tOFF.length();
if (isHours) {
lcd.setCursor(add + 0, row);
} else if (isMinutes) {
lcd.setCursor(add + 3, row);
} else if (isSeconds) {
lcd.setCursor(add + 6, row);
}
if (blink) {
lcd.print(" ");
}
blink = !blink;
}
}
void increaseScreenTimerValue(int hours, int minutes, int seconds, boolean timer) {
if (timer) {
timerON = timerON + TimeSpan(0, hours, minutes, seconds);
} else {
timerOFF = timerOFF + TimeSpan(0, hours, minutes, seconds);
}
}
void decreaseScreenTimerValue(int hours, int minutes, int seconds, boolean timer) {
if (timer) {
timerON = timerON - TimeSpan(0, hours, minutes, seconds);
} else {
timerOFF = timerOFF - TimeSpan(0, hours, minutes, seconds);
}
}
bool isTimeInRange(DateTime currentTime, DateTime startTime, DateTime endTime) {
return (currentTime >= startTime && currentTime <= endTime);
}
void loop() {
DateTime now = rtc.now();
currentTime = millis();
// оновлення виводу таймеру при режимі основного екрану
if(currentTime - previousTime >= timerInterval) {
previousTime = currentTime;
if (mainTimerMode) {
displayTimer(now);
}
}
// debounce кнопок
int buttonK1State = digitalRead(buttonK1);
int buttonK2State = digitalRead(buttonK2);
int buttonK3State = digitalRead(buttonK3);
if (buttonK1State != lastButtonK1State) {
lastDebounceTimeK1 = currentTime;
lastDebounceTime = lastDebounceTimeK1;
}
if (buttonK2State != lastButtonK2State) {
lastDebounceTimeK2 = currentTime;
lastDebounceTime = lastDebounceTimeK2;
}
if (buttonK3State != lastButtonK3State) {
lastDebounceTimeK3 = currentTime;
lastDebounceTime = lastDebounceTimeK3;
}
if (timerScreenMode) { // Якщо активний режим "екран таймера"
if(currentTime - previousTimerTime >= timerInterval) {
displayTimerScreen();
previousTimerTime = currentTime;
}
if (changeTimeMode) { // режим зміни часу
if (currentTime - lastDebounceTimeK2 > debounceDelay) {
// перевірка чи коротко натиснута кнопка чи ні
if (buttonK2State == LOW) {
if (currentTime - previousBtn2Time < btnPressedTime) {
changeTimeK2 = true;
} else {
changeTimeK2 = false;
}
} else {
previousBtn2Time = currentTime;
}
}
if (changeTimeK2 && buttonK2State == HIGH) { // якщо кнопку відпустили і вона була коротко натиснена
changeTimeK2 = false;
if (isHours) increaseScreenTimerValue(1, 0, 0, timer);
else if (isMinutes) increaseScreenTimerValue(0, 1, 0, timer);
else increaseScreenTimerValue(0, 0, 1, timer);
}
if (currentTime - lastDebounceTimeK3 > debounceDelay) {
// перевірка чи коротко натиснута кнопка чи ні
if (buttonK3State == LOW) {
if (currentTime - previousBtn3Time < btnPressedTime) {
changeTimeK3 = true;
} else {
changeTimeK3 = false;
}
} else {
previousBtn3Time = currentTime;
}
}
if (changeTimeK3 && buttonK3State == HIGH) { // якщо кнопку відпустили і вона була коротко натиснена
changeTimeK3 = false;
if (isHours) decreaseScreenTimerValue(1, 0, 0, timer);
else if (isMinutes) decreaseScreenTimerValue(0, 1, 0, timer);
else decreaseScreenTimerValue(0, 0, 1, timer);
}
if (currentTime - lastDebounceTimeK1 > debounceDelay) {
// перевірка чи коротко натиснута кнопка чи ні
if (buttonK1State == LOW) {
if ((currentTime - previousBtnK1Time) < btnPressedTime) {
isBtnShortClicked = true;
} else {
isBtnShortClicked = false;
isBtnLongClicked = true;
}
} else {
previousBtnK1Time = currentTime;
}
}
if (buttonK1State == HIGH) { // якщо кнопку відпустили
if (isBtnShortClicked) { // коротко натиснута => зміна часу, який міняється
isBtnShortClicked = false;
if (isHours) {
isMinutes = isHours;
isHours = !isHours;
} else if (isMinutes) {
isSeconds = isMinutes;
isMinutes = !isMinutes;
} else {
timer = !timer;
isHours = isSeconds;
isSeconds = !isSeconds;
}
} else if (isBtnLongClicked) { // довго => перехід до режиму основного екрану
isBtnLongClicked = false;
mainTimerMode = true;
timerScreenMode = false;
blinkHour = false;
changeTimeMode = false;
}
}
} else { // перевірка на довге натиснення при активному режимі екран таймера
if (currentTime - lastDebounceTimeK1 > debounceDelay) {
// перевірка чи коротко натиснута кнопка чи ні
if (buttonK1State == LOW) {
if ((currentTime - previousBtnK1Time) >= btnPressedTime) {
isBtnLongClicked = true;
}
} else if (isBtnLongClicked) {
isBtnLongClicked = false;
changeTimeMode = true;
blinkHour = true;
} else {
previousBtnK1Time = currentTime;
}
}
}
} else {
if ((currentTime - lastDebounceTimeK1) > debounceDelay) {
if (buttonK1State == LOW && !wasBtnPressed) { // Якщо кнопку натиснуто
// перевірка чи коротко натиснута кнопка чи ні
if (currentTime - previousBtnK1Time < btnPressedTime) {
isBtnShortClicked = true;
} else {
isBtnShortClicked = false;
}
} else if (isBtnShortClicked) { // Якщо кнопку натиснуто коротко
wasBtnPressed = true;
mainTimerMode = false;
if(currentTime - previousTimerTime >= timerInterval) {
displayTimerScreen();
previousTimerTime = currentTime;
}
if (currentTime - previousBtnK1Time >= btnInterval) { // перевірка чи пройшло 10с
isBtnShortClicked = false;
mainTimerMode = true;
wasBtnPressed = false;
} else { // якщо ще не пройшло, то перевіряємо чи натиснута хоча б одна кнопка
if ((currentTime - lastDebounceTime) > debounceDelay) {
boolean isAnyBtnPressed = digitalRead(buttonK1) == LOW || buttonK2State == LOW || buttonK3State == LOW;
if (isAnyBtnPressed) {
timerScreenMode = true;
isBtnShortClicked = false;
previousBtnK1Time = currentTime;
wasBtnPressed = false;
}
}
}
} else {
previousBtnK1Time = currentTime;
}
}
}
lastButtonK1State = buttonK1State;
lastButtonK2State = buttonK2State;
lastButtonK3State = buttonK3State;
bool isRelayOn = isTimeInRange(now, timerON, timerOFF);
if (isRelayOn) {
digitalWrite(relayPin, HIGH); // Увімкнути реле
} else {
digitalWrite(relayPin, LOW); // Вимкнути реле
}
}