#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <RTClib.h>
#include <SoftwareSerial.h>
#include <DFRobotDFPlayerMini.h>
// --- Time and Alarm Variables ---
int Hour = 0;
int Minute = 0;
int mode;
bool isAM = true;
int setHour = -1;
int setMinute = -1;
bool setIsAM = true;
bool alarmTriggered = false;
int nextAlarmTrack = 1;
bool button2PrevState = HIGH;
bool button3PrevState = HIGH;
bool button4PrevState = HIGH;
bool button5PrevState = HIGH;
bool button6PrevState = HIGH; // << NEW for second illuminated button
bool setupStarted = false;
unsigned long lastUpdate = 0;
LiquidCrystal_I2C lcd(0x27, 16, 2);
RTC_DS3231 rtc;
SoftwareSerial mySoftwareSerial(10, 11);
DFRobotDFPlayerMini myDFPlayer;
unsigned long lastBlink = 0; // << NEW: track blink timing
bool ledState = false; // << NEW: current ON/OFF for LED blink
void setup() {
pinMode(2, INPUT_PULLUP); // MODE
pinMode(3, INPUT_PULLUP); // INCREMENT
pinMode(4, INPUT_PULLUP); // CONFIRM
pinMode(5, INPUT_PULLUP); // LED Button 1 - push
pinMode(6, OUTPUT); // LED Button 1 - LED
pinMode(7, INPUT_PULLUP); // << NEW: LED Button 2 - push
pinMode(8, OUTPUT); // << NEW: LED Button 2 - LED
digitalWrite(6, LOW); // Ensure LEDs off at start
digitalWrite(8, LOW); // << NEW
Serial.begin(9600); // Add for debugging
Wire.begin();
lcd.init();
lcd.backlight();
lcd.clear();
if (!rtc.begin()) {
lcd.setCursor(0, 0);
lcd.print("RTC not found!");
while (1);
}
if (rtc.lostPower()) {
lcd.setCursor(0, 0);
lcd.print("RTC lost power!");
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
delay(2000);
lcd.clear();
}
mySoftwareSerial.begin(9600);
if (!myDFPlayer.begin(mySoftwareSerial)) {
myDFPlayer.volume(12);
}
}
void loop() {
bool button2State = digitalRead(2);
bool button3State = digitalRead(3);
bool button4State = digitalRead(4);
bool button5State = digitalRead(5); // Button 1 push
bool button6State = digitalRead(7); // << NEW: Button 2 push
// Check for alarm button presses first - this is critical for stopping the alarm
if (alarmTriggered) {
// Blink LEDs when alarm is triggered
if (millis() - lastBlink >= 500) { // Blink every 0.5 sec
lastBlink = millis();
ledState = !ledState;
digitalWrite(6, ledState ? HIGH : LOW); // LED 1
digitalWrite(8, ledState ? HIGH : LOW); // LED 2
}
// Check if either button is pressed (with debounce via state change)
if ((button5State == LOW && button5PrevState == HIGH) ||
(button6State == LOW && button6PrevState == HIGH)) {
// Stop sound
myDFPlayer.stop();
// Reset alarm state completely
alarmTriggered = false;
// Turn off both LEDs
digitalWrite(6, LOW);
digitalWrite(8, LOW);
// Reset the alarm so it doesn't trigger again
setHour = -1;
setMinute = -1;
// Debug info
Serial.println("Alarm stopped by button press");
Serial.println("Alarm cleared - will not trigger again until reset");
// Force LCD to update with current time
lcd.clear();
lastUpdate = 0;
}
}
// --- NORMAL MODE: Display & Check Time ---
if (!setupStarted) {
if (millis() - lastUpdate >= 1000) {
lastUpdate = millis();
DateTime now = rtc.now();
int displayHour = now.hour();
bool displayAM = true;
if (displayHour == 0) displayHour = 12;
else if (displayHour == 12) displayAM = false;
else if (displayHour > 12) {
displayHour -= 12;
displayAM = false;
}
lcd.setCursor(0, 0);
lcd.print("Time:");
lcd.setCursor(0, 1);
lcd.print(displayHour);
lcd.print(":");
if (now.minute() < 10) lcd.print('0');
lcd.print(now.minute());
lcd.print(displayAM ? " AM" : " PM");
lcd.print(" ");
// Only check for alarm if not already triggered and an alarm is set
if (!alarmTriggered && setHour != -1) {
if (displayHour == setHour && now.minute() == setMinute && displayAM == setIsAM) {
// Trigger the alarm with random track
int randomTrack = random(1, 2); // Picks 1, 2, 3, 4, or 5
myDFPlayer.play(randomTrack);
alarmTriggered = true;
// Debug info
Serial.println("Alarm triggered!");
Serial.print("Playing track: ");
Serial.println(randomTrack);
}
}
}
}
// --- ENTER SETUP MODE ---
if (!setupStarted && button2State == LOW && button2PrevState == HIGH) {
setupStarted = true;
mode = 2;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("HOUR");
lcd.setCursor(0, 1);
lcd.print(Hour);
}
else if (setupStarted && button2State == LOW && button2PrevState == HIGH) {
mode = (mode + 1) % 3;
lcd.clear();
if (mode == 2) {
lcd.print("HOUR");
lcd.setCursor(0, 1);
lcd.print(Hour);
} else if (mode == 0) {
lcd.print("MINUTE");
lcd.setCursor(0, 1);
lcd.print(Minute);
} else {
lcd.print("AM/PM");
lcd.setCursor(0, 1);
lcd.print(isAM ? "AM" : "PM");
}
}
// --- INCREASE VALUE ---
if (button3State == LOW && button3PrevState == HIGH && setupStarted) {
if (mode == 2) Hour = (Hour % 12) + 1;
else if (mode == 0) Minute = (Minute + 1) % 60;
else isAM = !isAM;
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.setCursor(0, 1);
if (mode == 2) lcd.print(Hour);
else if (mode == 0) lcd.print(Minute);
else lcd.print(isAM ? "AM" : "PM");
}
// --- CONFIRM VALUE ---
if (button4State == LOW && button4PrevState == HIGH && setupStarted) {
if (mode == 2) {
mode = 0;
lcd.clear();
lcd.print("MINUTE");
lcd.setCursor(0, 1);
lcd.print(Minute);
} else if (mode == 0) {
mode = 1;
lcd.clear();
lcd.print("AM/PM");
lcd.setCursor(0, 1);
lcd.print(isAM ? "AM" : "PM");
} else {
setHour = Hour;
setMinute = Minute;
setIsAM = isAM;
alarmTriggered = false;
lcd.clear();
lcd.print("Time Set:");
lcd.setCursor(0, 1);
lcd.print(Hour);
lcd.print(":");
if (Minute < 10) lcd.print('0');
lcd.print(Minute);
lcd.print(isAM ? " AM" : " PM");
// Debug info
Serial.print("Alarm set for: ");
Serial.print(Hour);
Serial.print(":");
if (Minute < 10) Serial.print('0');
Serial.print(Minute);
Serial.println(isAM ? " AM" : " PM");
delay(3000);
Hour = 0;
Minute = 0;
isAM = true;
setupStarted = false;
lcd.clear();
}
}
// Save states
button2PrevState = button2State;
button3PrevState = button3State;
button4PrevState = button4State;
button5PrevState = button5State;
button6PrevState = button6State; // << NEW
delay(50);
}