#include <U8glib.h>
#include <RTClib.h>
#include <math.h>
RTC_DS1307 rtc;
U8GLIB_SSD1306_128X64 u8g;
#define WIDTH 128
#define HEIGHT 64
enum clock_modes {
DIGITAL,
ANALOG,
STOPWATCH,
ALARM,
TEMP
};
int mode = DIGITAL; //default mode
int temp_mode; //used to restore previous mode
//pins
const int button = 3;
const int thermistor = A0;
const int led_red = 26, led_green = 28, led_blue = 30;
//button tracking
int last_press = 0;
int button_count = 0;
const int buzzer = 13;
void draw_digital()
{
String hour = String(rtc.now().hour());
String minute = String(rtc.now().minute());
String time = String(hour + " : " + minute);
u8g.setPrintPos(33, 38);
u8g.print(time.c_str());
}
void draw_analog()
{
DateTime now = rtc.now();
double hours = now.hour();
double minutes = now.minute();
double minute_angle = minutes * (M_PI / 30) - (M_PI / 2);
u8g.drawLine(64, 32, 30 * cos(minute_angle) + 64, 30 * sin(minute_angle) + 32);
double hour_angle = ((hours + (minutes / 60)) * M_PI / 6) - (M_PI / 2);
u8g.drawLine(64, 32, 15 * cos(hour_angle) + 64, 15 * sin(hour_angle) + 32);
}
void buzz()
{
for (int i = 0; i < 4; i++) {
analogWrite(buzzer, 200);
delay(100);
analogWrite(buzzer, 0);
delay(100);
}
}
int start_time; //time the stopwatch was started
void draw_stopwatch()
{
String time = String(millis() - start_time);
u8g.setPrintPos(33, 38);
u8g.print(time.c_str());
}
int alarm_time; //time the alarm was started
void draw_alarm()
{
int elapsed = millis() - alarm_time;
if (elapsed > 5000) {
//set off alarm
buzz();
//go back to previous action
mode = temp_mode;
}
String time = "Alarm set";
u8g.setPrintPos(0, 0);
u8g.print(time.c_str());
}
void draw_temp()
{
const float BETA = 3950; // should match the Beta Coefficient of the thermistor
int analogValue = analogRead(thermistor);
float celsius = 1 / (log(1 / (1023. / analogValue - 1)) / BETA + 1.0 / 298.15) - 273.15;
String temp = "Temp: " + String(celsius);
u8g.setPrintPos(33, 38);
u8g.print(temp.c_str());
//set LED colour
if (celsius < 15) {
//blue
digitalWrite(led_red, HIGH);
digitalWrite(led_green, HIGH);
digitalWrite(led_blue, LOW);
} else if (celsius < 25) {
//green
digitalWrite(led_red, HIGH);
digitalWrite(led_green, LOW);
digitalWrite(led_blue, HIGH);
} else if (celsius > 25) {
//red
digitalWrite(led_red, LOW);
digitalWrite(led_green, HIGH);
digitalWrite(led_blue, HIGH);
}
}
void read_option()
{
String s = Serial.readStringUntil('\n');
switch (s.charAt(0)) {
case 'A':
mode = ANALOG;
break;
case 'D':
mode = DIGITAL;
break;
default:
Serial.println("unrecognised input");
}
}
void handle_button()
{
if (millis() - last_press > 500 && button_count > 0) {
//user has finished entering menu option
Serial.println(button_count);
switch(button_count) {
case 1:
start_time = millis();
mode = (mode == STOPWATCH) ? temp_mode : STOPWATCH;
break;
case 2:
alarm_time = millis();
mode = (mode == ALARM) ? temp_mode : ALARM;
break;
case 3:
mode = (mode == TEMP) ? temp_mode : TEMP;
break;
}
button_count = 0;
}
}
void button_ISR()
{
if (millis() - last_press < 500 || button_count == 0) {
button_count++;
}
last_press = millis();
}
void setup()
{
u8g.setFont(u8g_font_tpssb);
u8g.setColorIndex(1);
Serial.begin(9600);
pinMode(button, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(button), button_ISR, RISING);
pinMode(buzzer, OUTPUT);
pinMode(thermistor, INPUT);
pinMode(led_red, OUTPUT);
pinMode(led_green, OUTPUT);
pinMode(led_blue, OUTPUT);
rtc.begin();
Serial.println("Enter 'A' for analog or 'D' for digital modes.");
}
void loop() {
//picture loop
u8g.firstPage();
do {
if (Serial.available() > 0) {
//user entered another option
read_option();
temp_mode = mode;
}
handle_button();
switch (mode) {
case DIGITAL:
draw_digital();
break;
case ANALOG:
draw_analog();
break;
case STOPWATCH:
draw_stopwatch();
break;
case ALARM:
draw_alarm();
break;
case TEMP:
draw_temp();
}
} while (u8g.nextPage());
}