// initializare librari pentru LCD si RTC
#include <LiquidCrystal_I2C.h>
#include "RTClib.h"
// initializare proprietati LCD I2C
#define I2C_ADDR 0x27
#define LCD_COLUMNS 16
#define LCD_LINES 2
// se declara obiect LCD
LiquidCrystal_I2C lcd(I2C_ADDR, LCD_COLUMNS, LCD_LINES);
// se declara obiect RTC
RTC_DS1307 rtc;
// Variabile pentru pinurile care sunt conectate la butoanele respective
int incHourPin = 8; // buton de incrementare ore
int incMinutePin = 9; // buton de incrementare minute
int incSecondPin = 10; // buton de incrementare secunde
int decHourPin = 11; // buton de decrementare ore
int decMinutePin = 12; // buton de decrementare minute
int decSecondPin = 13; // buton de decrementare secunde
int setTimerPin = 7; // buton de setare a timer-ului
int setAlarmPin = 6; // buton de setare a alarmei
int confirmPin = 5; // buton de confirmare a unei setari, reintoarcere la ecran sau anulare alarma manual
int buzzerPin = 4; // buzzer output pentru alarma
int switchPin = 3; // slide switch pentru schimbarea tipurilor de ecran
// initializare variable pentru ore, minute, secunde timer
int hours = 0;
int mins = 0;
int secs = 0;
// initializare variable pentru ore, minute, secunde alarma
int ahours = 0;
int amins = 0;
int asecs = 0;
// conditie buton "Set Timer"
bool buttonState = false;
// conditie buton "Set Alarm"
bool buttonState2 = false;
unsigned long buzzerStartTime = 0; // To track when the buzzer started
bool buzzerActive = false; // To check if the buzzer is currently active
// unsigned long starttime;
unsigned long currentMillis;
unsigned long prevMillis = 0;
// Variabile debouncing pentru butoane
unsigned long debounceDelay = 200; // intarziere debounce in milisecunde
// variabile pentru stocarea ultimii apasari de butoane in milisecunde
unsigned long lastButtonPressMillis_8 = 0; // buton incHourPin (cu pin 8)
unsigned long lastButtonPressMillis_9 = 0; // buton incMinutePin
unsigned long lastButtonPressMillis_10 = 0; // buton incSecondPin
unsigned long lastButtonPressMillis_11 = 0; // buton decHourPin
unsigned long lastButtonPressMillis_12 = 0; // buton decMinutePin
unsigned long lastButtonPressMillis_13 = 0; // buton decSecondPin
// functie pentru ecranul 1 (afisare data + ora)
void screen1();
// functie pentru ecranul 2 cu 2 meniuri (timer + alarma)
void screen2();
// functie actualizare timer in secunde
void secondsUpdater();
// functii pentru ecranul 2
void displayScreen2(); // afisare principal
void displayTimer(); // afisare timer
void logicTimer(); // logica timer
void displayAlarm(); // afisare alarma
void logicAlarm(); // logica alarma
void alarmTrigger(); // porneste si opreste alarma
void resetAlarmState(); // reseteaza alarma
void displayClock(int hours, int minutes, int seconds); // afisare ore:minute:secunde
// functie helper pentru displayClock
void displayCorrectTime(int timeUnit); // corecteaza afisarea cifrelor de ceas
void handleButtonPress(int buttonPin, unsigned long &lastPressTime, int &value, bool increment);
// caracter custom LCD clopot pentru alarma
byte customChar[8] = {
0b00000,
0b00100,
0b01110,
0b01110,
0b01110,
0b11111,
0b00100,
0b00000
};
// caracter custom LCD clepsidra pentru ora
byte customChar1[8] = {
0b11111,
0b10001,
0b01010,
0b00100,
0b00100,
0b01010,
0b10001,
0b11111
};
void setup() {
// initializare comunicare arduino cu calculatorul
Serial.begin(9600);
// initializare pinMode cu rezistor pullup intern de la arduino
pinMode(incHourPin, INPUT_PULLUP);
pinMode(incMinutePin, INPUT_PULLUP);
pinMode(incSecondPin, INPUT_PULLUP);
pinMode(decHourPin, INPUT_PULLUP);
pinMode(decMinutePin, INPUT_PULLUP);
pinMode(decSecondPin, INPUT_PULLUP);
pinMode(setTimerPin, INPUT_PULLUP);
pinMode(setAlarmPin, INPUT_PULLUP);
pinMode(confirmPin, INPUT_PULLUP);
pinMode(buzzerPin, OUTPUT);
pinMode(switchPin, INPUT_PULLUP);
// initializare LCD
lcd.begin(16, 2);
lcd.init();
lcd.backlight();
lcd.display();
// Verificare daca functioneaza RTC-ul
if (! rtc.begin()) {
Serial.println("Couldn't find RTC");
Serial.flush();
abort();
}
// creeare caractere custom LCD
lcd.createChar(0, customChar);
lcd.createChar(1, customChar1);
}
void loop() {
// pastreaza timpul curent de cand s-a compilat programul
currentMillis = millis();
// citeste conditia de la slide switch
int switchState = digitalRead(switchPin);
// valori statice pentru a se pastra la loop
static int lastSwitchState = LOW; // pastreaza conditia anterioara a switch-ului
static int currentScreen = 0; // verifica ce ecran este activ
// verifica daca s-a schimbat conditia switch-ului si schimba ecranele in acest caz
if (switchState != lastSwitchState) {
lastSwitchState = switchState; // actualizeaza ultima conditie de switch
lcd.clear(); // sterge ecranul LCD cand se schimba ecranele
if (switchState == HIGH) {
// schimba la ecranul 1 si pastreaza valoarea ecranului curent
currentScreen = 1;
screen1();
} else {
// schimba la ecranul 2 si pastreaza valoarea ecranului curent
currentScreen = 2;
screen2();
}
}
// actualizeaza ecranul in continuare odata selectat
if (currentScreen == 1) {
screen1();
} else {
screen2();
}
}
void screen1() {
// afisarea datei si a timpului actual cu ajutorul RTC-ului pe ecranul principal
// functia now() citeste data si timpul curent prin modulul RTC
// informatia se pastreaza in obiectul DateTime numit now
DateTime now = rtc.now();
// afisarea datei
lcd.setCursor(0, 0);
lcd.print("Data");
lcd.setCursor(6, 0);
lcd.print(now.day(), DEC); // zi
lcd.print('/');
lcd.print(now.month(), DEC); // luna
lcd.print('/');
lcd.print(now.year(), DEC); // an
// afisarea orei (ore:minute:secunde)
// daca valorile sunt sub 10, se afiseaza un 0 in fata cifrei
lcd.setCursor(0, 1);
lcd.print("Ora ");
lcd.setCursor(6, 1);
if (now.hour() < 10) { // ora
lcd.print(0);
lcd.print(now.hour(), DEC);
} else {
lcd.print(now.hour(), DEC);
}
lcd.print(':');
if (now.minute() < 10) { // minut
lcd.print(0);
lcd.print(now.minute(), DEC);
} else {
lcd.print(now.minute(), DEC);
}
lcd.print(':');
if (now.second() < 10) { // secunda
lcd.print(0);
lcd.print(now.second(), DEC);
} else {
lcd.print(now.second(), DEC);
}
// se afiseaza caracterul custom clepsidra
lcd.setCursor(15, 1);
lcd.write((byte)1);
}
void screen2() {
// actualizarea timer-ului in secunde (se incrementeaza ca la un ceas)
secondsUpdater();
// Butonul de setare a timer-ului
// daca se apasa pe buton, se sterge ecranul si se seteaza o conditie pentru buttonState
if(digitalRead(setTimerPin) == LOW) {
lcd.clear();
buttonState = true;
// pentru a putea muta dintre butonul 'set time' la 'set alarm'
buttonState2 = false;
}
// Butonul de setare a alarmei
if(digitalRead(setAlarmPin) == LOW) {
lcd.clear();
buttonState2 = true;
// pentru a putea muta dintre butonul 'set alarm' la 'set time'
buttonState = false;
}
// daca se apasa butonul de confirmare, se reintoarce la ecranul 2 principal
if (digitalRead(confirmPin) == LOW) {
buttonState = false;
buttonState2 = false;
lcd.clear(); // Clear the LCD when returning to main screen
}
// daca niciun buton nu a fost apasat afiseaza ecran 2 principal
if(buttonState == false && buttonState2 == false) {
displayScreen2();
} else if(buttonState == true) {
// daca butonul de set timer a fost apasat, afiseaza ecranul de timer
logicTimer();
displayTimer();
} else if (buttonState2 == true) {
// daca butonul de set alarma a fost apasat, afiseaza ecranul de alarma
logicAlarm();
displayAlarm();
}
// daca ora de la timer se potriveste cu ora de la alarma sau alarma este activa, sa se cheme functia
if(ahours == hours && amins == mins && asecs == secs && !buttonState2 || buzzerActive) {
alarmTrigger(); // functie de pornire si inchidere alarma
}
}
void secondsUpdater() {
// Actualizeaza secundele la fiecare secunda
if (currentMillis - prevMillis >= 1000) { // Daca a trecut o secunda
prevMillis = currentMillis; // Actualizeaza prevMillis la timpul curent
secs++; // incrementeaza secundele
// daca secundele ajung la 60 incrementeaza minutele si reseteaza secundele
if(secs > 59) {
secs = 0;
mins++;
}
// daca minutele ajung la 60 incrementeaza orele si reseteaza minutele
if(mins > 59) {
mins = 0;
hours++;
}
// daca orele ajung la 24 reseteaza orele
if(hours > 23) {
hours = 0;
}
}
}
void displayScreen2() {
// afisare ecran 2
// afisare ora timer
lcd.setCursor(0,0);
lcd.print("Timer");
lcd.setCursor(8,0);
displayClock(hours, mins, secs);
// afisare ora alarma
lcd.setCursor(0,1);
lcd.print("Alarma");
lcd.setCursor(8,1);
displayClock(ahours, amins, asecs);
// daca alarma este setata, sa se afiseaza un caracter clopot
if (asecs > 0 || amins > 0 || ahours > 0) {
lcd.setCursor(6,1);
// printare caracter custom
lcd.write((byte)0);
}
}
// Functia generala pentru a controla butoanele de incrementare si decrementare
// se bazeaza pe debouncing impreuna cu millis pentru a incrementa sau a decrementa corect (cu cate 1)
// value e valoarea de ore, minute, secunde
void handleButtonPress(int buttonPin, unsigned long &lastPressTime, int &value, bool increment) {
if (digitalRead(buttonPin) == LOW && currentMillis - lastPressTime > debounceDelay) {
if (increment) {
value++;
} else {
if (value > 0) { // Previne ora/min/sec sa ajunga negativa
value--;
}
}
lastPressTime = currentMillis;
}
}
void logicTimer() {
// cresterea valorii la timer cu ajutorul butoanelor de incrementare
// incrementare ore
handleButtonPress(incHourPin, lastButtonPressMillis_8, hours, true);
// incrementare minute
handleButtonPress(incMinutePin, lastButtonPressMillis_9, mins, true);
// incrementare secunde
handleButtonPress(incSecondPin, lastButtonPressMillis_10, secs, true);
// scaderea valorii la timer cu ajutorul butoanelor de decrementare
// decrementare ore
handleButtonPress(decHourPin, lastButtonPressMillis_11, hours, false);
// decrementare minute
handleButtonPress(decMinutePin, lastButtonPressMillis_12, mins, false);
// decrementare secunde
handleButtonPress(decSecondPin, lastButtonPressMillis_13, secs, false);
}
void displayTimer() {
// afisare ecran de setare a timer-ului
lcd.setCursor(1,0);
lcd.print("Seteaza Timer");
lcd.setCursor(4,1);
displayClock(hours, mins, secs);
}
void logicAlarm() {
// cresterea valorii la alarma cu ajutorul butoanelor de incrementare
// incrementare ore
handleButtonPress(incHourPin, lastButtonPressMillis_8, ahours, true);
// incrementare minute
handleButtonPress(incMinutePin, lastButtonPressMillis_9, amins, true);
// incrementare secunde
handleButtonPress(incSecondPin, lastButtonPressMillis_10, asecs, true);
// scaderea valorii la timer cu ajutorul butoanelor de decrementare
// decrementare ore
handleButtonPress(decHourPin, lastButtonPressMillis_11, ahours, false);
// decrementare minute
handleButtonPress(decMinutePin, lastButtonPressMillis_12, amins, false);
// decrementare secunde
handleButtonPress(decSecondPin, lastButtonPressMillis_13, asecs, false);
}
void displayAlarm() {
// afisare ecran de setare a alarmei
lcd.setCursor(1,0);
lcd.print("Seteaza Alarma");
lcd.setCursor(4,1);
displayClock(ahours, amins, asecs);
}
void displayClock(int hours, int minutes, int seconds) {
// afisare ore:minute:secunde
displayCorrectTime(hours);
lcd.print(":");
displayCorrectTime(minutes);
lcd.print(":");
displayCorrectTime(seconds);
}
// Functia helper ajuta displayClock sa arate cifrele 0 la ceas (eg. 05)
void displayCorrectTime(int timeUnit) {
// daca valorile sunt sub 10, se afiseaza un 0 in fata cifrei
if (timeUnit < 10) {
lcd.print("0");
}
lcd.print(timeUnit);
}
void alarmTrigger() {
// verifica conditia alarmei si porneste buzzer-ul
if (!buzzerActive) {
buzzerActive = true;
buzzerStartTime = millis(); // porneste timpul millis pentru buzzer
}
// configurarea timpului de alarma la buzzer (30 secunde)
if (buzzerActive) {
tone(buzzerPin, 1000); // aprinde alarma cu 1000Hz sunet
// daca au trecut 30 de secunde de la inceperea alarmei, opreste buzzer-ul
if (millis() - buzzerStartTime >= 30000) {
resetAlarmState();
}
// daca se apasa pe butonul de confirmare, se opreste alarma manual de catre utilizator
if (digitalRead(confirmPin) == LOW) {
resetAlarmState();
}
}
}
void resetAlarmState() {
// opreste buzzer-ul (alarma)
noTone(buzzerPin);
// reseteaza conditia buzzer-ului
buzzerActive = false;
// reseteaza valorile alarmei
asecs = 0;
amins = 0;
ahours = 0;
// sterge caracterul de clopot la dezactivarea alarmei
lcd.setCursor(15,1);
lcd.print(" ");
}