Devices & Components
Arduino Micro
16x2 LCD display with I²C interface
5V 2.5A Switching Power Supply
High Accuracy Pi RTC (DS3231)
Pro Micro - 5V/16MHz
Pushbutton Switch, SPST-NO
Speaker: 3W, 4 ohms
DFPlayer Mini MP3 player
Stripboard
Flash Memory Card, MicroSD Card
Barrel Jack
Hardware & Tools
3D Printer (generic)
Code
shoni_clock.ino
arduino
1// Shoni's clock - alarms every 30 minutes 2 3// Date and time functions using a DS1307 RTC connected via I2C and Wire lib 4#include "RTClib.h" 5 6// I2C LCD 7#include <Wire.h> 8#include <LiquidCrystal_I2C.h> 9 10// DFPlayer sound card 11// https://wiki.dfrobot.com/DFPlayer_Mini_SKU_DFR0299#Connection_Diagram 12#include "Arduino.h" 13#include "SoftwareSerial.h" 14#include "DFRobotDFPlayerMini.h" 15SoftwareSerial mySoftwareSerial(8, 9); // RX, TX 16DFRobotDFPlayerMini myDFPlayer; 17 18#define ALARM_SECONDS 10 // seconds 19#define ALARM_REPEAT_DELAY 2000 // milliseconds 20#define ALARM_VOLUME 15 // 0 to 30 21#define SESSION_TIME 30 // minutes; but this implementation only works for 30 minute sessions 22 23// time adjust plus/minus buttons. LOW when pressed Connected to interrupt inputs, software debounced. 24#define TPLUS_PIN 0 25#define TMINUS_PIN 1 26volatile int TPLUS_button = false; 27volatile int TMINUS_button = false; 28 29RTC_DS1307 rtc; 30LiquidCrystal_I2C lcd(0x27, 20, 4); // set the LCD address to 0x27 for a 16 chars and 2 line display 31 32char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; 33 34void playalarm() { 35 myDFPlayer.volume(ALARM_VOLUME); //Set volume value. From 0 to 30 36 myDFPlayer.play(1); //Play the first mp3 37} 38 39void setup () { 40 Serial.begin(57600); 41 //while (!Serial); // for Leonardo/Micro/Zero 42 Serial.println("Shoni's Clock"); 43 44 pinMode(TPLUS_PIN, INPUT_PULLUP); 45 pinMode(TMINUS_PIN, INPUT_PULLUP); 46 47 lcd.init(); 48 lcd.backlight(); 49 lcd.setCursor(0, 0); 50 lcd.print(" Shoni's Clock"); 51 delay(1000); 52 53 mySoftwareSerial.begin(9600); 54 55 if (! rtc.begin()) { 56 Serial.println("Couldn't find RTC"); 57 lcd.clear(); 58 lcd.setCursor(0, 0); 59 lcd.print("RTC error!"); 60 delay(3000); 61 } 62 63 if (! rtc.isrunning()) { 64 Serial.println("RTC is NOT running!"); 65 lcd.clear(); 66 lcd.setCursor(0, 0); 67 lcd.print("Clock time error!"); 68 delay(3000); 69 } 70 71 // following line sets the RTC to the date & time this sketch was compiled 72 rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); 73 // This line sets the RTC with an explicit date & time, for example to set 74 //rtc.adjust(DateTime(2019, 10, 12, 11, 59, 50)); 75 76 if (!myDFPlayer.begin(mySoftwareSerial)) { //Use softwareSerial to communicate with mp3. 77 Serial.println(F("Unable to begin:")); 78 Serial.println(F("1.Please recheck the connection!")); 79 Serial.println(F("2.Please insert the SD card!")); 80 while (true) { 81 delay(0); // Code to compatible with ESP8266 watch dog. 82 } 83 } 84 myDFPlayer.volume(ALARM_VOLUME); //Set volume value. From 0 to 30 85 playalarm(); 86 87 attachInterrupt(digitalPinToInterrupt(TPLUS_PIN), TPLUS_button_interrupt, LOW); 88 attachInterrupt(digitalPinToInterrupt(TMINUS_PIN), TMINUS_button_interrupt, LOW); 89} 90 91 92void TPLUS_button_interrupt() { 93 TPLUS_button = true; 94} 95 96void TMINUS_button_interrupt() { 97 TMINUS_button = true; 98} 99 100void check_buttons() { 101 int dir; 102 if (TPLUS_button | TMINUS_button) { 103 if (TPLUS_button) { 104 dir = 1; 105 //Serial.println("Adjust time -1 minute"); 106 delay(50); 107 TPLUS_button = false; 108 } 109 if (TMINUS_button) { 110 dir = -1; 111 //Serial.println("Adjust time -1 minute"); 112 delay(50); 113 TMINUS_button = false; 114 } 115 DateTime newtime = rtc.now() + (60 * dir); 116 rtc.adjust(newtime); 117 } 118} 119 120char d[16]; 121int prevmin = 99; 122int alarmplaying; 123 124void loop () { 125 int minleft; 126 int updateDisplay = true; 127 check_buttons(); 128 129 DateTime now = rtc.now(); 130 // update display only if the minute has changed 131 if (prevmin == now.minute()) { 132 updateDisplay = false; 133 } 134 else { 135 updateDisplay = true; 136 prevmin = now.minute(); 137 } 138 139 if (now.minute() == 0) { 140 minleft = 0; 141 } 142 else if (now.minute() > 30) { 143 minleft = 60 - now.minute(); 144 } 145 else { 146 minleft = 30 - now.minute(); 147 } 148 149 // Display current time 150 if (updateDisplay) { 151 sprintf(d, "%2d:%02d", TwentyFourToTwelve(now.hour()), now.minute()); 152 Serial.println(d); 153 lcd.clear(); 154 lcd.setCursor(5, 0); 155 lcd.print(d); 156 } 157 158 // Display time left in session 159 if (minleft == 0) { 160 if ((now.second() < ALARM_SECONDS)) { 161 if (!alarmplaying) { 162 playalarm(); 163 alarmplaying = true; 164 } 165 lcd.setCursor(0, 1); 166 lcd.print("--Session over--"); 167 Serial.println("--Session over--"); 168 delay(ALARM_REPEAT_DELAY); 169 } 170 else { 171 minleft = SESSION_TIME; 172 alarmplaying = false; 173 } 174 } 175 lcd.setCursor(0, 1); 176 sprintf(d, "minutes left: %2d", minleft); 177 lcd.print(d); 178 //Serial.println(d); 179 delay(500); 180} 181 182int TwentyFourToTwelve(int hour) { 183 int h = hour % 12; 184 if (h == 0) { 185 h = 12; 186 } 187 return h; 188} 189
Downloadable files
shoni_clock
shoni_clock
shoni_clock
shoni_clock
Documentation
speaker_mount.stl
speaker_mount.stl
shoni_clock_case.stl
shoni_clock_case.stl
speaker_mount.stl
speaker_mount.stl
shoni_clock_case_bottom_cover.stl
shoni_clock_case_bottom_cover.stl
speaker_mount.stl
speaker_mount.stl
shoni_clock_case_bottom_cover.stl
shoni_clock_case_bottom_cover.stl
speaker_mount.stl
speaker_mount.stl
shoni_clock_case.stl
shoni_clock_case.stl
Comments
Only logged in users can leave comments