/*
Author: Juan M. Gandarias
Date: 03/11/2023
Description: ejemplo_fsm_builder-2
*/
#define LED_PIN 26 // LED conectado a GPIO26
#define BUTTON_PIN 14 // BUTTON conectado a GPIO14
hw_timer_t *timer0 = NULL; // Puntero al timer0 del hardware
hw_timer_t *timer1 = NULL; // Puntero al timer1 del hardware
volatile uint8_t interrupt_counter = 0; // Variable volátil para contar cuántas veces se produce la interrupción
volatile uint8_t fsm_state = 0; // Variable volátil para almacenar el estado de la FSM
volatile bool long_pressed = false; // Variable volátil para detectar cuándo se ha presionado
volatile uint8_t timer1_interrupt_counter = 0; // Variable volátil para contar los segundos que está pulsado el botón
volatile bool button_pressed = false; // Variable volátil que almacena el estado del botón (true = pulsado)
volatile bool button_interrupted = false; // Variable volátil que indica si el botón se ha interrumpido o no
volatile bool timer0_interrupted = false; // Variable volátil que indica si ha habido una interrupción del timer0
volatile bool timer1_interrupted = false; // Variable volátil que indica si ha habido una interrupción del timer1
// Callback ISR botón cambia de estado (se pulsa o se suelta)
void IRAM_ATTR buttonStateChange()
{
button_interrupted = true; // Se ha interrumpido el botón
button_pressed = !button_pressed; // Almaceno el cambio el estado del botón
}
// Callback ISR interrupción del timer 0
void IRAM_ATTR timer0Interrupt()
{
timer0_interrupted = true;
}
// Callback ISR interrupción del timer 1
void IRAM_ATTR timer1Interrupt()
{
timer1_interrupted = true;
}
// Función setup
void setup()
{
Serial.begin(115200);
// Establecer modos de los GPIO digitales del LED y BUTTON
pinMode(LED_PIN, OUTPUT);
pinMode(BUTTON_PIN, INPUT_PULLUP);
// Inicializar interrupción por pulsación del botón
attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), buttonStateChange, CHANGE); // Flanco de bajada = botón se presiona
// Inicializar el timer0
// Parámetro 1: Timer que queremos usar. El ESP32 tiene 4 timers => valores válidos 0,1,2,3
// Parámetro 2: Prescaler. El reloj por defecto del ESP32 va a 80MHz. Si ponemos 80, dividimos el reloj por 80, dándonos 1 000 000 ticks/s
// Parámetro 3: true indica que el timer empieza en ON, false sería OFF
timer0 = timerBegin(0, 80, true); // Timer 0, divisor de reloj 80
timerAttachInterrupt(timer0, &timer0Interrupt, true); // Adjuntar la función de manejo de interrupción
timerAlarmWrite(timer0, 5e5, true); // Interrupción cada medio segundo (500ms ON, 500ms OFF)
// Inicializar el timer1
timer1 = timerBegin(1, 80, true); // Timer 1, divisor de reloj 80
timerAttachInterrupt(timer1, &timer1Interrupt, true); // Adjuntar la función de manejo de interrupción
timerAlarmWrite(timer1, 1e6, true); // Interrupción cada segundo
// Empezamos con el LED apagado
digitalWrite(LED_PIN, LOW);
}
// Función loop
void loop()
{
switch (fsm_state) {
case 0: // Estoy en el estado 0 - LED apagado
if (button_interrupted) { // Si ha habido una interrupción del botón
if (button_pressed) { // Si está pulsado
Serial.println("Button pressed");
Serial.println("Counting time ON");
timerAlarmEnable(timer1); // Activo el timer1 para que empiece a contar el tiempo
} else {
Serial.println("Button released");
}
else
{
if (!long_pressed) // Presionado menos de 1s
{
digitalWrite(LED_PIN, !digitalRead(LED_PIN)); // Se cambia el estado del LED
fsm_state = int(digitalRead(LED_PIN)); // FSM en estado 0 si el LED está apagado, 1 si está encendido
Serial.println(fsm_state); // Deubg
timerAlarmDisable(timer0); // Desactivo el timer0 para dejar a parpadear
}
else // Presionado más de 1s
{
timerAlarmEnable(timer0); // Activo el timer0 para empezar a parpadear
Serial.println("Counting time OFF");
}
// Desactivo el timer1 para que dejar de contar el tiempo
timerAlarmDisable(timer1); // Deshabilitar timer 1
Serial.println("Counting time OFF");
long_pressed = false; // Se pone a FALSE la variable booleana que indica que la pulsación ha sido larga
timer1_interrupt_counter = 0;
}
button_interrupted = false;
}
if (timer1_interrupted) { // Si se ha interrumpido el timer1
long_pressed = true; // Se pone a TRUE la variable booleana que indica que la pulsación ha sido larga
timer1_interrupted = false; // Desactivo la variable de control de interrupción del timer1
}
break;
case 1: // Estoy en el estado 1 - LED encendido
if (button_interrupted && !button_pressed) { // Si se ha habido una interrupción del botón y se ha soltado el botón - Ir a estado 0
Serial.println("Button released");
digitalWrite(LED_PIN, LOW); // Apagar el LED
fsm_state = 0; // FSM va al estado 0
Serial.println(fsm_state); // Debug
button_interrupted = false; // Desactivo la variable de control de interrupción del botón
}
break;
case 2: // Estoy en el estado 2 - LED parpadeando
if (timer0_interrupted) { // Si hay una interrupción del timer0 - parpadear
digitalWrite(LED_PIN, !digitalRead(LED_PIN)); // Alternar el estado del LED
timer0_interrupted = false; // Desactivo la variable de control de interrupción del timer0
}
if (button_interrupted && !button_pressed) { // Si se ha habido una interrupción del botón y se ha soltado el botón - Ir a estado 0
Serial.println("Button released");
digitalWrite(LED_PIN, LOW);
fsm_state = 0;
Serial.println(fsm_state);
timerAlarmDisable(timer0); // Deshbilitar timer 0
timerAlarmDisable(timer1); // Deshbilitar timer 1
Serial.println("Counting time OFF");
timer1_interrupt_counter = 0;
long_pressed = false; // Poner a FALSE la variable long_pressed
button_interrupted = false; // Desactivo la variable de control de interrupción del botón
}
break;
}
delay(10); // Necesario para el rendimiento en Wokwi
}