3.11. Eliminación de rebotes (debouncing)¶
Un interruptor se dibuja como un contacto perfecto abierto o cerrado, pero los contactos de un interruptor real no conmutan limpiamente entre ambos estados. Vibran – establecen y rompen el contacto eléctrico muchas veces en unos pocos milisegundos antes de estabilizarse. Una entrada GPIO que lee el pin lo percibe como una ráfaga de bordes; un bucle de sondeo descuidado cuenta varias «pulsaciones» para una sola pulsación real, y un manejador de interrupciones se ejecuta varias veces por cada pulsación real.
Un interruptor con rebotes produce una ráfaga de transiciones rápidas antes de estabilizarse.¶
La eliminación de rebotes es la práctica de filtrar la vibración para que cada pulsación física se registre como un único evento. Dos enfoques resuelven esto – software (una regla de temporización en el firmware) o hardware (un pequeño filtro en el cable). No son mutuamente excluyentes.
3.11.1. Eliminación de rebotes por software¶
La idea es recordar cuándo cambió por última vez la entrada y rechazar cambios posteriores dentro de una ventana corta a partir de esa marca de tiempo. El rebote de los contactos suele durar menos de 10 ms; una pulsación real tarda de 50 a 100 ms; una ventana de 30 a 50 ms captura todos los rebotes sin bloquear las pulsaciones reales.
En un bucle de sondeo, lee el pin, compáralo con el último valor estable y acepta un cambio solo después de que haya transcurrido la ventana de eliminación de rebotes:
import time
from machine import Pin
button = Pin("P0", Pin.IN, Pin.PULL_UP)
last_state = 1
last_change = 0
DEBOUNCE_MS = 50
while True:
now = time.ticks_ms()
state = button.value()
if state != last_state and time.ticks_diff(now, last_change) > DEBOUNCE_MS:
last_change = now
last_state = state
if state == 0:
do_action()
time.sleep_ms(10)
Para las lecturas controladas por interrupciones, aplica la misma regla de temporización dentro del manejador y luego pasa la pulsación real al contexto principal mediante micropython.schedule() (consulta Entrada GPIO):
import time
import micropython
from machine import Pin
button = Pin("P0", Pin.IN, Pin.PULL_UP)
last_irq = 0
DEBOUNCE_MS = 50
def handle_press(pin):
do_action()
def on_press(pin):
global last_irq
now = time.ticks_ms()
if time.ticks_diff(now, last_irq) < DEBOUNCE_MS:
return
last_irq = now
micropython.schedule(handle_press, pin)
button.irq(handler=on_press, trigger=Pin.IRQ_FALLING)
La ISR filtra los rebotes por marca de tiempo y encola la función de retorno (callback); handle_press se ejecuta de nuevo en el contexto principal, donde la asignación de memoria y la E/S lenta son seguras.
3.11.2. Eliminación de rebotes por hardware¶
La eliminación de rebotes por hardware filtra la vibración eléctricamente, antes de que llegue al pin. La herramienta estándar es un condensador.
Un condensador es un componente de dos terminales que almacena carga eléctrica. Físicamente, son dos placas conductoras separadas una corta distancia por un aislante (el dieléctrico).
Un condensador de placas paralelas: dos conductores separados por una capa aislante.¶
Aplicar una tensión entre sus terminales impulsa cargas iguales y opuestas hacia las dos placas; la relación es
Q = C × V
donde Q es la carga almacenada (culombios), V es la tensión entre los terminales del condensador y C es su capacitancia (faradios). La capacitancia viene fijada por la construcción del dispositivo; más capacitancia significa más carga almacenada a la misma tensión.
La consecuencia: un condensador no puede cambiar su tensión instantáneamente. La carga que entra o sale tiene que atravesar cualquier resistencia que haya en el camino, y esa resistencia determina la rapidez con la que puede cambiar la tensión.
3.11.2.1. Constante de tiempo RC¶
Cargar un condensador a través de una resistencia produce un suave aumento exponencial hacia la tensión de alimentación, no un escalón. El tiempo característico de ese aumento es la constante de tiempo RC:
τ = R × C
Después de una τ, el condensador ha alcanzado alrededor del 63 % de la tensión de alimentación. Después de 5 τ, supera el 99 % – «completamente cargado» a efectos prácticos.
Un condensador se carga siguiendo una curva exponencial. τ = RC es el tiempo para alcanzar el 63 % de la tensión final.¶
La descarga a través de una resistencia sigue la imagen especular: la tensión cae exponencialmente desde su valor inicial hacia cero, descendiendo al 37 % de la tensión inicial después de una τ, y por debajo del 1 % después de 5 τ.
Un condensador se descarga siguiendo un decaimiento exponencial. τ = RC es el tiempo para caer al 37 % de la tensión inicial.¶
3.11.2.2. El circuito de eliminación de rebotes¶
Un condensador entre un pin de entrada y tierra, alimentado a través de una resistencia en serie, forma un filtro paso bajo. Los picos rápidos no tienen tiempo de cargar o descargar el condensador a través de esa resistencia; el pin permanece cerca de la tensión que tenía antes del pico. Los cambios lentos – una pulsación deliberada – cargan o descargan el condensador y la lectura los sigue.
R1 lleva el lado alto del interruptor hasta Vcc, produciendo una señal de interruptor en bruto que rebota. R2 y C luego filtran en paso bajo esa señal hacia el pin:
Eliminación de rebotes por hardware: R2 y C filtran en paso bajo la señal en bruto del interruptor antes de que llegue al pin.¶
Valores típicos: R1 = 10 kΩ (pull-up), R2 = 10 kΩ (en serie), C = 100 nF.
Cuando el interruptor está abierto, la corriente fluye Vcc → R1 → R2 → condensador (en serie), cargando el condensador a Vcc con τ_charge = (R1 + R2) × C = 2 ms.
Cuando el interruptor se cierra, el nodo del interruptor se fija a tierra y el condensador se descarga únicamente a través de R2 hacia esa tierra con τ_discharge = R2 × C = 1 ms.
Ambos bordes se filtran mediante RC. Como el condensador se encuentra en su propio nodo, aguas abajo de R2 respecto al interruptor, oscila limpiamente entre Vcc (abierto) y 0 V (cerrado) – en estado estacionario no tiene que fluir corriente a través de R1 en ninguno de los dos casos.
3.11.3. Elegir entre ambos¶
El software es la opción por defecto. No cuesta nada en componentes, el umbral es fácil de ajustar y funciona en cualquier pin que la CPU pueda leer.
El hardware merece la pena los componentes cuando el rebote alcanza algo distinto al código de sondeo de la CPU – una interrupción que no debe dispararse dos veces, un contador por hardware, un periférico sin filtro propio.
La eliminación de rebotes por software y por hardware también conviven sin problemas: un pequeño filtro RC suprime los peores picos, y una ventana de eliminación de rebotes por software cubre lo que queda.