#include <TM1637TinyDisplay.h>
#include <pitches.h>
#define CLK 2
#define DIO 3
#define PIN_START 5
#define PIN_STOP 6
#define PIN_POTENTIOMETER A0
#define PIN_BUZZER 4
#define SECS_PER_MIN 60UL
#define SECS_PER_HOUR 3600UL
#define numberOfSeconds(_time_) (_time_ % SECS_PER_MIN)
#define numberOfMinutes(_time_) ((_time_ / SECS_PER_MIN) % SECS_PER_MIN)
#define numberOfHours(_time_) (_time_ / SECS_PER_HOUR)
#define hmsToMillis(_h_, _m_, _s_) (((_h_) * SECS_PER_HOUR) + ((_m_) * SECS_PER_MIN) + (_s_)) * 1000ul
TM1637TinyDisplay display(CLK, DIO);
int melody[] = {NOTE_E5, NOTE_D5, NOTE_FS4, NOTE_GS4, NOTE_CS5, NOTE_B4, NOTE_D4, NOTE_E4, NOTE_B4, NOTE_A4, NOTE_CS4, NOTE_E4, NOTE_A4};
int durations[] = {8, 8, 4, 4, 8, 8, 4, 4, 8, 8, 4, 4, 2};
bool tonDelay = false;
unsigned long startClockTime;
unsigned long currentClockTime;
unsigned long setClockTime;
bool clock_Set;
enum State {
BEGIN,
IDLE,
RUNNING,
FINISHED,
CLOCK_DISPLAY,
CLOCK_SET_HOURS,
CLOCK_SET_MINUTES,
CLOCK_SET_SECONDS,
RECORD_START_TIME
};
State currentState = BEGIN;
int pinStart = PIN_START;
int pinStop = PIN_STOP;
int pinPotentiometer = PIN_POTENTIOMETER;
int pinBuzzer = PIN_BUZZER;
unsigned long endMillis;
unsigned long currentTime;
int Hour = 0;
int Min = 0;
int Sec = 0;
int minutes;
int note;
void handleBeginState() {
int poti = analogRead(pinPotentiometer);
minutes = static_cast<int>(poti / 17.05);
display.showNumberDec(minutes, 0b01000000, true, 2, 0);
display.showNumberDec(0, 0b01000000, true, 2, 2);
setTime(minutes);
currentState = RUNNING;
}
void handleIdleState() {
while (digitalRead(pinStart) == HIGH) {
int poti = analogRead(pinPotentiometer);
minutes = static_cast<int>(poti / 17.05);
display.showNumberDec(minutes, 0b01000000, true, 2, 0);
display.showNumberDec(0, 0b01000000, true, 2, 2);
delay(100);
if (digitalRead(pinStop) == LOW) {
unsigned long stopButtonPressMillis = millis();
while (digitalRead(pinStop) == LOW)
if ((millis() - stopButtonPressMillis) > 500) {
currentState = CLOCK_DISPLAY;
}
break;
}
}
if (digitalRead(pinStart) == LOW && minutes > 0) {
while (digitalRead(pinStart) == LOW)
setTime(minutes);
currentState = RUNNING;
}
}
void handleRunningState() {
if (digitalRead(pinStop) == LOW) {
while (digitalRead(pinStop) == LOW)
currentState = IDLE;
} else if (millis() >= endMillis) {
currentState = FINISHED;
note = 0;
tonDelay = false;
}
}
void handleFinishedState() {
if (digitalRead(pinStop) == LOW) {
while (digitalRead(pinStop) == LOW)
noTone(pinBuzzer);
currentState = IDLE;
} else {
if ((note % 13 == 0) && (tonDelay)) {
for (int i = 0; i < 200; i++) {
if (digitalRead(pinStop) == LOW) {
while (digitalRead(pinStop) == LOW)
break;
}
delay(10);
}
tonDelay = false;
} else {
int duration = 1000 / durations[note % 13];
tone(pinBuzzer, melody[note % 13], duration);
delay(duration * 1.30);
note++;
tonDelay = true;
}
}
}
void handleClockDisplayState() {
if (millis() < startClockTime){
setClockTime = currentClockTime + 1000;
startClockTime = millis();
}
currentClockTime = (millis() - startClockTime) + setClockTime;
Hour = numberOfHours(currentClockTime / 1000);
Min = numberOfMinutes(currentClockTime / 1000);
unsigned long since = (long)(millis() / 500);
if (since % 2) {
display.showNumberDec(Hour, 0, true, 2, 0);
display.showNumberDec(Min, 0, true, 2, 2);
} else {
display.showNumberDec(Hour, 0b01000000, true, 2, 0);
display.showNumberDec(Min, 0b01000000, true, 2, 2);
}
if (digitalRead(pinStop) == LOW) {
unsigned long stopButtonPressMillis = millis();
while (digitalRead(pinStop) == LOW)
if ((millis() - stopButtonPressMillis) > 500) {
display.showString(" SEt");
currentState = CLOCK_SET_HOURS;
delay(1000);
}
}
if (digitalRead(pinStart) == LOW) {
while (digitalRead(pinStart) == LOW)
currentState = IDLE;
}
}
void handleSetHoursState() {
// Flash hours field
unsigned long since = (long)(millis() / 500);
if (since % 2) {
display.showNumberDec(Hour, 0b01000000, true, 2, 0);
} else
display.clear();
if (digitalRead(pinStart) == LOW) {
while (digitalRead(pinStart) == LOW)
; // Wait for user to let up
currentState = CLOCK_DISPLAY;
}
if (digitalRead(pinStop) == LOW) {
while (digitalRead(pinStop) == LOW)
; // Wait for user to let up
currentState = CLOCK_SET_MINUTES;
}
Hour = (int)analogRead(A0) / 42.625;
}
void handleSetMinutesState() {
// Flash minutes field
unsigned long since = (long)(millis() / 500);
display.showNumberDec(Hour, 0b01000000, true, 2, 0);
if (since % 2) {
display.showNumberDec(Min, 0b01000000, true, 2, 2);
} else
display.showString("", 2, 2);
if (digitalRead(pinStart) == LOW) {
while (digitalRead(pinStart) == LOW)
; // Wait for user to let up
currentState = CLOCK_DISPLAY;
}
if (digitalRead(pinStop) == LOW) {
while (digitalRead(pinStop) == LOW)
; // Wait for user to let up
currentState = CLOCK_SET_SECONDS;
}
Min = (int)analogRead(A0) / 17.05;
}
void handleSetSecondsState() {
// Flash seconds field
unsigned long since = (long)(millis() / 500);
display.showString("S", 2, 0);
if (since % 2) {
display.showNumberDec(Sec, 0b01000000, true, 2, 2);
} else
display.showString("", 2, 2);
if (digitalRead(pinStart) == LOW) {
while (digitalRead(pinStart) == LOW)
; // Wait for user to let up
currentState = RECORD_START_TIME;
}
if (digitalRead(pinStop) == LOW) {
while (digitalRead(pinStop) == LOW)
; // Wait for user to let up
currentState = CLOCK_SET_HOURS;
}
Sec = (int)analogRead(A0) / 17.05;
}
void handleRecordStartTimeState() {
// Record Start Time and countDown
display.clear();
startClockTime = millis();
setClockTime = hmsToMillis(Hour, Min, Sec);
currentClockTime = (millis() - startClockTime) + setClockTime;
clock_Set = false;
currentState = CLOCK_DISPLAY;
}
void setup() {
pinMode(pinStart, INPUT_PULLUP);
pinMode(pinStop, INPUT_PULLUP);
pinMode(pinPotentiometer, INPUT);
pinMode(pinBuzzer, OUTPUT);
currentClockTime = 0;
clock_Set = true;
display.begin();
delay(1000);
}
void displayTime() {
if (currentState != CLOCK_DISPLAY && currentState != CLOCK_SET_HOURS && currentState != CLOCK_SET_MINUTES && currentState != CLOCK_SET_SECONDS && currentState != RECORD_START_TIME) {
unsigned long counter = (millis() >= endMillis) ? millis() - endMillis : endMillis - millis();
unsigned long MINUTES = numberOfMinutes(counter / 1000);
unsigned long SECONDS = numberOfSeconds(counter / 1000);
display.showNumberDec(MINUTES, 0b01000000, true, 2, 0);
display.showNumberDec(SECONDS, 0b01000000, true, 2, 2);
}
}
void setTime(int minutes) {
endMillis = millis() + (minutes * SECS_PER_MIN * 1000);
}
void loop() {
int poti = analogRead(pinPotentiometer);
minutes = static_cast<int>(poti / 17.05);
switch (currentState) {
case BEGIN:
handleBeginState();
break;
case IDLE:
handleIdleState();
break;
case RUNNING:
handleRunningState();
break;
case FINISHED:
handleFinishedState();
break;
case CLOCK_DISPLAY:
handleClockDisplayState();
break;
case CLOCK_SET_HOURS:
handleSetHoursState();
break;
case CLOCK_SET_MINUTES:
handleSetMinutesState();
break;
case CLOCK_SET_SECONDS:
handleSetSecondsState();
break;
case RECORD_START_TIME:
handleRecordStartTimeState();
break;
}
displayTime();
}