#include <TM1637TinyDisplay.h>
#include <ButtonDebounce.h>
#include <EveryTimer.h>
/*
* Demo of classic alarm clock setting using three buttons
* All buttons are debounced.
* Usage: Long-press Set to cycle state. Up/Down to change.Timer
* EveryTimer and ButtonDebounce does not use MCU Timer.
*/
TM1637TinyDisplay display(4,3);
ButtonDebounce buttonDown(5, 50);
ButtonDebounce buttonUp(6, 50);
ButtonDebounce buttonMenu(7, 400);
EveryTimer timer;
bool active = true;
byte hh = 12; // time
byte mm = 1;
byte ahh = 12; // alarm
byte amm = 2;
unsigned long ms = 0; // last millisek.
char outtext[] = "0000"; //display buffer
byte state = 0; // 0=normal, 1=set/blink hh, 2=set/blink mm
// 3=set/blink ahh, 4=set/blink amm, 5=alarm
void onButtonUpChange(const int bstate)
{
if (bstate == 0) //pushed and not released
{
switch (state)
{
case 1:
hh = hh == 23 ? hh = 0 : hh+1;
break;
case 2:
mm = mm == 59 ? mm = 0 : mm+1;
break;
case 3:
ahh = ahh == 23 ? ahh = 0 : ahh+1;
break;
case 4:
amm = amm == 59 ? amm = 0 : amm+1;
break;
}
updateDisplay(true);
}
}
void onButtonDownChange(const int bstate)
{
if (bstate == 0)
{
switch (state)
{
case 1:
hh = hh == 0 ? hh = 23 : hh-1;
break;
case 2:
mm = mm == 0 ? mm = 59 : mm-1;
break;
case 3:
ahh = ahh == 0 ? ahh = 23 : ahh-1;
break;
case 4:
amm = amm == 0 ? amm = 59 : amm-1;
break;
}
updateDisplay(true);
}
}
void onButtonMenuChange(const int bstate)
{
if (bstate == 0)
{
//this is the state circle
switch (state)
{
case 0:
state = 1;
break;
case 1:
state = 2;
break;
case 2:
state = 3;
break;
case 3:
state = 4;
break;
case 5:
digitalWrite(A7, HIGH); //buzzer off
state = 0;
break;
default: //case 4
state = 0;
// Write to RTC here
}
//Serial.print("new state ");
//Serial.println((int)state);
updateDisplay(true);
}
}
void updateDisplay(bool on)
{
byte h;
byte m;
if (state >= 3)
{
h = ahh;
m = amm;
} else
{
h = hh;
m = mm;
}
//Update outtext with hh and mm (primitive formatter)
outtext[0] = '0' + (h / 10);
outtext[1] = '0' + (h % 10);
outtext[2] = '0' + (m / 10);
outtext[3] = '0' + (m % 10);
//blink h or m
if (!on)
{
if (state == 1 || state == 3 || state == 5)
{
outtext[0] = ' ';
outtext[1] = ' ';
}
if (state == 2 || state == 4 || state == 5)
{
outtext[2] = ' ';
outtext[3] = ' ';
}
}
display.showString(outtext, 4, 0, 0b01000000);
}
void onBeat()
{
unsigned long t = millis();
Serial.print(state);
Serial.print(" ");
Serial.println(hh*100+mm);
if (t - ms >= 10000) // 1 sec elapsed event
{
ms = t;
if (mm == 59)
{
mm = 0;
hh = hh == 23 ? hh = 0 : hh+1;
} else
{
mm++;
}
}
if (state == 0 && hh == ahh && mm == amm) //alarm
{
state = 5;
digitalWrite(13, HIGH); //buzzer on, press set to cancel
}
if (state == 5 && mm != amm) //alarm timed out
{
state = 0;
digitalWrite(13, LOW); //buzzer off
}
if (state > 0)
{
active = !active;
}
// sync with RTC here each time or less
updateDisplay(active);
}
void setup() {
ms = millis();
pinMode(A7, OUTPUT);
digitalWrite(A7, HIGH);
display.begin();
Serial.begin(9600);
Serial.println(A7);
buttonUp.setCallback(onButtonUpChange);
buttonDown.setCallback(onButtonDownChange);
buttonMenu.setCallback(onButtonMenuChange);
timer.Every(500, onBeat);
timer.Start(); //get blink events
updateDisplay(true);
}
void loop() {
buttonDown.update();
buttonUp.update();
buttonMenu.update();
timer.Update();
// Display is only updated in eventhandlers.
// RTC should update time in onBeat() or a separate
// onMinuteChange() event.
}