/*Si el botón se presiona durante menos de 1s, el LED cambia de estado.
Si se presiona durante más de 1s, el LED parpadea (500ms ON, 500ms OFF).
Si se vuelve a pulsar el botón, se apaga y desactiva el parpadeo (independientemente del estado en que se encuentre).*/
// Librerías.
#include <Arduino.h> // Arduino.
#include <iostream> // Declara los objetos que controlan la lectura y escritura en los flujos estándar.
// Defines
// Pines.
#define PIN_BUTTON 27
#define PIN_LED 26
// Constantes
// Variables.
volatile bool button_interrupt = false; // Variable boleana volatil que indica que no se ha interrumpido el botón.
volatile bool timer_button_interrupt = false; // Variable boleana volatil que indica que no se ha interrumpido el timer del botón.
volatile bool timer_LED_interrupt = false; // Variable boleana volatil que indica que no se ha interrumpido el timer del LED.
volatile bool button_pressed = false; // Variable boleana volatil que indica que no se ha pulsado el botón.
volatile bool long_press = false; // Variable boleana volátil que indica que la pulsación no es larga.
volatile uint8_t state = 0; // Variable numérica entera sin digno volátil que dice el estado en el que estoy.
hw_timer_t *timer_button = NULL; // Puntero del timer del hardward. Primero anulado.
hw_timer_t *timer_LED = NULL;
// Interrupciones.
// Interrupción del botón.
void IRAM_ATTR ButtonState() // IRAM_ATTR es que guarda la interrupción en la memoria flash que es más rápida.
{
button_interrupt = true; // Se ha interrumpido el botón.
button_pressed = !button_pressed; // Cambia estado del botón.
}
// Interrupción de los timer.
void IRAM_ATTR timerInterruptButton()
{
timer_button_interrupt = true; // Se ha interrumpido el timer del botón.
}
void IRAM_ATTR timerInterruptLED()
{
timer_LED_interrupt = true; // Se ha interrumpido el timer del LED.
}
// Funciones.
// SET UP.
void setup()
{
Serial.begin(115200); // Comunicación con el puerto serie.
// Configurar pines como modo salida/entrada.
pinMode(PIN_BUTTON, INPUT_PULLUP);
pinMode(PIN_LED, OUTPUT);
digitalWrite(PIN_LED, LOW); // Primero el LED apagado.
// Interrupción del botón.
// Ata la interrupción de la función ChageLEDState cuando se pulse el botón y cuando se suelte vuelve a activarse la interrupción.
attachInterrupt(digitalPinToInterrupt(PIN_BUTTON), ButtonState, CHANGE);
// Timer botón.
// Inicializar el timer del botón.
// 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.
timer_button = timerBegin(0, 80, true); // Timer 0, divisor de reloj 80.
timerAttachInterrupt(timer_button, &timerInterruptButton, true); // Adjuntar la función de manejo de interrupción.
timerAlarmWrite(timer_button, 1e6, true); // Interrupción cada medio segundo (500ms ON, 500ms OFF).
timerAlarmDisable(timer_button); // Primero el timer deshabilitado hasta que plse el botón.
// Timer del LED.
timer_LED = timerBegin(1, 80, true); // Timer 0, divisor de reloj 80.
timerAttachInterrupt(timer_LED, &timerInterruptLED, true); // Adjuntar la función de manejo de interrupción.
timerAlarmWrite(timer_LED, 5e5, true); // Interrupción cada medio segundo (500ms ON, 500ms OFF).
timerAlarmDisable(timer_LED); // Primero el timer deshabilitado hasta que plse el botón.
}
// LOOP.
void loop()
{
if (button_interrupt) // Si se ha interrumpido el botón.
{
if (button_pressed) // Si el botón pulsado es verdadero.
{
timerAlarmEnable(timer_button); // Habilito el timer del botón.
timer_button_interrupt = false; // Para que no cuente la primera interrupción.
}
else // Si no está pulsado.
{
if (state == 2) // Si estoy en el estado 2.
{
// Lo paro todo.
digitalWrite(PIN_LED, LOW); // Apago el LED.
timerAlarmDisable(timer_LED); // Deshbilitar timer del LED.
timerAlarmDisable(timer_button); // Deshbilitar timer del botón.
state = 0; // Vuelvo al estado 0.
long_press = false;
}
else // Sino estoy en el estado 0 o 1.
{
if (!long_press) // Si la pulsación es menos de 1s.
{
digitalWrite(PIN_LED, !digitalRead(PIN_LED)); // Se cambia el estado del LED.
state = int(digitalRead(PIN_LED)); // Estado 0 si el LED está apagado, 1 si está encendido.
}
else // Sino la pulsación es más de 1 segundo.
{
state = 2;
timerAlarmEnable(timer_LED); // Activo el timer del LED para empezar a parpadear.
}
timerAlarmDisable(timer_button); // Reiniciar timer del botón.
long_press = false;
}
}
button_interrupt = false;
}
if (timer_LED_interrupt) // Si se activa la interrupción del LED.
{
digitalWrite(PIN_LED, !digitalRead(PIN_LED)); // Cambio el estad del LED.
timer_LED_interrupt = false;
}
if (timer_button_interrupt) // Si se activa la interrupción del botón.
{
long_press = true; // Es que la pulsación es larga.
timer_button_interrupt = false;
}
delay(10);
}