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:

#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 Mr Green
Why not use an sram and a watch battery?
This was a very rough prototype, I'm going to start working on a more revised and accessable version using an ESP32 devkit and SSD1306 display, since I ordered some from Amazon, and they are arriving Monday 🙂
As for the watch battery, I was trying to combine some LR44 batteries, but I didn't have good enough tape for them to power
.
For other stuff, you could add a real-time-clock module for more arduino uno support, but the ESP32 has a built in RTC, so I wouldn't need to worry as much about that.
Quote:
a breadboard (It would be interesting if someone made a soldered version, though)

Have you drawn out the schematic for it? We have a lot of users here who use tools like KiCAD or Eagle to design circuit boards and who I'm sure would be happy to help you learn. I personally use OSH Park or JLCPCB to get circuit boards manufactured for cheap: if you're not handy with a soldering iron, JLC will even assemble the boards for an additional fee.
I've never tried designing a PCB or anything, but I've put a bit of interest into it recently, and I feel like I've heard of KiCAD before, maybe, once I've finished the ESP32 version, I'll try designing a PCB for it 🙂
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 1
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement