#include <Wire.h>
#include <RTClib.h>
#include <LiquidCrystal_I2C.h>
#include <EEPROM.h>
RTC_DS3231 rtc;
LiquidCrystal_I2C lcd(0x27, 16, 2);
// Buttons
#define BTN_ALARM_SET 2
#define BTN_UP 3
#define BTN_DOWN 4
#define BTN_ALARM_EN 5
#define BTN_TIME_SET 6
#define BUZZER 8
int alarmHour, alarmMin;
bool alarmEnable;
bool alarmRinging = false;
unsigned long alarmStart;
byte bell[8] = {
B00100,B01110,B01110,B01110,B11111,B00100,B00000,B00000
};
const char* days[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
void setup() {
pinMode(BUZZER, OUTPUT);
pinMode(BTN_ALARM_SET, INPUT_PULLUP);
pinMode(BTN_UP, INPUT_PULLUP);
pinMode(BTN_DOWN, INPUT_PULLUP);
pinMode(BTN_ALARM_EN, INPUT_PULLUP);
pinMode(BTN_TIME_SET, INPUT_PULLUP);
lcd.init();
lcd.backlight();
lcd.createChar(0, bell);
rtc.begin();
EEPROM.get(0, alarmHour);
EEPROM.get(2, alarmMin);
EEPROM.get(4, alarmEnable);
if (alarmHour > 23) alarmHour = 6;
if (alarmMin > 59) alarmMin = 0;
}
void loop() {
DateTime now = rtc.now();
int h = now.hour();
bool pm = h >= 12;
int h12 = h % 12;
if (h12 == 0) h12 = 12;
// ---- Line 1 ----
lcd.setCursor(0,0);
if (h12 < 10) lcd.print("0");
lcd.print(h12);
lcd.print(":");
if (now.minute() < 10) lcd.print("0");
lcd.print(now.minute());
lcd.print(":");
if (now.second() < 10) lcd.print("0");
lcd.print(now.second());
lcd.print(pm ? " PM" : " AM");
if (alarmEnable) {
lcd.setCursor(15,0);
lcd.write(byte(0));
}
// ---- Line 2 ----
lcd.setCursor(0,1);
lcd.print(days[now.dayOfTheWeek()]);
lcd.print(" ");
lcd.print(now.day());
lcd.print("/");
lcd.print(now.month());
lcd.print("/");
lcd.print(now.year());
// ---- Alarm Logic (10 sec) ----
if (alarmEnable &&
now.hour() == alarmHour &&
now.minute() == alarmMin &&
now.second() == 0 &&
!alarmRinging) {
alarmRinging = true;
alarmStart = millis();
digitalWrite(BUZZER, HIGH);
}
if (alarmRinging && millis() - alarmStart >= 10000) {
digitalWrite(BUZZER, LOW);
alarmRinging = false;
}
// ---- Buttons ----
if (digitalRead(BTN_TIME_SET) == LOW) {
delay(300);
setTimeDate();
}
if (digitalRead(BTN_ALARM_SET) == LOW) {
delay(300);
setAlarm();
}
if (digitalRead(BTN_ALARM_EN) == LOW) {
alarmEnable = !alarmEnable;
EEPROM.put(4, alarmEnable);
delay(300);
}
delay(200);
}
// ================= SET TIME & DATE =================
void setTimeDate() {
DateTime now = rtc.now();
int h = now.hour(), m = now.minute(), s = now.second();
int d = now.day(), mo = now.month(), y = now.year();
int dow = now.dayOfTheWeek();
setValue("Set Hour", h, 0, 23);
setValue("Set Minute", m, 0, 59);
setValue("Set Second", s, 0, 59);
setValue("Set Day", dow, 0, 6);
setValue("Set Date", d, 1, 31);
setValue("Set Month", mo, 1, 12);
setValue("Set Year", y, 2024, 2099);
rtc.adjust(DateTime(y, mo, d, h, m, s));
}
void setValue(const char* title, int &val, int minV, int maxV) {
lcd.clear();
lcd.print(title);
while (digitalRead(BTN_TIME_SET) == HIGH) {
if (digitalRead(BTN_UP) == LOW) {
val++;
if (val > maxV) val = minV;
delay(200);
}
if (digitalRead(BTN_DOWN) == LOW) {
val--;
if (val < minV) val = maxV;
delay(200);
}
lcd.setCursor(0,1);
lcd.print(" ");
lcd.setCursor(0,1);
lcd.print(val);
}
delay(300);
}
// ================= SET ALARM =================
void setAlarm() {
setValue("Alarm Hour", alarmHour, 0, 23);
setValue("Alarm Min", alarmMin, 0, 59);
EEPROM.put(0, alarmHour);
EEPROM.put(2, alarmMin);
}