#define STATE_NORMAL 0
#define STATE_SHORT 1
#define STATE_LONG 2
#include "U8glib.h"
#include "RTClib.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], buf4[20];
DateTime current;
// Button input related values
static const byte BUTTON_PIN = 19;
volatile int resultButton = 0; // global value set by checkButton()
int mode = 2;
//0: digital clock
//1: stopwatch
//2: alarm system
//3: temperature sensor
//stopwatch
bool isStop = true;
unsigned long start, finished, elapsed, prevElapsed;
//alarm clock
const int incrementValue = 5;
int alarmH = -1, alarmM = 60 - incrementValue;
bool isAlarmOn = false, isAlarming = false;
const int SPEAKER_PIN = 6;
//temperature sensor
const float BETA = 3950;
bool isTemperatureDisplayOn = true;
const int RPin = 44;
const int GPin = 46;
const int BPin = 48;
void setup() {
Serial.begin(9600);
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(RPin,OUTPUT);
pinMode(GPin,OUTPUT);
pinMode(BPin,OUTPUT);
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);
displayAlarm(alarmH, alarmM, isAlarmOn);
}
else if (mode == 3) {
processTemperatureSensor();
}
if (isAlarmOn) {
processAlarm(alarmH, alarmM);
}
if (isAlarming) {
playAlarmSound();
displayAlarm(alarmH, alarmM, isAlarmOn);
delay(500);
}
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;
}
}
else if (mode == 3) {
isTemperatureDisplayOn = !isTemperatureDisplayOn;
setRGBColour(0,0,0);
}
if (isAlarming) {
isAlarming = false;
isAlarmOn = false;
}
resultButton = STATE_NORMAL;
break;
}
case STATE_LONG: {
resetStopWatch();
if (mode == 3) {
mode = 0;
} else {
mode++;
}
setRGBColour(0,0,0);
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();
if (h < 0) {
isAlarmOn = false;
} else {
isAlarmOn = true;
}
if (current.hour() == alarmH && current.minute() == alarmM) {
isAlarming = true;
Serial.println("Alarm is ringing");
}
else {
isAlarming = false;
}
}
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 playAlarmSound() {
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 processTemperatureSensor() {
int analogValue = analogRead(A0);
float celsius = 1 / (log(1 / (1023. / analogValue - 1)) / BETA + 1.0 / 298.15) - 273.15;
displayTemperature(isTemperatureDisplayOn, celsius);
}
void displayTemperature(bool isOn, float celsius) {
u8g.firstPage(); //marks the beginning of the picture loop.
do {
if (isOn) {
char *tmpSign = (celsius < 0) ? "-" : "";
float tmpVal = (celsius < 0) ? -celsius : celsius;
int tmpInt1 = tmpVal; // Get the integer (678).
float tmpFrac = tmpVal - tmpInt1; // Get fraction (0.0123).
int tmpInt2 = trunc(tmpFrac * 100); // Turn into integer (123).
// Print as parts, note that you need 0-padding for fractional bit.
sprintf (buf4, "%s%d.%02d C", tmpSign, tmpInt1, tmpInt2);
String heatLevel = classifyTemperature(celsius);
char output[10];
heatLevel.toCharArray(output,10);
u8g.drawStr(0,10, "Temperature Sensor");
u8g.drawStr (40,25,output);
u8g.drawStr(40, 40,buf4);
}
} while ( u8g.nextPage() ); //marks the end of the body of the picture loop
}
String classifyTemperature(float celsius) {
String heatLevel;
if (celsius < 15) {
heatLevel = "COLD";
setRGBColour(0,0,255);
}
else if (15 <= celsius && celsius < 30) {
heatLevel = "MEDIUM";
setRGBColour(255,125,0);
}
else if (30 <= celsius) {
heatLevel = "HOT";
setRGBColour(255,0,0);
}
return heatLevel;
}
void setRGBColour(int red, int green, int blue){
analogWrite(BPin,blue);
analogWrite(GPin,green);
analogWrite(RPin,red);
}
//*****************************************************************
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
}
}