wseltzer
Published © MIT

30-Minute Timer Alarm Clock

Simple Arduino-based 30-minute alarm clock with gentle "gong" sound.

IntermediateFull instructions provided4,107
30-Minute Timer Alarm Clock

Things used in this project

Hardware components

Pro Micro - 5V/16MHz
SparkFun Pro Micro - 5V/16MHz
×1
DFRobot DFPlayer Mini MP3 player
×1
Flash Memory Card, MicroSD Card
Flash Memory Card, MicroSD Card
×1
High Accuracy Pi RTC (DS3231)
Seeed Studio High Accuracy Pi RTC (DS3231)
×1
I2C 16x2 Arduino LCD Display Module
DFRobot I2C 16x2 Arduino LCD Display Module
×1
Speaker: 3W, 4 ohms
Speaker: 3W, 4 ohms
×1
Pushbutton Switch, SPST-NO
Pushbutton Switch, SPST-NO
×1
5V 2.5A Switching Power Supply
Digilent 5V 2.5A Switching Power Supply
×1
Barrel Jack
×1
Stripboard
×1
Arduino Micro
Arduino Micro
×1

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)

Story

Read more

Custom parts and enclosures

shoni_clock_case.stl

shoni_clock_case_bottom_cover.stl

speaker_mount.stl

speaker_mount.stl

Schematics

shoni_clock

Code

shoni_clock.ino

Arduino
// Shoni's clock - alarms every 30 minutes

// Date and time functions using a DS1307 RTC connected via I2C and Wire lib
#include "RTClib.h"

// I2C LCD
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

// DFPlayer sound card
// https://wiki.dfrobot.com/DFPlayer_Mini_SKU_DFR0299#Connection_Diagram
#include "Arduino.h"
#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h"
SoftwareSerial mySoftwareSerial(8, 9); // RX, TX
DFRobotDFPlayerMini myDFPlayer;

#define ALARM_SECONDS 10        // seconds
#define ALARM_REPEAT_DELAY 2000 // milliseconds
#define ALARM_VOLUME 15         // 0 to 30
#define SESSION_TIME 30         // minutes; but this implementation only works for 30 minute sessions

// time adjust plus/minus buttons. LOW when pressed Connected to interrupt inputs, software debounced.
#define TPLUS_PIN 0
#define TMINUS_PIN 1
volatile int TPLUS_button = false;
volatile int TMINUS_button = false;

RTC_DS1307 rtc;
LiquidCrystal_I2C lcd(0x27, 20, 4); // set the LCD address to 0x27 for a 16 chars and 2 line display

char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

void playalarm() {
  myDFPlayer.volume(ALARM_VOLUME);  //Set volume value. From 0 to 30
  myDFPlayer.play(1);  //Play the first mp3
}

void setup () {
  Serial.begin(57600);
  //while (!Serial); // for Leonardo/Micro/Zero
  Serial.println("Shoni's Clock");

  pinMode(TPLUS_PIN, INPUT_PULLUP);
  pinMode(TMINUS_PIN, INPUT_PULLUP);

  lcd.init();
  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print("  Shoni's Clock");
  delay(1000);

  mySoftwareSerial.begin(9600);

  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("RTC error!");
    delay(3000);
  }

  if (! rtc.isrunning()) {
    Serial.println("RTC is NOT running!");
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Clock time error!");
    delay(3000);
  }

  // following line sets the RTC to the date & time this sketch was compiled
  rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  // This line sets the RTC with an explicit date & time, for example to set
  //rtc.adjust(DateTime(2019, 10, 12, 11, 59, 50));

  if (!myDFPlayer.begin(mySoftwareSerial)) {  //Use softwareSerial to communicate with mp3.
    Serial.println(F("Unable to begin:"));
    Serial.println(F("1.Please recheck the connection!"));
    Serial.println(F("2.Please insert the SD card!"));
    while (true) {
      delay(0); // Code to compatible with ESP8266 watch dog.
    }
  }
  myDFPlayer.volume(ALARM_VOLUME);  //Set volume value. From 0 to 30
  playalarm();

  attachInterrupt(digitalPinToInterrupt(TPLUS_PIN), TPLUS_button_interrupt, LOW);
  attachInterrupt(digitalPinToInterrupt(TMINUS_PIN), TMINUS_button_interrupt, LOW);
}


void TPLUS_button_interrupt() {
  TPLUS_button = true;
}

void TMINUS_button_interrupt() {
  TMINUS_button = true;
}

void check_buttons() {
  int dir;
  if (TPLUS_button | TMINUS_button) {
    if (TPLUS_button) {
      dir = 1;
      //Serial.println("Adjust time -1 minute");
      delay(50);
      TPLUS_button = false;
    }
    if (TMINUS_button) {
      dir = -1;
      //Serial.println("Adjust time -1 minute");
      delay(50);
      TMINUS_button = false;
    }
    DateTime newtime = rtc.now() + (60 * dir);
    rtc.adjust(newtime);
  }
}

char d[16];
int prevmin = 99;
int alarmplaying;

void loop () {
  int minleft;
  int updateDisplay = true;
  check_buttons();

  DateTime now = rtc.now();
  // update display only if the minute has changed
  if (prevmin == now.minute()) {
    updateDisplay = false;
  }
  else {
    updateDisplay = true;
    prevmin = now.minute();
  }

  if (now.minute() == 0) {
    minleft = 0;
  }
  else if (now.minute() > 30) {
    minleft = 60 - now.minute();
  }
  else {
    minleft = 30 - now.minute();
  }

  // Display current time
  if (updateDisplay) {
    sprintf(d, "%2d:%02d", TwentyFourToTwelve(now.hour()), now.minute());
    Serial.println(d);
    lcd.clear();
    lcd.setCursor(5, 0);
    lcd.print(d);
  }

  // Display time left in session
  if (minleft == 0) {
    if ((now.second() < ALARM_SECONDS)) {
      if (!alarmplaying) {
        playalarm();
        alarmplaying = true;
      }
      lcd.setCursor(0, 1);
      lcd.print("--Session over--");
      Serial.println("--Session over--");
      delay(ALARM_REPEAT_DELAY);
    }
    else {
      minleft = SESSION_TIME;
      alarmplaying = false;
    }
  }
  lcd.setCursor(0, 1);
  sprintf(d, "minutes left: %2d", minleft);
  lcd.print(d);
  //Serial.println(d);
  delay(500);
}

int TwentyFourToTwelve(int hour) {
  int h = hour % 12;
  if (h == 0) {
    h = 12;
  }
  return h;
}

Github

https://github.com/johnrickman/LiquidCrystal_I2C

Credits

wseltzer

wseltzer

1 project • 2 followers

Comments