Está en la página 1de 7

LEER UN PULSADOR

CON ARDUINO CON


INTERRUPCIONES Y
DEBOUNCE

4 MAYO, 2016

En la entrada anterior vimos qué son las interrupciones y cómo usarlas para responder a
eventos de hardware en pins.

También dejamos claro que los dispositivos físicos, como pulsadores, detectores ópticos,
etc, presentan un efecto rebote que interfiere con el uso de interrupciones, y que necesitamos
eliminarlo o no podremos usar interrupciones con estos dispositivos.

El proceso de eliminación de este rebote se llama “debounce”. En esta entrada


aprenderemos qué es el rebote y aprenderemos a eliminarlo con debounce por hardware y por
software.
¿QUÉ ES EL DEBOUNCE?
Los dispositivos electrónicos al cambiar de estado generan una señal que, sin ser
perfectamente cuadrada, en general es más o menos “limpia”. Veamos, por ejemplo, la señal
que genera Arduino al cambiar el estado de una salida digital de HIGH a LOW.

Sin embargo el mundo real no es tan bonito. Muchos dispositivos físicos


habitualmente generan ruido en los flancos de señal. Como ejemplo, veamos la variación de
tensión que ocurre cuando el cambio de estado se genera por un pulsador.

Anuncio:
Observar la cantidad de ruido ocurrido tras el flanco. En esencia, en el rango de unos
microsegundos la señal es puro ruido. Todos esos picos pueden provocar disparos múltiples de
una interrupción.

PROBANDO EL REBOTE
Para probar el rebote, simplemente vamos a emplear un cable para conectar el Pin 2 y
Ground (también podéis usar un pulsador o un interruptor).
Activamos la resistencia interna de Pull UP en el Pin 2 y definimos una interrupción al
evento de bajada en el PIN, y en la función ISR asociada simplemente incrementamos un
contador.

En el bucle principal, comprobamos si el contador, y si este ha sido modificado mostramos


su valor por el puerto serie.

1 const int intPin = 2;


2 volatile int ISRCounter = 0;
3 int counter = 0;
4
5
6 void setup()
7 {
8 pinMode(intPin, INPUT_PULLUP);
9 Serial.begin(9600);
10 attachInterrupt(digitalPinToInterrupt(intPin), debounceCount, LOW);
11 }
12
13 void loop()
14 {
15 if (counter != ISRCounter)
16 {
17 counter = ISRCounter;
18 Serial.println(counter);
19 }
20 }
21
22 void debounceCount()
23 {
24 ISRCounter++;
25 }
Al probar nuestro montaje y poner en contacto el PIN 2 a GROUND, esperaríamos que la
variable se incrementara de uno en uno. Pero veremos que en realidad salta varios números
cada vez(incluso varias decenas).

Este es el efecto del rebote. El ruido de la señal está generando múltiples interrupciones cada
vez que conectamos el cable.

ELIMINANDO EL REBOTE
Disponemos de dos formas de aplicar el debounce. Añadiendo dispositivos electrónicos que
filtren la señal (debounce por hardware) o modificando nuestro código para eliminar el rebote
(debounce por hardware).

DEBOUNCE POR HARDWARE


Aplicar un debounce por hardware tiene la ventaja de no incrementar el tiempo de ejecución
de nuestro código. Además, en general, es una solución más robusta. Por contra, tiene la
desventaja de aumentar la complejidad de nuestro montaje.

La forma más sencilla de aplicar un debounce por hardware es colocar un condensador en


paralelo con el dispositivo (pulsador, interruptor, sensor…). Un condensador del orden de 1uF
debería ser suficiente para filtrar la mayoría del ruido.

El esquema de conexión es el siguiente.


En general siempre es conveniente añadir un filtro por hardware cuando empleamos entradas
físicas con interrupciones.

DEBOUNCE POR SOFTWARE


El debounce por software tiene la ventaja de no requerir componentes adicionales.
Resolvemos el rebote únicamente modificando el código de nuestro programa.

Como desventaja, incrementa levemente el tiempo de ejecución y la complejidad del código.


Además, si no aplicamos el código correctamente podemos ignorar interrupciones “verdaderas”.

La forma más sencilla de aplicar un debounce por software es comprobar el tiempo entre
disparos de la interrupción. Si el tiempo es inferior a un determinado umbral de tiempo
(threshold) simplemente ignoramos la interrupción. En definitiva, hemos definido una “zona
muerta” en la que ignoramos las interrupciones generadas.

Para aplicar el debounce por software, modificamos la función ISR de la siguiente forma.
1 const int timeThreshold = 150;
2 const int intPin = 2;
3 volatile int ISRCounter = 0;
4 int counter = 0;
5 long timeCounter = 0;
6
7
8 void setup()
9 {
10 pinMode(intPin, INPUT_PULLUP);
11 Serial.begin(9600);
12 attachInterrupt(digitalPinToInterrupt(intPin), debounceCount, FALLING);
13 }
14
15 void loop()
16 {
17 if (counter != ISRCounter)
18 {
19 counter = ISRCounter;
20 Serial.println(counter);
21 }
22 }
23
24 void debounceCount()
25 {
26 if (millis() > timeCounter + timeThreshold)
27 {
28 ISRCounter++;
29 timeCounter = millis();
30 }
31 }
Un tiempo de 100-200ms es correcto para un pulsador pero en otros casos deberemos ajustar
el tiempo de forma que eliminemos el rebote, pero no ignoremos dos posibles eventos cercanos
“verdaderos”.

En un montaje real, lo mejor es emplear una combinación de ambos sistemas, a la vez


que ajustamos correctamente el valor del condensados y los tiempos del filtro por software para
adaptarlos a nuestro sistema.