¿Qué es un circuito antirrebote?
Los pulsadores, switches y relés están en todos lados.
Cuando los conectamos a un microcontrolador (PIC, ESP32, Arduino, etc.) esperamos un cambio de estado limpio por cada pulsación. En la práctica no ocurre así: los contactos mecánicos rebotan durante unos milisegundos y generan varias transiciones antes de estabilizarse. A esto se le llama rebote de contacto (contact bounce).
Ideal vs. real: sin rebote (arriba) vs. con rebote (abajo)
En aplicaciones lentas (encender una lámpara) el rebote pasa desapercibido.
En sistemas digitales (contadores, menús, teclados) puede convertirse en pulsaciones falsas.
¿Por qué rebotan los contactos?
Por masa, elasticidad y vibración de las piezas metálicas. Al presionar o soltar, los contactos no se quedan quietos al primer intento: golpean y “tiemblan” durante 1–20 ms (depende de tipo/calidad, desgaste, humedad, temperatura).
Pull-up vs Pull-down (y dónde aparece el rebote)
Hay dos formas comunes de cablear un botón:
Pull-up: el pin está en
1por defecto (resistencia a Vcc). Al presionar, cae a0.PLACEHOLDER IMG: "button-pullup-bounce.png" — Esquema + forma de onda (alto→bajo con rebote)Pull-up: rebote al ir de alto a bajo
Pull-down: el pin está en
0por defecto (resistencia a GND). Al presionar, sube a1.PLACEHOLDER IMG: "button-pulldown-bounce.png" — Esquema + forma de onda (bajo→alto con rebote)Pull-down: rebote al ir de bajo a alto
Cómo eliminar el rebote (antirrebote)
Nos quedamos con dos estrategias sencillas y efectivas:
(1) Hardware con RC y (2) Software con máquina de estados usando millis().
1) Antirrebote por hardware con filtro RC
Vamos a suponer un rebote de 20 ms para simplificar. La idea es que el filtro sea un poco más lento que ese rebote para que lo “suavice”.
- Esquema (pull-up típico): usa un pull-up a Vcc, el botón a GND, y coloca un condensador del pin a GND.
- Cálculo directo: un RC se define por su constante de tiempo ( \tau = R \cdot C ). Queremos que (5\tau > 20,\text{ms}), así el pin no cruza varias veces el umbral durante el rebote.
Ejemplo práctico (con 20 ms):
[
R = 100,\text{k}\Omega, \quad C = 47,\text{nF} \quad \Rightarrow \quad \tau \approx 4.7,\text{ms} \quad \Rightarrow \quad 5\tau \approx 23.5,\text{ms}
]
Arriba: rebote crudo. Abajo: el RC hace que el pin cruce el umbral una sola vez
Circuito recomendado (3.3 V o 5 V, pull-up)
- Rpull-up = 100 kΩ a Vcc
- SW1 a GND
- C = 47 nF del pin a GND
- (Opcional) Rserie = 100 Ω con el botón para limitar picos de corriente hacia el condensador
Pull-up externo de 100 kΩ + C de 47 nF → 5τ ≈ 23.5 ms
Nota: El RC añade un retardo a la lectura. Si quieres más rapidez, reduce un poco (R) o (C) y valida que siga filtrando bien.
2) Antirrebote por software con millis() (no bloqueante)
Usaremos una máquina de estados muy simple: detecta un cambio crudo, abre una ventana de estabilidad y confirma el nuevo estado si pasan ~35 ms sin más cambios. No bloquea la CPU.
const int buttonPin = 2; // INPUT_PULLUP si no usas RC
const int led = 13;
const unsigned long debounceMs = 35; // ventana de estabilidad
int stableState = HIGH; // reposo en HIGH (pull-up)
int lastRead = HIGH;
unsigned long lastEdgeMs = 0;
void setup() {
pinMode(buttonPin, INPUT_PULLUP); // o INPUT si usas RC externo
pinMode(led, OUTPUT);
}
void loop() {
int reading = digitalRead(buttonPin);
// 1) Cambio crudo → reinicia ventana
if (reading != lastRead) {
lastEdgeMs = millis();
lastRead = reading;
}
// 2) Pasado debounceMs sin más cambios → confirma estado
if ((millis() - lastEdgeMs) > debounceMs && reading != stableState) {
stableState = reading;
// Ejemplo: actuar al PRESIONAR (pull-up: HIGH->LOW)
if (stableState == LOW) {
digitalWrite(led, !digitalRead(led)); // toggle
}
// Si prefieres actuar al SOLTAR: (stableState == HIGH)
}
}
Tip: si usas interrupciones, es mejor llevar al pin de IRQ una señal ya filtrada por RC y, en la ISR, solo detectar el flanco.
Conclusión y recomendaciones (en 8 puntos)
- Usa
millis()si no quieres tocar la PCB. - Combina ambos (RC moderado +
millis()) para producto robusto. - Valores de arranque: RC 100 kΩ + 47 nF (≈5τ = 23.5 ms),
debounceMs35 ms. - Mide el rebote con osciloscopio; si no, diseña para ~20 ms y ajusta.
- Evita
delay(); usa ventana no bloqueante conmillis()o FSM. - En PCB, deja pads DNF para R/C y pon el C cerca del pin (retorno GND corto).
- Si usas IRQ, filtra antes con RC y en la ISR solo detecta el flanco.
