#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// SSD1306 DISPLAY:
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
//Clock variables
String timeStr = "00:00:00";
volatile int hours = 0;
volatile int minutes = 0;
volatile int seconds = 0;
int previousSeconds = 0;
String hoursString = "0";
String minutesString = "0";
String secondsString = "0";
//Analog Clock Variables
float radius = 31;
double angle;
int x1, x2, y1, y2;
const int X_CENTRE = SCREEN_WIDTH/2;
const int Y_CENTRE = SCREEN_HEIGHT/2;
//Stopwatch Variables
volatile bool stopwatchStarted = false;
volatile bool stopwatchFinished = false;
volatile unsigned long startingMillis = 0;
unsigned long stopwatchSeconds = 0;
unsigned long stopwatchMinutes = 0;
unsigned long stopwatchMillis = 0;
String stopwatchStr = "00:00:00";
String stopwatchMinStr = "0";
String stopwatchSecStr = "0";
String stopwatchMilliStr = "0";
void setup()
{
// INITIALIZE SSD1306 DISPLAY:
Wire.begin(); // Start Wire library for I2C
display.begin(SSD1306_SWITCHCAPVCC, 0x3c); // Initialize OLED with I2C address 0x3c
Serial.begin(9600);
display.clearDisplay();
pinMode(2, INPUT);
digitalWrite(2, HIGH); //turn on internal pull-up on pin and set resting state to HIGH
attachInterrupt(digitalPinToInterrupt(2),toggleStopwatch,RISING);
//Setup Timer Interrupt
cli();//stop interrupts
//set timer4 interrupt at 1Hz
TCCR4A = 0;// set entire TCCR1A register to 0
TCCR4B = 0;// same for TCCR1B
TCNT4 = 0;//initialize counter value to 0
// set compare match register for 1hz increments
OCR4A = 15624/1;// = (16*10^6) / (1*1024) - 1 (must be <65536)
// turn on CTC mode
TCCR4B |= (1 << WGM12);
// Set CS12 and CS10 bits for 1024 prescaler
TCCR4B |= (1 << CS12) | (1 << CS10);
// enable timer compare interrupt
TIMSK4 |= (1 << OCIE4A);
sei();//allow interrupts
DrawClock();
ProcessInput();
}
ISR(TIMER4_COMPA_vect)
{
seconds++;
if (seconds==60){ seconds = seconds -60; minutes++; }
if (minutes==60){ minutes = minutes -60; hours++; }
if (hours==24){ hours = 0; }
previousSeconds = seconds;
}
void loop()
{
while (stopwatchStarted == false) { DrawClock(); }
while (stopwatchStarted == true) { DrawStopwatch(); }
}
void ProcessInput()
{
Serial.println("Enter hours: ");
while(Serial.available() == 0) {}
hours = Serial.parseInt();
Serial.end();
Serial.begin(9600);
Serial.println("Enter minutes: ");
while(Serial.available() == 0) {}
minutes = Serial.parseInt();
Serial.end();
Serial.begin(9600);
Serial.println("Enter seconds: ");
while(Serial.available() == 0) {}
seconds = Serial.parseInt();
Serial.end();
Serial.begin(9600);
}
void toggleStopwatch()
{
if (stopwatchStarted == false) { stopwatchStarted = true; startingMillis = millis(); Serial.println("Started"); }
else if (stopwatchFinished == true) { stopwatchStarted = false; stopwatchFinished = false; Serial.println("Reset");}
else if (stopwatchStarted == true) { stopwatchFinished = true; Serial.println("Stopped"); }
}
void DrawStopwatch()
{
delay(27);
if (stopwatchFinished == false)
{
unsigned long milliseconds = millis() - startingMillis;
if (milliseconds > 60000)
{
stopwatchMinutes = milliseconds/60000;
if (milliseconds - (stopwatchMinutes*60000) > 1000)
{
stopwatchSeconds = (milliseconds - (stopwatchMinutes*60000))/1000;
stopwatchMillis = milliseconds - (stopwatchMinutes*60000) - (stopwatchSeconds*1000);
}
}
else if (milliseconds > 1000)
{
stopwatchMinutes = 0;
stopwatchSeconds = milliseconds/1000;
stopwatchMillis = milliseconds - stopwatchSeconds*1000;
}
else
{
stopwatchMinutes = 0;
stopwatchSeconds = 0;
stopwatchMillis = milliseconds;
}
}
if (stopwatchMinutes < 10) { stopwatchMinStr = "0" + String(stopwatchMinutes); } else { stopwatchMinStr = String(stopwatchMinutes); }
if (stopwatchSeconds < 10) { stopwatchSecStr = "0" + String(stopwatchSeconds); } else { stopwatchSecStr = String(stopwatchSeconds); }
int twoDigitMillis = stopwatchMillis/10;
if (twoDigitMillis < 10) { stopwatchMilliStr = "0" + String(twoDigitMillis); } else { stopwatchMilliStr = String(twoDigitMillis); }
stopwatchStr = stopwatchMinStr + ":" + stopwatchSecStr+ ":" + stopwatchMilliStr;
if (stopwatchFinished != false || stopwatchStarted != false)
{
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(12,26);
display.print(stopwatchStr);
display.display();
}
}
void DrawClock()
{
if (previousSeconds != seconds)
{
if (hours < 10) { hoursString = "0" + String(hours); } else { hoursString = String(hours); }
if (minutes < 10) { minutesString = "0" + String(minutes); } else { minutesString = String(minutes); }
if (seconds < 10) { secondsString = "0" + String(seconds); } else { secondsString = String(seconds); }
timeStr = hoursString + ":" + minutesString+ ":" + secondsString;
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(72,8);
display.print(timeStr);
display.drawCircle(X_CENTRE-(SCREEN_WIDTH/4),Y_CENTRE,radius,WHITE);
display.drawCircle(X_CENTRE-(SCREEN_WIDTH/4),Y_CENTRE,1,WHITE);
for (int i = 1; i <60; i++)
{
//second markings
angle = i*6;
angle = angle * 0.0174533;
x1 = X_CENTRE-(SCREEN_WIDTH/4) + (sin(angle) *radius);
y1 = Y_CENTRE + (cos(angle)*radius);
x2 = X_CENTRE-(SCREEN_WIDTH/4) + (sin(angle) *(radius-1));
y2 = Y_CENTRE + (cos(angle)*(radius-1));
display.drawLine(x1,y1,x2,y2,WHITE);
//1-12 markings
angle = i*30;
angle = angle * 0.0174533;
x1 = X_CENTRE-(SCREEN_WIDTH/4) + (sin(angle) *radius);
y1 = Y_CENTRE + (cos(angle)*radius);
x2 = X_CENTRE-(SCREEN_WIDTH/4) + (sin(angle) *(radius-4));
y2 = Y_CENTRE + (cos(angle)*(radius-5));
display.drawLine(x1,y1,x2,y2,WHITE);
//seconds hand
angle = seconds*6;
angle = angle * 0.0174533;
x2 = X_CENTRE-(SCREEN_WIDTH/4) + (sin(angle) *(radius-1));
y2 = Y_CENTRE - (cos(angle)*(radius-1));
display.drawLine(X_CENTRE-(SCREEN_WIDTH/4),Y_CENTRE,x2,y2,WHITE);
//minutes hand
angle = minutes*6;
angle = angle * 0.0174533;
x2 = X_CENTRE-(SCREEN_WIDTH/4) + (sin(angle) *(radius-11));
y2 = Y_CENTRE - (cos(angle)*(radius-11));
display.drawLine(X_CENTRE-(SCREEN_WIDTH/4),Y_CENTRE,x2,y2,WHITE);
//hours hand
angle = hours*30 + (minutes/12) * 6;
angle = angle * 0.0174533;
x2 = X_CENTRE-(SCREEN_WIDTH/4) + (sin(angle) *(radius/2));
y2 = Y_CENTRE - (cos(angle)*(radius/2));
display.drawLine(X_CENTRE-(SCREEN_WIDTH/4),Y_CENTRE,x2,y2,WHITE);
}
display.display();
}
}