/*
* Arduino Digital Clock with Alarm using 7-Segment Display
* Features: Time display, Time setting, Alarm setting, Buzzer alert
*/
#include <Wire.h>
#include <RTClib.h>
RTC_DS3231 rtc;
// Pin definitions for 7-segment display
const int segmentPins[8] = {2, 3, 4, 5, 6, 7, 8, 9}; // A, B, C, D, E, F, G, DP
const int digitPins[4] = {10, 11, 12, 13}; // Digit 1, 2, 3, 4
// Other pins
const int buzzerPin = A0;
const int btnSet = A1;
const int btnUp = A2;
const int btnDown = A3;
// 7-segment patterns for digits 0-9 (Common Cathode)
const byte digitPattern[10] = {
0b11111100, // 0
0b01100000, // 1
0b11011010, // 2
0b11110010, // 3
0b01100110, // 4
0b10110110, // 5
0b10111110, // 6
0b11100000, // 7
0b11111110, // 8
0b11110110 // 9
};
// Variables
int hours = 0, minutes = 0, seconds = 0;
int alarmHour = 7, alarmMinute = 0;
bool alarmEnabled = true;
bool alarmTriggered = false;
enum Mode { MODE_DISPLAY, MODE_SET_HOUR, MODE_SET_MINUTE, MODE_SET_ALARM_HOUR, MODE_SET_ALARM_MINUTE };
Mode currentMode = MODE_DISPLAY;
unsigned long lastDebounceTime = 0;
const unsigned long debounceDelay = 200;
unsigned long lastBlinkTime = 0;
bool blinkState = false;
void setup() {
Serial.begin(9600);
// Initialize 7-segment pins
for (int i = 0; i < 8; i++) {
pinMode(segmentPins[i], OUTPUT);
}
for (int i = 0; i < 4; i++) {
pinMode(digitPins[i], OUTPUT);
digitalWrite(digitPins[i], HIGH); // Turn off all digits initially
}
// Initialize other pins
pinMode(buzzerPin, OUTPUT);
pinMode(btnSet, INPUT);
pinMode(btnUp, INPUT);
pinMode(btnDown, INPUT);
// Initialize RTC
if (!rtc.begin()) {
Serial.println("RTC not found!");
while (1);
}
// Set initial time if RTC lost power (uncomment and modify as needed)
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
if (rtc.lostPower()) {
Serial.println("RTC lost power, setting default time!");
rtc.adjust(DateTime(2024, 1, 1, 12, 0, 0));
}
}
void loop() {
handleButtons();
updateTime();
checkAlarm();
displayTime();
delay(2); // Small delay for multiplexing
}
void handleButtons() {
if (millis() - lastDebounceTime < debounceDelay) return;
// SET button
if (digitalRead(btnSet) == HIGH) {
lastDebounceTime = millis();
currentMode = (Mode)((currentMode + 1) % 5);
if (currentMode == MODE_DISPLAY) {
saveTime(); // Save time when exiting setting mode
}
Serial.print("Mode: ");
Serial.println(currentMode);
delay(200);
}
// UP button
if (digitalRead(btnUp) == HIGH) {
lastDebounceTime = millis();
adjustValue(1);
if (alarmTriggered) {
alarmTriggered = false;
digitalWrite(buzzerPin, LOW);
}
}
// DOWN button
if (digitalRead(btnDown) == HIGH) {
lastDebounceTime = millis();
adjustValue(-1);
if (alarmTriggered) {
alarmTriggered = false;
digitalWrite(buzzerPin, LOW);
}
}
}
void adjustValue(int direction) {
switch (currentMode) {
case MODE_SET_HOUR:
hours += direction;
if (hours > 23) hours = 0;
if (hours < 0) hours = 23;
break;
case MODE_SET_MINUTE:
minutes += direction;
if (minutes > 59) minutes = 0;
if (minutes < 0) minutes = 59;
break;
case MODE_SET_ALARM_HOUR:
alarmHour += direction;
if (alarmHour > 23) alarmHour = 0;
if (alarmHour < 0) alarmHour = 23;
break;
case MODE_SET_ALARM_MINUTE:
alarmMinute += direction;
if (alarmMinute > 59) alarmMinute = 0;
if (alarmMinute < 0) alarmMinute = 59;
break;
}
}
void updateTime() {
if (currentMode == MODE_DISPLAY) {
DateTime now = rtc.now();
hours = now.hour();
minutes = now.minute();
seconds = now.second();
}
}
void saveTime() {
rtc.adjust(DateTime(2024, 1, 1, hours, minutes, 0));
Serial.println("Time saved!");
}
void checkAlarm() {
if (!alarmEnabled || currentMode != MODE_DISPLAY) return;
if (hours == alarmHour && minutes == alarmMinute && !alarmTriggered) {
alarmTriggered = true;
}
if (alarmTriggered) {
// Sound alarm pattern
if (millis() % 500 < 250) {
tone(buzzerPin, 1000);
} else {
noTone(buzzerPin);
}
} else {
noTone(buzzerPin);
}
}
void displayTime() {
int displayHour, displayMinute;
// Determine what to display based on mode
switch (currentMode) {
case MODE_DISPLAY:
displayHour = hours;
displayMinute = minutes;
break;
case MODE_SET_HOUR:
case MODE_SET_MINUTE:
displayHour = hours;
displayMinute = minutes;
break;
case MODE_SET_ALARM_HOUR:
case MODE_SET_ALARM_MINUTE:
displayHour = alarmHour;
displayMinute = alarmMinute;
break;
}
// Blinking effect for setting mode
if (currentMode != MODE_DISPLAY && millis() - lastBlinkTime > 500) {
lastBlinkTime = millis();
blinkState = !blinkState;
}
// Display each digit with multiplexing
int digits[4] = {
displayHour / 10,
displayHour % 10,
displayMinute / 10,
displayMinute % 10
};
for (int i = 0; i < 4; i++) {
// Skip blinking digit in setting mode
if (currentMode == MODE_SET_HOUR && i < 2 && !blinkState) {
clearDisplay();
continue;
}
if (currentMode == MODE_SET_MINUTE && i >= 2 && !blinkState) {
clearDisplay();
continue;
}
if (currentMode == MODE_SET_ALARM_HOUR && i < 2 && !blinkState) {
clearDisplay();
continue;
}
if (currentMode == MODE_SET_ALARM_MINUTE && i >= 2 && !blinkState) {
clearDisplay();
continue;
}
displayDigit(i, digits[i]);
delay(2); // Multiplexing delay
}
}
void displayDigit(int digit, int number) {
// Turn off all digits
for (int i = 0; i < 4; i++) {
digitalWrite(digitPins[i], HIGH);
}
// Set segments for the number
byte pattern = digitPattern[number];
// Add colon (DP on digit 2)
if (digit == 1 && currentMode == MODE_DISPLAY && millis() % 1000 < 500) {
pattern |= 0b00000001; // Turn on decimal point
}
for (int i = 0; i < 8; i++) {
digitalWrite(segmentPins[i], (pattern >> (7 - i)) & 0x01);
}
// Turn on current digit
digitalWrite(digitPins[digit], LOW);
}
void clearDisplay() {
for (int i = 0; i < 4; i++) {
digitalWrite(digitPins[i], HIGH);
}
}