/*
ref https://forum.arduino.cc/t/a-demo-code-explaining-the-switch-case-state-machine-and-how-to-do-things-almost-in-parallel/888172
*/
#define dbg(myFixedText, variableName) \
Serial.print( F(#myFixedText " " #variableName"=") ); \
Serial.println(variableName);
// usage: dbg("1:my fixed text",myVariable);
// myVariable can be any variable or expression that is defined in scope
#define dbgi(myFixedText, variableName,timeInterval) \
{ \
static unsigned long intervalStartTime; \
if ( millis() - intervalStartTime >= timeInterval ){ \
intervalStartTime = millis(); \
Serial.print( F(#myFixedText " " #variableName"=") ); \
Serial.println(variableName); \
} \
}
//includes
#include <Bounce2.h>
#include <TM1637TinyDisplay.h>
// the states for the state-machine
const byte standby = 0;
const byte comienzo_10 = 1;
const byte turno_a = 2;
const byte intermedio_10 = 3;
const byte turno_b = 4;
const byte triple_beep = 5;
byte myState = standby; //estado inicial
char myStateName[][16] = {
"standby",
"comienzo_10",
"turno_a",
"intermedio_10",
"turno_b",
"triple_beep"
};
//constantes
const int8_t duracion_turno = 5; //180
const int pin_boton = 2;
const PROGMEM char FlashString[] = "ERTA TIMER";
//vars int8_t SIGNED 8 bit integer holds values -127....0,...+127
int8_t tiempo_preparacion = 11; //contador 10s, resetear al llamarlo
int8_t tiempo_turno = duracion_turno; //variable contador tiempo de turnos
unsigned long waiting10_timer; //timestamp inicio de 10s
unsigned long waiting180_timer; //timestamp inicio de 180s
unsigned long beeptimestamp; //timestamp inicio de beeper
unsigned long triplebeeptimestamp; //timestamp inicio de triple beep final
bool beep_req = false;
//bool beeping;
byte beepcount;
//instancias
Bounce boton = Bounce(); //instancing bounce
TM1637TinyDisplay display(4, 3); //clock pin 4, data 3
void setup() {
boton.attach(pin_boton, INPUT_PULLUP); // Attach the debouncer to a pin with INPUT_PULLUP mode
boton.interval(25); // Use a debounce interval of 25 milliseconds
pinMode(LED_BUILTIN, OUTPUT); // Setup the LED
display.begin(); // init display
display.clear();
Serial.begin(115200);
Serial.println("ERTA TIMER v0.2"); //insertar version
}
void loop() {
boton.update(); // Update the Bounce instance
if (boton.fell()) { // Call code if button transitions from HIGH to LOW
if (myState == standby) {
Serial.println("boton presionado, iniciar");
waiting10_timer = millis(); //timestamp para inicio de preparación
beep_req = true;
beeptimestamp = millis(); //timestamp beeper
myState = comienzo_10;
tiempo_preparacion = 11;
display.stopAnimation();
display.clear();
beepcount = 0;
}
else if (myState >= 1) { //forced stop/reset
// beep_req=1;
beeptimestamp = millis(); //timestamp beeper
triplebeeptimestamp = millis();
Serial.println("Abort/reset");
display.clear();
myState = triple_beep;
}
}
switch (myState) {
case standby:
//display scroll text, enviar por BT
if (!display.Animate()) {
display.startStringScroll_P(FlashString, 250);
}
break;
case comienzo_10:
// timer de 10 segundos preparacion inicial
if (TimePeriodIsOver(waiting10_timer, 1000)) {
// tick cada 1 segundo
tiempo_preparacion--;
dbg("Tiempo restante preparación ", tiempo_preparacion);
display.showString("PR", 2, 0);
display.showNumber(tiempo_preparacion, false, 2, 2);
if (tiempo_preparacion == 0) {
display.showNumber(tiempo_preparacion, false, 2, 2);
beep_req = true; //pedir beep
tiempo_turno = duracion_turno; //init duración turno
beeptimestamp = millis(); //timestamp beeper
waiting180_timer = millis(); //timestamp turno A
//display.clear();
myState = turno_a;
}
}
break;
case turno_a:
// ciclo turno A
if (TimePeriodIsOver(waiting180_timer, 1000)) {
// tick cada 1 segundo
dbg("Tiempo restante A ", tiempo_turno);
display.showString("A", 1, 0);
display.showNumber(tiempo_turno, false, 3, 1);
tiempo_turno--;
if (tiempo_turno == -1) {
beep_req = true;
tiempo_preparacion = 10; //init duración intermedio
beeptimestamp = millis(); //timestamp beeper
waiting10_timer = millis(); //timestamp para inicio de preparación
//display.clear();
myState = intermedio_10;
}
}
break;
case intermedio_10:
if (TimePeriodIsOver(waiting10_timer, 1000)) {
// tick cada 1 segundo
dbg("Tiempo restante intermedio ", tiempo_preparacion);
tiempo_preparacion--;
display.showString("PR", 2, 0);
display.showNumber(tiempo_preparacion, false, 2, 2);
if (tiempo_preparacion == -1) {
display.showNumber(tiempo_preparacion, false, 2, 2);
beep_req = true;
tiempo_turno = duracion_turno; //init duración turno
beeptimestamp = millis(); //timestamp beeper
waiting180_timer = millis(); //timestamp turno A
//display.clear();
myState = turno_b;
}
}
break;
case turno_b:
// timer de 180 segundos
if (TimePeriodIsOver(waiting180_timer, 1000)) {
// tick cada 1 segundo
dbg("Tiempo restante B ", tiempo_turno);
tiempo_turno--;
display.showString("B", 1, 0);
display.showNumber(tiempo_turno, false, 3, 1);
if (tiempo_turno == -1) {
// beep_req = true;
beeptimestamp = millis(); //timestamp beeper
triplebeeptimestamp = millis();
display.clear();
myState = triple_beep;
}
}
break;
case triple_beep:
if ( TimePeriodIsOver(triplebeeptimestamp, 1000) ) {
beeptimestamp = millis();
beep_req = true;
dbg("conteo beep", beepcount)
//dbg("triple beep_req end", millis());
beepcount++;
if (beepcount >= 3) {
myState = standby;
//break;
}
}
break; // end
}
beeperv2(); //funcion recurrente beeper
}
// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver(unsigned long &startOfPeriod, unsigned long TimePeriod) {
unsigned long currentMillis = millis();
if (currentMillis - startOfPeriod >= TimePeriod) {
// more time than TimePeriod has elapsed since last time if-condition was true
startOfPeriod = currentMillis; // a new period starts right here so set new starttime
return true;
} else return false; // actual TimePeriod is NOT yet over
}
// beeper function, 1s on
void beeperv2() {
if (beep_req == true) {
digitalWrite(LED_BUILTIN, HIGH);
Serial.print("beeb in state ");
Serial.println(myStateName[myState]);
tone(8, 400, 500);
//dbgi("beep_req start", beeptimestamp, 100);
beep_req = false;
}
else if (TimePeriodIsOver(beeptimestamp, 1000)) {
//dbgi("beep_req end",millis(),100);
digitalWrite(LED_BUILTIN, LOW);
}
}