In my free time, I have been working on a project called AlarmDuino!
All it requires is a arduino uno (or whatever microcontroller you have, given you are willing to port the code), a breadboard (It would be interesting if someone made a soldered version, though), an LCD1602, and some other small parts and wires!
Features of AlarmDuino:
▪ 24 hour time (will add 12 hour support some time)
▪ Extensively customizable alarm (frequency, beeps, beep hold, beep delay, or no alarm at all)
▪ Beeping stops when your light gets turned on (customizable light threshold)
▪ Automatically stores value of time in EEPROM once every minute (to extend the EEPROMs life, it's not every second)
▪ Hours, minutes, and seconds
▪ Absolutely free (as all things like this should be)
I have been using this as a personal alarm clock, and it has worked pretty well!
Here are some pictures of how it's looking right now:
The home screen:
Setting up the beep count:
The whole project:
The chaotic wiring:
And here is the source code 🙂
Code:
Any suggestions will be greatly appreciated
All it requires is a arduino uno (or whatever microcontroller you have, given you are willing to port the code), a breadboard (It would be interesting if someone made a soldered version, though), an LCD1602, and some other small parts and wires!
Features of AlarmDuino:
▪ 24 hour time (will add 12 hour support some time)
▪ Extensively customizable alarm (frequency, beeps, beep hold, beep delay, or no alarm at all)
▪ Beeping stops when your light gets turned on (customizable light threshold)
▪ Automatically stores value of time in EEPROM once every minute (to extend the EEPROMs life, it's not every second)
▪ Hours, minutes, and seconds
▪ Absolutely free (as all things like this should be)
I have been using this as a personal alarm clock, and it has worked pretty well!
Here are some pictures of how it's looking right now:
The home screen:
Setting up the beep count:
The whole project:
The chaotic wiring:
And here is the source code 🙂
Code:
#include <LiquidCrystal.h>
#include <EEPROM.h>
// --- Pin Definitions ---
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
const int buzzerPin = 8;
const int modePin = 9;
const int hourPin = 7;
const int minPin = 6;
const int configPin = 13;
const int alarmSwitchPin = 10;
const int ldrPin = A0;
// --- EEPROM Addresses ---
const int addrThresh = 0, addrFreq = 2, addrHour = 4, addrMin = 5, addrBeeps = 6, addrDelay = 7, addrHold = 9;
// --- Settings ---
int lightThreshold, beepFreq, beepCount, beepDelay, beepHold;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
// --- State Variables ---
enum MainMode { CLOCK_DISPLAY, CALIBRATE, SET_FREQ, SET_BEEPS, SET_HOLD, SET_DELAY };
MainMode currentMainMode = CLOCK_DISPLAY;
enum EditMode { NONE, SET_TIME, SET_ALARM };
EditMode currentEditMode = NONE;
int currentHour, currentMinute, currentSecond = 0;
int alarmHour = 6, alarmMinute = 0;
unsigned long previousMillis = 0;
const long interval = 1000;
bool alarmActive = false;
bool manualTest = false;
void setup() {
pinMode(buzzerPin, OUTPUT);
pinMode(modePin, INPUT_PULLUP);
pinMode(hourPin, INPUT_PULLUP);
pinMode(minPin, INPUT_PULLUP);
pinMode(configPin, INPUT_PULLUP);
pinMode(alarmSwitchPin, INPUT_PULLUP);
EEPROM.get(addrThresh, lightThreshold);
EEPROM.get(addrFreq, beepFreq);
currentHour = EEPROM.read(addrHour);
currentMinute = EEPROM.read(addrMin);
beepCount = EEPROM.read(addrBeeps);
EEPROM.get(addrDelay, beepDelay);
EEPROM.get(addrHold, beepHold);
if (lightThreshold < 0) lightThreshold = 400;
if (beepFreq < 100) beepFreq = 1000;
if (beepCount < 1) beepCount = 3;
if (beepDelay < 50) beepDelay = 200;
if (beepHold < 50) beepHold = 200;
lcd.begin(16, 2);
lcd.print("System Ready");
delay(1000);
lcd.clear();
}
void loop() {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis += interval;
tickClock();
}
checkAlarmLogic();
handleButtons();
updateDisplay();
}
void checkAlarmLogic() {
bool switchArmed = (digitalRead(alarmSwitchPin) == LOW);
if (switchArmed && currentHour == alarmHour && currentMinute == alarmMinute && currentSecond == 0) {
alarmActive = true;
}
if (!switchArmed) {
alarmActive = false;
}
bool shouldBeep = alarmActive || manualTest;
if (shouldBeep) {
if (alarmActive && analogRead(ldrPin) > lightThreshold) {
alarmActive = false;
noTone(buzzerPin);
} else {
unsigned long totalCycle = (unsigned long)(beepHold + beepDelay) * beepCount + 800;
unsigned long patternPos = millis() % totalCycle;
unsigned long singleBeepCycle = (unsigned long)(beepHold + beepDelay);
if (patternPos < (singleBeepCycle * beepCount)) {
if ((patternPos % singleBeepCycle) < beepHold) tone(buzzerPin, beepFreq);
else noTone(buzzerPin);
} else {
noTone(buzzerPin);
}
}
} else {
noTone(buzzerPin);
}
}
void handleButtons() {
static bool lastModeState = HIGH, lastHourState = HIGH, lastMinState = HIGH, lastConfigState = HIGH;
bool modeBtn = digitalRead(modePin), hourBtn = digitalRead(hourPin), minBtn = digitalRead(minPin), configBtn = digitalRead(configPin);
if (configBtn == LOW && lastConfigState == HIGH) {
if (currentMainMode == CALIBRATE) EEPROM.put(addrThresh, lightThreshold);
if (currentMainMode == SET_FREQ) EEPROM.put(addrFreq, beepFreq);
if (currentMainMode == SET_BEEPS) EEPROM.update(addrBeeps, beepCount);
if (currentMainMode == SET_HOLD) EEPROM.put(addrHold, beepHold);
if (currentMainMode == SET_DELAY) EEPROM.put(addrDelay, beepDelay);
manualTest = false;
if (currentMainMode == CLOCK_DISPLAY) currentMainMode = CALIBRATE;
else if (currentMainMode == CALIBRATE) currentMainMode = SET_FREQ;
else if (currentMainMode == SET_FREQ) currentMainMode = SET_BEEPS;
else if (currentMainMode == SET_BEEPS) currentMainMode = SET_HOLD;
else if (currentMainMode == SET_HOLD) currentMainMode = SET_DELAY;
else currentMainMode = CLOCK_DISPLAY;
currentEditMode = NONE; lcd.clear(); delay(200);
}
if (modeBtn == LOW && lastModeState == HIGH) {
if (currentMainMode == CLOCK_DISPLAY) {
if (currentEditMode == NONE) currentEditMode = SET_TIME;
else if (currentEditMode == SET_TIME) { currentEditMode = SET_ALARM; EEPROM.update(addrHour, currentHour); EEPROM.update(addrMin, currentMinute); }
else currentEditMode = NONE;
} else if (currentMainMode != CALIBRATE) {
manualTest = !manualTest;
}
delay(200);
}
if (hourBtn == LOW && lastHourState == HIGH) {
if (currentEditMode == SET_TIME) currentHour = (currentHour + 1) % 24;
else if (currentEditMode == SET_ALARM) alarmHour = (alarmHour + 1) % 24;
else if (currentMainMode == CALIBRATE) lightThreshold = min(1023, lightThreshold + 25);
else if (currentMainMode == SET_FREQ) beepFreq += 100;
else if (currentMainMode == SET_BEEPS) beepCount = min(20, beepCount + 1);
else if (currentMainMode == SET_HOLD) beepHold = min(2000, beepHold + 50);
else if (currentMainMode == SET_DELAY) beepDelay = min(2000, beepDelay + 50);
delay(150);
}
if (minBtn == LOW && lastMinState == HIGH) {
if (currentEditMode == SET_TIME) { currentMinute = (currentMinute + 1) % 60; currentSecond = 0; }
else if (currentEditMode == SET_ALARM) alarmMinute = (alarmMinute + 1) % 60;
else if (currentMainMode == CALIBRATE) lightThreshold = max(0, lightThreshold - 25);
else if (currentMainMode == SET_FREQ) beepFreq = max(100, beepFreq - 100);
else if (currentMainMode == SET_BEEPS) beepCount = max(1, beepCount - 1);
else if (currentMainMode == SET_HOLD) beepHold = max(50, beepHold - 50);
else if (currentMainMode == SET_DELAY) beepDelay = max(50, beepDelay - 50);
delay(150);
}
lastModeState = modeBtn; lastHourState = hourBtn; lastMinState = minBtn; lastConfigState = configBtn;
}
void updateDisplay() {
unsigned long currentMillis = millis();
bool blink = (currentMillis / 250) % 2 == 0;
bool switchArmed = (digitalRead(alarmSwitchPin) == LOW);
switch (currentMainMode) {
case CLOCK_DISPLAY:
lcd.setCursor(0,0);
lcd.print("TIME: ");
if (currentEditMode == SET_TIME && !blink) lcd.print(" ");
else { printDigits(currentHour); lcd.print(":"); printDigits(currentMinute); lcd.print(":"); printDigits(currentSecond); }
lcd.setCursor(0,1);
// If switch is OFF, just clear the second line.
// EXCEPT: Always show the alarm if we are currently editing it!
if (!switchArmed && currentEditMode != SET_ALARM) {
lcd.print(" "); // Blank space
} else {
lcd.print("ALARM: ");
if (currentEditMode == SET_ALARM && !blink) lcd.print(" ");
else { printDigits(alarmHour); lcd.print(":"); printDigits(alarmMinute); }
lcd.print(" ");
}
break;
case CALIBRATE:
lcd.setCursor(0,0); lcd.print("SENSOR: "); lcd.print(analogRead(ldrPin)); lcd.print(" ");
lcd.setCursor(0,1); lcd.print("THRESH: "); lcd.print(lightThreshold); lcd.print(" ");
break;
default:
String label = (currentMainMode == SET_FREQ) ? "FREQ" : (currentMainMode == SET_BEEPS) ? "COUNT" : (currentMainMode == SET_HOLD) ? "HOLD" : "DELAY";
lcd.setCursor(0,0); lcd.print("SET "); lcd.print(label); if(manualTest) lcd.print(" [TEST]");
lcd.setCursor(0,1);
if (currentMainMode == SET_FREQ) { lcd.print(beepFreq); lcd.print(" Hz"); }
else if (currentMainMode == SET_BEEPS) { lcd.print(beepCount); lcd.print(" Beeps"); }
else if (currentMainMode == SET_HOLD) { lcd.print(beepHold); lcd.print(" ms"); }
else if (currentMainMode == SET_DELAY) { lcd.print(beepDelay); lcd.print(" ms"); }
lcd.print(" ");
break;
}
}
void tickClock() {
if (++currentSecond >= 60) {
currentSecond = 0;
if (++currentMinute >= 60) { currentMinute = 0; currentHour = (currentHour + 1) % 24; }
EEPROM.update(addrHour, currentHour); EEPROM.update(addrMin, currentMinute);
}
}
void printDigits(int digits) { if (digits < 10) lcd.print("0"); lcd.print(digits); }
Any suggestions will be greatly appreciated




