Антидребезг: как победить дрожание контактов
Решаем коварную проблему, из-за которой одно нажатие считается десятком.
Дребезг (debounce) — кратковременное дрожание контактов кнопки в момент нажатия: вместо одного чистого перехода вход несколько раз скачет между 0 и 1.
Откуда берётся дребезг
Кнопка — это две металлические пластины. Когда они соприкасаются, происходит микроскопический «отскок»: контакт замыкается и размыкается несколько раз за пару миллисекунд, прежде чем установится стабильно. Глаз этого не видит, но быстрый микроконтроллер успевает прочитать каждый скачок и решит, что кнопку нажали много раз.
Программный антидребезг по времени
Идея проста: зафиксировав изменение, игнорируем новые изменения некоторое время (обычно 20–50 мс), пока контакты не успокоятся. Логику задержки можно проверить на обычном Python — здесь только арифметика и условия, без модуля machine:
# Симуляция: серия «грязных» показаний кнопки с временными метками (мс)
readings = [(0, 1), (101, 0), (103, 1), (104, 0), (106, 0), (108, 0)]
# (время_мс, уровень)
DEBOUNCE = 20 # мс
stable = 1
last_change = -1000
presses = 0
for t, level in readings:
if level != stable and (t - last_change) > DEBOUNCE:
stable = level
last_change = t
if stable == 0: # нажатие = переход в 0
presses += 1
print("Засчитано нажатий:", presses)Вывод:
Засчитано нажатий: 1
Грязная серия скачков на отметке ~100 мс засчиталась как одно нажатие, потому что повторные изменения внутри 20 мс игнорировались.
Тот же приём на плате
from machine import Pin
import time
button = Pin(15, Pin.IN, Pin.PULL_UP)
last = button.value()
last_change = time.ticks_ms()
while True:
now = button.value()
t = time.ticks_ms()
if now != last and time.ticks_diff(t, last_change) > 20:
last = now
last_change = t
if now == 0:
print("Нажато!")
time.sleep_ms(2)time.ticks_ms() и time.ticks_diff() — специальные функции MicroPython для измерения интервалов, устойчивые к переполнению счётчика.
Как работает под капотом
Внутренний счётчик миллисекунд тикает непрерывно. Мы запоминаем момент последнего принятого изменения и сравниваем с ним каждое новое. ticks_diff корректно считает разницу, даже когда счётчик переполнился и «обнулился». Аппаратная альтернатива — RC-фильтр (резистор и конденсатор сглаживают скачки), но программный способ не требует деталей.
Частые ошибки
- Игнорировать дребезг. Меню будет «проскакивать» пункты, счётчики накручиваться.
- Брать слишком большое окно. 300 мс — и быстрые двойные нажатия теряются. 20–50 мс обычно оптимально.
- Использовать
time.time()вместоticks_ms(). Для коротких интервалов на плате правильнее тики.
Итог
- Дребезг — дрожание контактов, превращающее одно нажатие во множество.
- Программный антидребезг игнорирует изменения короче порога (20–50 мс).
- На плате используют
ticks_ms()иticks_diff()для надёжного измерения времени. - Отслеживайте именно фронт (переход), а не уровень.