#include "U8glib.h"
#include <SPI.h>
#include <RTClib.h>
U8GLIB_SSD1306_128X64 u8g; // create an instant of OLED display
RTC_DS1307 rtc;
//states for length of button presses
#define button 19
#define HALT while(true);
#define STATE_NORMAL 0
#define STATE_SHORT 1
#define STATE_LONG 2
#define STATE_ELONG 3
float pi = 3.14;
int Xmid = 31;
int Ymid = 31;
int sHour = 0;
int sMin = 0;
int sSec = 0;
int Minute = 0;
unsigned long button_time = 0;
unsigned long last_button_time = 0;
volatile int resultButton = 0;
bool changeToSW = false;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200); //serial begin
pinMode(button, INPUT_PULLUP);
u8g.begin();
if (!rtc.begin()) { //if rtc module is not found, display error msg
Serial.println("Couldn't find RTC");
Serial.flush();
abort();
}
rtc.adjust(DateTime(2022, 8, 25, 11, 30, 0)); //set randon date/time
u8g.setFont(u8g_font_7x13); // set the font for text
attachInterrupt(digitalPinToInterrupt(button), clock_change, CHANGE);
//attachInterrupt(digitalPinToInterrupt(19), clock_change2, FALLING);
Serial.println("Enter time in format hhmm"); //prompt user
}
void clock_change () {
//int state = digitalRead(19);
//set to true, create function in which the stopwatch will run
//if (changeToSW is true, call the stopwatch funtion in main so we can allow looping)
//when in loop, if button pressed for less then 3 secs, start/ stop watch (check for high and low pin).
//button_time = millis(); //start counting
//mechanism to stop millis from accumulating
//attachInterrupt(digitalPinToInterrupt(19), clock_change2, FALLING);
const unsigned long LONG_DELTA = 2000ul; // hold seconds for a long press
const unsigned long ELONG_DELTA = 4000ul;
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, ElongTime = 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, timeoutLongE = false; // flags for the state of the presses
buttonStatus = digitalRead(button); // read the button state on the pin "BUTTON_PIN"
timeoutShort = (millis() > shortTime); // calculate the current time states for the button presses
timeoutLong = (millis() > longTime);
timeoutLongE = (millis() > ElongTime);
if (buttonStatus != lastButtonStatus) { // reset the timeouts if the button state changed
shortTime = millis() + DEBOUNCE_DELTA;
longTime = millis() + LONG_DELTA;
ElongTime = millis() + ELONG_DELTA;
}
Transition = (buttonStatus != lastButtonStatus); // has the button changed state
Released = (Transition && (buttonStatus == HIGH));
lastButtonStatus = buttonStatus;
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 (timeoutLongE && Released) {
resultButton = STATE_ELONG | resultButton;
}
else 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
//Serial.println("pressed for long!");
}
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
}
}
/*
void clock_change2 () {
last_button_time = millis(); //time when button is released
Serial.println(last_button_time - button_time);
if ((last_button_time - button_time) >= 3000) { //check time
changeToSW = true; //set flag to initiate stopwatch
button_time = last_button_time;
Serial.println("long press");
Serial.println(button_time);
}
else {
//changeToSW = false;
Serial.println("Short Press");
Serial.println(button_time);
}
//mechanism to stop millis from accumulating
attachInterrupt(digitalPinToInterrupt(19), clock_change, RISING);
}
*/
int pressed = 0;
int state = 0;
int startSW = 0;
unsigned long timer = 0;
int ms = 0;
int mint = 0;
int seconds = 0;
int sc = 0;
int miR = 0;
void playSW() {
//u8g.drawStr(20, 60, "hello");
u8g.setColorIndex(0);
u8g.drawBox(1, 1, 64, 128);
u8g.setColorIndex(1);
if (digitalRead(button) == 0) { //if button is pressed
if (pressed == 0) //button state control
{
state++; //go the next stage
pressed = 1; //set pressed to 1
if (state > 3) state = 0; //go to state 0 after last state
}
}
else
{
pressed = 0;
}
if (state == 0) {
u8g.drawStr(15, 35, "PRESS TO START!"); //prompt user in first state
timer = 0; //need to set timer to 0 when start again
sc = 0;
mint = 0;
timer = 0;
miR = 0;
ms = 0;
startSW = 0;
}
if (state == 1) { //state to run stopwatch
u8g.drawStr(30, 10, "STOPWATCH");
if (startSW == 0) {
startSW = 1;
timer = millis();
}
ms = (millis() - timer); //millisecond time
mint = ms / 60000; //convert to minutes
seconds = ms / 1000; //convert to seconds
if (seconds > 59) { //if one minute has passed
sc = (seconds / 1000) - (mint * 60); //
}
else {
sc = seconds;
}
miR = (ms % 1000) / 10;
//convert to char array and display on oled
String display = String(mint) + ":" + String(sc) + ":" + String(miR);
int strLen = display.length() + 1;
char disC[strLen];
display.toCharArray(disC, strLen);
u8g.drawStr(40, 45, disC);
}
if (state == 2) { //state to display global varibles (time stopwatch was stopped)
//u8g.setCursorPos(52,0);
u8g.setColorIndex(0);
u8g.drawBox(1, 1, 64, 128);
u8g.setColorIndex(1);
u8g.drawStr(35, 10, "ELAPSED:");
//u8g.setCursorPos(42,30);
String display = String(mint) + ":" + String(sc) + ":" + String(miR);
int strLen = display.length() + 1;
char disC[strLen];
display.toCharArray(disC, strLen);
u8g.drawStr(40, 45, disC);
}
if (state == 3) { //show clock interface when button pressed 3 third time
showClock();
}
}
void hourHand (int hour, int minute) {
//trignometry to draw to hour hand
//formula for y pos: y = (R*cos(pi-(2*pi)/12*hour-(2*PI)/720*minute))
//formula for x pos: x = (R*sin(pi-(2*pi)/12*hour-(2*PI)/720*minute))
float x, y;
y = (20 * cos(pi - (2 * pi) / 12 * hour - (2 * PI) / 720 * minute)) + Ymid;
x = (20 * sin(pi - (2 * pi) / 12 * hour - (2 * PI) / 720 * minute)) + Xmid;
u8g.drawLine(Xmid, Ymid, x, y);
}
void minHand(int minute)
{
//trignometry to draw to minute hand
//formula for y pos: y = (R*cos(pi-(2*pi)/60*minute))
//formula for x pos: x = (R*sin(pi-(2*pi)/60*minute))
float x, y;
y = (22 * cos(pi - (2 * pi) / 60 * minute)) + Ymid;
x = (22 * sin(pi - (2 * pi) / 60 * minute)) + Xmid;
u8g.drawLine(Xmid, Ymid, x, y);
}
void secHand(int second) {
//trignometry to draw to second hand
//formula for y pos: (R*cos(pi-(2*pi)/60*second))
//formula for x pos: (R*sin(pi-(2*pi)/60*second))
float x, y;
y = (24 * cos(pi - (2 * pi) / 60 * second)) + Ymid;
x = (24 * sin(pi - (2 * pi) / 60 * second)) + Xmid;
u8g.drawLine(Xmid, Ymid, x, y);
}
int swap = 0;
void loop() {
// put your main code here, to run repeatedly:
// DateTime now = rtc.now(); //store date data into now variable
//sHour = now.hour();//store hour data
//sMin = now.minute();//store minute data
switch (resultButton) { //swtich statement for varible
case STATE_NORMAL: { //default state
/* Serial.print(".");
count++;
count = count % 10;
if (count==0) Serial.println(""); */
break;
}
case STATE_SHORT: { //short press state
Serial.println("Short press has been detected");
//digitalWrite(LED,HIGH);
//delay(1000);
//digitalWrite(LED, LOW);
resultButton = STATE_NORMAL; //take no action, go to default state
break;
}
case STATE_LONG: { //long press state
Serial.println("Button was pressed for long time");
//digitalWrite(LED,HIGH);
//delay(3000);
//digitalWrite(LED, LOW);
//longButton++;
changeToSW = true;
resultButton = STATE_NORMAL;
break;
}
case STATE_ELONG: { //extra long state
Serial.println("Oops! See Distinction task for this functionality!");
resultButton = STATE_NORMAL;
break;
}
}
if (changeToSW == true) {
u8g.firstPage();
do {
playSW();
} while ( u8g.nextPage() && rtc.isrunning());
}
else {
u8g.firstPage(); //marks the beginning of the picture loop.
do {
showClock();
} while ( u8g.nextPage() && rtc.isrunning()); //marks the end of the body of the picture loop
u8g.setColorIndex(1);
u8g.drawStr(0, 20, "outside");
}
}
void showClock() {
u8g.setColorIndex(1); // set the colour to white
for (int i = 0; i < 3; i++) {
u8g.drawCircle(Xmid, Ymid, 31 - i); //draw outer clock circle, three lines
}
for (int i = 0; i < 4; i++) {
u8g.drawCircle(Xmid, Ymid, i); //draw middle circle
}
int a = 0;
if (Serial.available() > 0 ) {
Minute = Serial.parseInt(); //read time input from serial
Serial.read(); //get rid of carriage value
a = 1; //set to indicate serial has been used
}
int firstPart = Minute / 100; //get hour part of input
int secPart = Minute - firstPart * 100; //get minute part of input
if (a == 1) //if serial is used
{
rtc.adjust(DateTime(2022, 8, 25, firstPart, secPart, 0)); //adjust time to input
}
DateTime now = rtc.now(); //continue from time
sHour = now.hour();//store hour data
sMin = now.minute();//store minute data
sSec = now.second(); //store second data
//coverting data into string then char array
String digitalC = String(sHour) + ":" + String(sMin);
int strLen = digitalC.length() + 1;
char digC[strLen];
digitalC.toCharArray(digC, strLen);
//pass data to hand functions
minHand(sMin);
hourHand(sHour, sMin);
secHand(sSec);
//draw digital clock
u8g.drawStr(80, 35, digC);
}