Electrónica Digital · Tema 11

Botones y rebotes

El botón miente 20 veces antes de decir la verdad: pull que define, rebote que ensucia y debounce que limpia.

01 · Punto de partida

Presionás 1, cuenta 20

El contacto mecánico rebota 5–50 ms generando decenas de flancos: un contador ve 20 pulsaciones donde tu dedo hizo 1. Tres remedios: pull bien puesto, filtro RC + Schmitt, o debounce por software.

  • ¿Pull-up o pull-down, y de qué valor?
  • ¿Cuánto dura un rebote?
  • ¿Cómo se filtra en hardware?
  • ¿Y en software?

02 · Pull

Reposo definido

Botón entre entrada y masa, pull-up 10k a Vcc: suelto lee 1 (0,5 mA por el pull), presionado lee 0. Nunca botón directo a Vcc (al presionar, corto Vcc-masa por el pull… o peor, sin pull: corto franco).

suelto → pull → 1 →presiono → masa →0 (+ rebotes)

03 · Rebote

20 flancos por 1 dedo

Qué rompe el rebote.
VíctimaSíntomaRemedio
ContadorSuma 20 por presiónDebounce sí o sí
Interrupción20 ISR por presiónDebounce por tiempo
Reloj manualAvanza varios pasosRC + Schmitt (74HC14)
LED simpleNada visibleNinguno (el ojo promedia)

Regla: si el circuito cuenta flancos, el rebote lo rompe. Si solo muestra niveles, ni se nota.

04 · Filtros

RC + Schmitt o latch

RC + 74HC14
R = 10k, C = 1 µF → τ = 10 ms: el capacitor no sigue los rebotes y el Schmitt (histéresis) entrega flanco único. Clásico universal.
Latch SR
Conmutador + 2 NAND/NOR cruzadas: el primer contacto traba, los rebotes no destaban. Ideal con switch SPDT.
Software
Al detectar cambio, ignorar 20–50 ms: dos líneas cuestan cero hardware. Para teclados de micro, el favorito.
Pull interno
Muchos micros traen pull-up programable (20–50k): ahorra la R externa, no el debounce.

05 · Rebote en código

Contar bien

Tren de rebotes simulado: contador crudo vs con debounce.

Python en tu navegador. Achicá el debounce y mirá colarse los rebotes.

import random

random.seed(11)
rebotes = [0] + [random.choice([0, 1]) for _ in range(14)] + [1] * 6
print("tren:", "".join(map(str, rebotes)))
flancos = sum(1 for a, b in zip(rebotes, rebotes[1:]) if a != b)
print(f"flancos={flancos} (el dedo hizo 1)")

Un tren típico da 7 flancos por una presión. ¿Cuántos da tu seed si lo cambiás?

Debounce por tiempo

def debounce(tren, ms_por_muestra=1, ventana_ms=20):
    cuenta, ultimo, i = 0, 0, 0
    while i < len(tren):
        if tren[i] != ultimo:
            cuenta += tren[i] == 1
            ultimo = tren[i]
            i += ventana_ms // ms_por_muestra
        i += 1
    print(f"con ventana {ventana_ms}ms: cuenta={cuenta}")
    return cuenta


debounce(rebotes)
debounce(rebotes, ventana_ms=2)

06 · Analogía programador

Usuario impaciente

  1. 1
    Rebote = doble-click.

    El usuario clickea 5 veces el botón que tarda: se atiende el primero, se ignoran los siguientes 500 ms.

  2. 2
    Pull = default.

    Valor cuando nadie escribe: como un parámetro con default ante input ausente.

  3. 3
    Schmitt = histéresis.

    La misma del curso 4 (Tema 20): dos umbrales ignoran el tembleque del borde.

07 · Exploración

Laboratorio: presionar sin mentir

Presioná el botón virtual: genera un tren de rebotes realista. Compará cuenta cruda vs con debounce de 20 ms.

LABORATORIO 11

Presionómetro

Sin presiones aún

Último tren—
Flancos0
Cuenta total0
Presiones0

Presioná para generar rebotes.

Preguntas para explorar

  1. Presioná 3 veces en crudo. ¿Cuenta? Cambiá a debounce y presioná 3 más. ¿Cuenta?
  2. ¿Por qué el debounce da exactamente 1 por presión aunque el tren varíe?
  3. ¿Qué pasaría con ventana de 2 ms? (Ver código.)
Ver respuestas sugeridas
  1. Crudo: ~15–30 total (~5–10 por presión). Debounce: +3 exactos. Total = crudo + 3.
  2. Porque la ventana de 20 ms cubre todo el tren (≤ 15 ms): solo el primer flanco cuenta.
  3. Se cuelan rebotes tardíos: ventana menor que el tren. Ventana ≥ tren, siempre.

08 · Comprensión

Confusiones frecuentes

«Botón a Vcc, total es lo mismo»

No: a Vcc necesita pull-down, y sin pull hay corto al presionar. Convención: a masa + pull-up.

«Pull de 1 MΩ, total gasta menos»

Gasta menos pero es antena: 1 MΩ + ruido = flancos fantasma. 10k es el punto justo.

«Software arregla todo»

Para relojes manuales y contadores discretos no hay software: RC + Schmitt o latch. El micro no siempre está.

«Mi botón no rebota»

Todos rebotan (hasta los caros): si tu contador anda, es que algo ya filtra. Verificar con osciloscopio asusta.

09 · Práctica guiada

Ejercicios de botones

Ejercicio 1: RC correcto

Rebote medido de 15 ms. Elegí R y C con τ ≈ 15 ms y verificá el cruce de 1,5/3,5 V. ¿10k + 1,5 µF?

Ver solución razonada

τ = 15 ms ✓ (10k×1,5 µF): el capacitor promedia el tren y el HC14 entrega un flanco. E12: 1,5 µF existe ✓.

Ejercicio 2: latch SR

Conmutador SPDT + 2 NAND cruzadas. Dibujá set/reset y explicá por qué los rebotes no afectan.

Ver solución

El primer contacto traba Q; rebotes del mismo lado no cambian nada; solo el lado opuesto conmuta. Debounce perfecto sin RC.

Ejercicio 3: medir tu botón

Osciloscopio en el botón con pull-up: presioná 5 veces. ¿Duración del tren? ¿Flancos por presión?

Ver solución

Típico 5–20 ms y 5–15 flancos: cada botón tiene su firma. Diseñar la ventana con la medida, no con el datasheet.

10 · Síntesis

Ideas para recordar

  • Botón a masa + pull-up 10k (0,5 mA).
  • Rebote 5–50 ms: si cuenta flancos, filtra.
  • RC (10k + 1 µF) + HC14, latch SR, o software 20–50 ms.
  • Ventana ≥ tren medido.
  • Todos los botones rebotan: el tuyo también.

Entradas domesticadas. Ahora los chips que las leen: en el próximo tema, 74HCxx en mesa.