#define STATE_NORMAL 0
#define STATE_SHORT 1
#define STATE_LONG 2
#include "U8glib.h"
#include "RTClib.h"
#include "pitches.h"
U8GLIB_SSD1306_128X64 u8g; // create an instant of OLED display
RTC_DS1307 rtc; //create an instant of RTC
char buf1[20], buf2[20], buf3[20];
DateTime current;
static const byte BUTTON_PIN = 19;
volatile int resultButton = 0; // global value set by checkButton()
int mode = 0;
//0: digital clock
//1: stopwatch
//2: alarm system
bool isStop = true;
unsigned long start, finished, elapsed, prevElapsed;
const int incrementValue = 1;
int alarmH = 14, alarmM = 21;
const int SPEAKER_PIN = 6;
void setup() {
Serial.begin(9600);
pinMode(BUTTON_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), checkButton, CHANGE);
u8g.setFont(u8g_font_7x13); // set the font for text
if (! rtc.begin()) {
Serial.println("Couldn't find RTC");
Serial.flush();
abort();
}
}
void loop() {
int longButton=0;
int count=0;
switch (resultButton) {
case STATE_NORMAL: {
if (mode == 0) {
displayDigitalClock();
}
else if (mode == 1) {
processStopWatch();
}
else if (mode == 2) {
processAlarm(alarmH, alarmM);
}
break;
}
case STATE_SHORT: {
if (mode == 1)
{
isStop = !isStop;
}
else if (mode == 2)
{
alarmM += incrementValue;
if (alarmM == 60) {
alarmM = 0;
alarmH ++;
}
if (alarmH == 24) {
alarmH = -1;
alarmM = 60 - incrementValue;
}
}
resultButton = STATE_NORMAL;
break;
}
case STATE_LONG: {
resetStopWatch();
if (mode == 2) {
mode = 0;
} else {
mode++;
}
resultButton = STATE_NORMAL;
break;
}
}
}
void displayDigitalClock() {
current = rtc.now(); //get the current time
sprintf(buf1, "%02d:%02d:%02d", current.hour(), current.minute(), current.second());
u8g.firstPage(); //marks the beginning of the picture loop.
do {
u8g.drawStr(20,10, "Digital Clock");
u8g.drawStr(40, 40,buf1);
} while ( u8g.nextPage() ); //marks the end of the body of the picture loop
delay(1000);
}
void processStopWatch() {
if (isStop) {
start = millis();
prevElapsed = elapsed;
displayStopWatch(elapsed,"Stopping");
} else {
finished = millis();
elapsed = prevElapsed + finished - start;
displayStopWatch(elapsed, "Running");
}
}
void displayStopWatch(int elapsed, char state[10]) {
int h, m, s, ms;
unsigned long over;
h = int(elapsed / 36000000);
over = elapsed % 36000000;
m = int(over/60000);
over = over % 60000;
s = int(over/1000);
ms = over % 1000;
sprintf(buf2, "%02d:%02d:%02d:%03d", h, m, s, ms);
u8g.firstPage(); //marks the beginning of the picture loop.
do {
u8g.drawStr(20,10, "Stopwatch Clock");
u8g.drawStr(30,25, state);
u8g.drawStr(30, 40,buf2);
} while ( u8g.nextPage() ); //marks the end of the body of the picture loop
}
void resetStopWatch() {
prevElapsed = 0;
elapsed = 0;
isStop = true;
}
void processAlarm(int h, int m) {
current = rtc.now();
bool isAlarmOn = false;
if (h < 0) {
isAlarmOn = false;
} else {
isAlarmOn = true;
}
//check when the alarm rings
if (current.hour() == alarmH && current.minute() == alarmM) {
playAlamrSound();
Serial.println("Alarm is ringing");
}
displayAlarm(alarmH, alarmM, isAlarmOn);
}
void displayAlarm(int h, int m, bool isOn) {
sprintf(buf3, "%02d:%02d", h, m);
u8g.firstPage(); //marks the beginning of the picture loop.
do {
u8g.drawStr(23,10, "Alarm Clock");
if (isOn) {
u8g.drawStr(30,25, "On");
u8g.drawStr(40, 40,buf3);
}
else {
u8g.drawStr(30,25, "Off");
}
} while ( u8g.nextPage() ); //marks the end of the body of the picture loop
}
void playAlamrSound() {
tone(SPEAKER_PIN, NOTE_E4);
delay(150);
tone(SPEAKER_PIN, NOTE_G4);
delay(150);
tone(SPEAKER_PIN, NOTE_E5);
delay(150);
tone(SPEAKER_PIN, NOTE_C5);
delay(150);
tone(SPEAKER_PIN, NOTE_D5);
delay(150);
tone(SPEAKER_PIN, NOTE_G5);
delay(150);
noTone(SPEAKER_PIN);
}
//*****************************************************************
void checkButton() {
/*
* This function implements software debouncing for a two-state button.
* It responds to a short press and a long press and identifies between
* the two states. Your sketch can continue processing while the button
* function is driven by pin changes.
*/
const unsigned long LONG_DELTA = 1000ul; // hold seconds for a long press
const unsigned long DEBOUNCE_DELTA = 30ul; // debounce time
static int lastButtonStatus = HIGH; // HIGH indicates the button is NOT pressed
int buttonStatus; // button atate Pressed/LOW; Open/HIGH
static unsigned long longTime = 0ul, shortTime = 0ul; // future times to determine is button has been poressed a short or long time
boolean Released = true, Transition = false; // various button states
boolean timeoutShort = false, timeoutLong = false; // flags for the state of the presses
buttonStatus = digitalRead(BUTTON_PIN); // read the button state on the pin "BUTTON_PIN"
timeoutShort = (millis() > shortTime); // calculate the current time states for the button presses
timeoutLong = (millis() > longTime);
if (buttonStatus != lastButtonStatus) { // reset the timeouts if the button state changed
shortTime = millis() + DEBOUNCE_DELTA;
longTime = millis() + LONG_DELTA;
}
Transition = (buttonStatus != lastButtonStatus); // has the button changed state
Released = (Transition && (buttonStatus == HIGH)); // for input pullup circuit
lastButtonStatus = buttonStatus; // save the button status
if ( ! Transition) { //without a transition, there's no change in input
// if there has not been a transition, don't change the previous result
resultButton = STATE_NORMAL | resultButton;
return;
}
if (timeoutLong && Released) { // long timeout has occurred and the button was just released
resultButton = STATE_LONG | resultButton; // ensure the button result reflects a long press
} else if (timeoutShort && Released) { // short timeout has occurred (and not long timeout) and button was just released
resultButton = STATE_SHORT | resultButton; // ensure the button result reflects a short press
} else { // else there is no change in status, return the normal state
resultButton = STATE_NORMAL | resultButton; // with no change in status, ensure no change in button status
}
}