Skip to main content

Ejemplo 1

Antes de empezar

Antes de empezar (ToDo: Hablar un poco sobre las interrupciones)...

Enunciado

Hacer una aplicación que cambie el estado de un led cada vez que se presiona un boton.

Hardware

Componentes

#ElementoCantidad
1ESP321
2Pulsador1
3Led1
4Resistencia de 10k1
5Resistencia de 2201

Conexiones

hw_e1

Sofware

A continuación se muestran varias implementaciones en software que cumplen con los requisitos de la aplicación. La lista de implementaciones mostradas se muestra a continuación:

  1. Implementación por polling usando la función delay().
  2. Implementación usando polling + millis.
  3. Implementación usando interrupciones: Problema del debounce.
  4. Implementación usando interrupciones con antidebunce.

Implementación por polling usando la función delay()

A continuación se muestra la implementación por polling usando la función delay(). Para determinar el flanco de subida al precionar el boton se hacen dos lecturas del botón (siguendo la forma: lectura 1 + delay + lectura 2) y se comparan los valores capturados en estas de tal manera que si ambos son diferentes y el valor de la ultima lectura es HIGH se produce un flanco de subida cambiando el estado del led. El algoritmo se resume a continuación:

#define SERIAL_SPEED 9600

const int buttonPin = 12;
const int ledPin = 25;

int buttonState, prev_buttonState;
int ledState;

unsigned long last_DebounceTime = 0;
unsigned long debounce_delay = 10;

void setup() {
// Configuracion de puertos
pinMode(ledPin, OUTPUT);
Serial.begin(SERIAL_SPEED);
// Inicializacion de variables
buttonState = 0;
ledState = LOW;
digitalWrite(ledPin, ledState);
prev_buttonState = buttonState;
// Iniciacion del puerto serial
Serial.println("Inicio...");
}

void loop() {
buttonState = digitalRead(buttonPin);
delay(debounce_delay);
if (buttonState != prev_buttonState) {
// Transición (positiva o negativa)
// Serial.println("[T]");
if (buttonState == HIGH) {
// Transición positiva
Serial.print("[T+]-> Led:");
Serial.println(ledState);
ledState = !ledState;
digitalWrite(ledPin, ledState);
}
}
prev_buttonState = buttonState;
}

Simulación online

En el siguiente link puede simular el código para comprender su funcionamiento.

important

Aunque el código anterior hace lo que se pide, este no es tan eficiente debido al retardo producido por la función delay() entre las dos lecturas. Como la aplicación solo lee un botón no hay problema, pero si por ejemplo, ademas de leer el valor de un botón se estuviera monitoreando una entrada asociada a una alarma, la respuesta de la alarma se retrazaria como minimo por el retardo debido al delay() lo cual haria que el sistema fuera impractico para un caso real donde una señal de estas caracteristicas debe ser atendida lo mas pronto posible.

Implementación por polling usando la función millis()

A continuación se muestra la implementación haciendo uso de la función millis().

#define SERIAL_SPEED 9600

const int buttonPin = 12;
const int ledPin = 25;

int buttonState, prev_buttonState;
int ledState;
int reading;

unsigned long last_DebounceTime = 0;
unsigned long debounce_delay = 50;

void setup() {
// Configuracion de puertos
pinMode(ledPin, OUTPUT);
Serial.begin(SERIAL_SPEED);
// Inicializacion de variables
buttonState = 0;
ledState = LOW;
digitalWrite(ledPin, ledState);
prev_buttonState = buttonState;
// Iniciacion del puerto serial
Serial.println("Inicio...");
}

void loop() {
reading = digitalRead(buttonPin);
// Verificacion si el boton no se ha estabilizado (hay rebote)
if (reading != prev_buttonState) {
// Reset del timer asociado al rebote
last_DebounceTime = millis();
}
// Verificacion si el boton se estabilizo
if ((millis() - last_DebounceTime) > debounce_delay) {
// Se verifica se el boton cambio de valor
if (reading != buttonState) {
buttonState = reading;
Serial.println("[T]");
// Se verifica si el cambio obedece a un flanco positivo
if (buttonState == HIGH) {
// Cambio del led
Serial.print("[T+]-> Led:");
Serial.println(ledState);
ledState = !ledState;
digitalWrite(ledPin, ledState);
}
}
}
prev_buttonState = reading;
}

Simulación online

En el siguiente link puede simular el código para comprender su funcionamiento.

important

Este código soluciona el problema del retardo asociado al caso anterior, sin embargo como se puede notar, la logica se vuelve más compleja.

Codigo interrupciones con problemas de rebote

A continuación se muestra el código usando interrupciones. Este código pese tiene problemas al manejar el rebote del boton.

#define SERIAL_SPEED 9600

const int buttonPin = 12;
const int ledPin = 25;

int ledState;
volatile bool led_change;

void IRAM_ATTR button_ISR() {
led_change = true;
}

void setup() {
// Configuracion de puertos
pinMode(ledPin, OUTPUT);
Serial.begin(SERIAL_SPEED);
// Inicializacion de variables
led_change = false;
ledState = LOW;
digitalWrite(ledPin, ledState);
attachInterrupt(digitalPinToInterrupt(buttonPin), button_ISR, RISING);
// Iniciacion del puerto serial
Serial.println("Inicio...");
}

void loop() {
if (led_change == true) {
// Transición positiva
Serial.print("[T+]-> Led:");
Serial.println(ledState);
ledState = !ledState;
digitalWrite(ledPin, ledState);
led_change = false;
}
}

Simulación online

En el siguiente link puede simular el código para comprender su funcionamiento.

Para entender el efecto del rebote en el programa, mire el siguiente código:

  1. Simule el código haciendo que el botón no tenga rebote (botón ideal). Tenga en cuenta la siguiente figura para esto:

    hw_e1

  2. Simule el código haciendo que el botón tenga rebote (bóton real). La siguiente figura ilustra esto:

    hw_e1

Codigo interrupciones con el problema solucionado

No es el mejor código, pero funciona.

#define SERIAL_SPEED 9600

const int buttonPin = 12;
const int ledPin = 25;

int ledState;

volatile bool led_change;

unsigned long last_DebounceTime = 0;
unsigned long debounce_delay = 70; // Probar con varios valores
// hasta que funcione (10, 20,...)


void IRAM_ATTR button_ISR() {
if(millis() - last_DebounceTime > debounce_delay){
// Software debouncing buton
// ets_printf("ISR triggered\n");
led_change = true;
}
last_DebounceTime = millis();
}

void setup() {
// Configuracion de puertos
pinMode(ledPin, OUTPUT);
Serial.begin(SERIAL_SPEED);
// Inicializacion de variables
led_change = false;
ledState = LOW;
digitalWrite(ledPin, ledState);
attachInterrupt(digitalPinToInterrupt(buttonPin), button_ISR, RISING);
// Iniciacion del puerto serial
Serial.println("Inicio...");
}

void loop() {
if (led_change == true) {
// Transición positiva
Serial.print("[T+]-> Led:");
Serial.println(ledState);
ledState = !ledState;
digitalWrite(ledPin, ledState);
led_change = false;
}
}

Simulación online

En el siguiente link puede simular el código para comprender su funcionamiento.

e1_ok

Referencias