#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <RTClib.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define buttonPin 2
const int speakerPin = A3;
Adafruit_SSD1306 oled(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
RTC_DS1307 rtc;
String displayTime;
DateTime timerStart;
int mode = 0;
int hour, minute, second;
int timerHour, timerMinute, timerSecond, pauseSecond;
int alarmHour, alarmMinute;
bool timerToggle = false;
bool buttonPressed = false;
void setup() {
Serial.begin(9600);
//Set pinmodes for button and speaker, attach interupt to button
pinMode(buttonPin, INPUT_PULLUP);
pinMode(speakerPin, OUTPUT);
attachInterrupt(0, buttonPress, FALLING);
//Check OLED connection
if (!oled.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
while (true);
}
delay(1000);
//Setuo OLED display
oled.clearDisplay();
oled.setTextSize(1);
oled.setTextColor(WHITE);
oled.setCursor(0, 10);
//Check RTC connection
if (! rtc.begin()) {
Serial.println("Couldn't find RTC");
Serial.flush();
while (true);
}
//Setup clock, timer
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
timerStart = rtc.now();
timerHour, timerMinute, timerSecond, pauseSecond, alarmHour, alarmMinute = 0;
//Print System instructions to serial
Serial.println("----Serial Open----\n");
Serial.println("System Options : ");
Serial.println(" Mode 1: Clock");
Serial.println(" Mode 2: Timer");
Serial.println(" Mode 3: Alarm");
Serial.println("\nSystem Instructions : ");
Serial.println(" -- Hold Button for >1s to change mode");
}
void loop() {
//Check if button interrupt has executed (buttonPressed == true)
if (buttonPressed) {
int count = 0;
bool buttonState = 0;
Serial.println("(Start Press)");
//While button is pressed, increase count/read button input
while (!buttonState){
count += 1;
buttonState = digitalRead(buttonPin);
delay(20);
}
//Calculate duration of press, change mode if > 1s
float duration = count*20.00/1000;
Serial.print("(End press. Press time: ");
Serial.print(duration);
Serial.println(" s)\n");
if (duration >= 1){
timerToggle = false;
changeMode();
}
//Pause timer if mode is Timer (1) and press is < 1s
else if (duration < 1 && mode == 1) {
pauseTimer();
if (timerToggle) { Serial.println(">> Timer Start"); }
else { Serial.println(">> Timer Pause"); }
}
//Set alarm minute if mode is Alarm (2) and press is < 1s
else if (duration < 1 && mode == 2) {
alarmMinute +=1;
if (alarmMinute == 60) { alarmMinute = 0; }
}
//Set alarm hour if mode is Alarm (3) and press is < 1s
else if (duration < 1 && mode == 3) {
alarmHour +=1;
if (alarmHour == 24) { alarmHour = 0; }
}
//Attempt to halt the flow of time if mode if Clock (1) and press is < 1s
else { Serial.println(">> Cannot stop time... :( ");}
delay(200);
//Turn interrupts back on
interrupts();
buttonPressed = false;
}
//Display time on OLED depending on mode
displayTime = getTime(mode);
oledDisplayCenter(displayTime);
//Activate alarm if set alarm time equals real time
if (hour == alarmHour && minute == alarmMinute){
soundAlarm();
}
}
//Function to display text in centre of OLED
void oledDisplayCenter(String text) {
int16_t x1;
int16_t y1;
uint16_t width;
uint16_t height;
//Print text to OLED
oled.getTextBounds(text, 0, 0, &x1, &y1, &width, &height);
oled.clearDisplay();
oled.setCursor((SCREEN_WIDTH - width) / 2, (SCREEN_HEIGHT - height) / 2);
oled.println(text);
oled.display();
}
//Function to register interrupt button press
void buttonPress(){
buttonPressed = true;
delay(20);
//Stops interrupts to prevent interference during hold
noInterrupts();
}
//Function to calculate and return time/timer output as String
String getTime(int mode){
DateTime now = rtc.now();
String time;
//Change output depending on mode setting. 0 = Clock, 1 = Timer,
// 2 = Set Alarm Minute, 3 = Set Alarm Hour
switch (mode) {
case 0:
hour = now.hour();
minute = now.minute();
second = now.second();
time = "";
time += hour;
time += ':';
time += minute;
time += ':';
time += second;
break;
case 1:
//Calculate seconds passed since timer started (timerToggle = true)
if (timerToggle){
timerSecond = now.second()-timerStart.second()+pauseSecond;
//Add to minutes at 60 seconds, reset seconds
if (timerSecond < 0) { timerSecond += 60; }
if (timerSecond > 59) {
timerStart = rtc.now();
pauseSecond = 0;
timerMinute += 1;
}
//Add to hours at 60 minutes, reset minutes
if (timerMinute < 0) { timerMinute += 60; }
if (timerMinute > 59) {
timerMinute = 0;
timerHour += 1;
}
}
//Create string from timer values
time = "";
time += timerHour;
time += ':';
time += timerMinute;
time += ':';
time += timerSecond;
break;
case 2:
//Create string from alarm values
time = "";
time += alarmHour;
time += ':';
time += alarmMinute;
break;
case 3:
time = "";
time += alarmHour;
time += ':';
time += alarmMinute;
break;
}
return time;
}
//Function to iterate through modes then prints action to serial and OLED
void changeMode() {
mode += 1;
if (mode > 3) { mode = 0; }
delay(50);
if ( mode == 0 ){
oledDisplayCenter("Alarm Set!");
Serial.println("\nAlarm Set!");
Serial.println("\nAlarm Instructions : ");
Serial.println(" -- Hold Button for >1s for Timer");
oledDisplayCenter("Mode Changed: Clock");
Serial.println("Mode Changed: Clock");
}
if ( mode == 1 ){
resetTimer();
Serial.println("\nTimer Instructions : ");
Serial.println(" -- Hold Button for >1s to Set Alarm");
Serial.println(" -- Short press to start/stop timer\n");
oledDisplayCenter("Mode Changed: Timer");
Serial.println("Mode Changed: Timer");
}
if ( mode == 2 ){
Serial.println("\nAlarm Instructions : ");
Serial.println(" -- Hold Button for >1s to set hour");
Serial.println(" -- Short press to set minute\n");
oledDisplayCenter("Mode Changed: Set Alarm Minute");
Serial.println("Mode Changed: Set Alarm Minute");
}
if ( mode == 3 ){
Serial.println("\nAlarm Instructions : ");
Serial.println(" -- Hold Button for >1s to see Clock");
Serial.println(" -- Short press to set minute\n");
oledDisplayCenter("Mode Changed: Set Alarm Hour");
Serial.println("Mode Changed: Set Alarm Hour");
}
delay(100);
}
//Function to pause timer
void pauseTimer() {
if (timerToggle) {
pauseSecond = timerSecond;
timerToggle = false;
}
else { timerToggle = true; }
timerStart = rtc.now();
}
//Function to reset timer
void resetTimer() {
timerHour = 0;
timerMinute = 0;
timerSecond = 0;
pauseSecond = 0;
}
//Function to activate the buzzer for alarm
void soundAlarm() {
for (int i = 0; i < 10; i++) {
tone(speakerPin, 300, 100);
delay(100);
tone(speakerPin, 800, 100);
delay(100);
tone(speakerPin, 1300, 100);
delay(100);
}
}