3.11. Подавление дребезга¶
Переключатель изображают как идеальный замкнуто-разомкнутый контакт, но контакты реального переключателя не переходят между двумя состояниями чисто. Они дребезжат – замыкают и размыкают электрический контакт множество раз в течение нескольких миллисекунд, прежде чем установиться. GPIO-вход, считывающий вывод, видит это как пачку фронтов; неаккуратный цикл опроса насчитывает несколько «нажатий» на одно реальное нажатие, а обработчик прерывания срабатывает несколько раз на каждое фактическое нажатие.
Дребезжащий переключатель создаёт пачку быстрых переходов перед тем, как установиться.¶
Подавление дребезга – это практика фильтрации дребезга так, чтобы каждое физическое нажатие регистрировалось как одно событие. Эту задачу решают два подхода – программный (правило тайминга в прошивке) или аппаратный (небольшой фильтр на проводе). Они не являются взаимоисключающими.
3.11.1. Программное подавление дребезга¶
Идея состоит в том, чтобы запоминать, когда вход последний раз менялся, и отклонять дальнейшие изменения в течение короткого окна после этой метки времени. Дребезг контактов обычно длится менее 10 мс; реальное нажатие занимает 50 – 100 мс; окно в 30 – 50 мс улавливает весь дребезг, не блокируя реальные нажатия.
В цикле опроса считайте вывод, сравните с последним стабильным значением и принимайте изменение только после того, как истекло окно подавления дребезга:
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)
Для считывания по прерыванию примените то же правило тайминга внутри обработчика, а затем передайте реальное нажатие в основной контекст через micropython.schedule() (см. 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)
ISR фильтрует дребезг по метке времени и ставит функцию обратного вызова в очередь; handle_press выполняется уже в основном контексте, где выделение памяти и медленный ввод-вывод безопасны.
3.11.2. Аппаратное подавление дребезга¶
Аппаратное подавление дребезга фильтрует дребезг электрически, ещё до того, как он достигнет вывода. Стандартный инструмент для этого – конденсатор.
Конденсатор – это двухполюсный компонент, который накапливает электрический заряд. Физически это две проводящие пластины, расположенные на небольшом расстоянии друг от друга и разделённые изолятором (диэлектриком).
Плоский конденсатор: два проводника, разделённые изолирующим слоем.¶
Приложение напряжения к его терминалам перемещает равные и противоположные заряды на две пластины; зависимость такова:
Q = C × V
где Q – накопленный заряд (кулоны), V – напряжение на конденсаторе, а C – его ёмкость (фарады). Ёмкость определяется конструкцией устройства; большая ёмкость означает больший накопленный заряд при том же напряжении.
Следствие: конденсатор не может мгновенно изменить своё напряжение. Заряд, втекающий или вытекающий, должен пройти через любое сопротивление на своём пути, и это сопротивление задаёт, насколько быстро может меняться напряжение.
3.11.2.1. Постоянная времени RC¶
Зарядка конденсатора через резистор даёт плавный экспоненциальный рост к напряжению питания, а не скачок. Характеристическое время этого роста – постоянная времени RC:
τ = R × C
По истечении одного τ конденсатор достигает примерно 63 % напряжения питания. После 5 τ он заряжен более чем на 99 % – «полностью заряжен» для практических целей.
Конденсатор заряжается по экспоненциальной кривой. τ = RC – это время достижения 63 % конечного напряжения.¶
Разрядка через резистор повторяет зеркальную картину: напряжение экспоненциально падает от своего начального значения к нулю, снижаясь до 37 % начального напряжения после одного τ и до менее 1 % после 5 τ.
Конденсатор разряжается по экспоненциальному спаду. τ = RC – это время падения до 37 % начального напряжения.¶
3.11.2.2. Схема подавления дребезга¶
Конденсатор между входным выводом и землёй, подключённый через последовательный резистор, образует фильтр нижних частот. Быстрые всплески не успевают зарядить или разрядить конденсатор через этот резистор; вывод остаётся близким к тому напряжению, на котором он был до всплеска. Медленные изменения – осознанное нажатие – заряжают или разряжают конденсатор, и считываемое значение следует за ними.
R1 подтягивает верхнюю сторону переключателя к Vcc, формируя необработанный сигнал переключателя, который дребезжит. R2 и C затем фильтруют этот сигнал по нижним частотам на пути к выводу:
Аппаратное подавление дребезга: R2 и C фильтруют необработанный сигнал переключателя по нижним частотам перед тем, как он достигнет вывода.¶
Типовые значения: R1 = 10 kΩ (подтягивающий), R2 = 10 kΩ (последовательный), C = 100 nF.
Когда переключатель разомкнут, ток течёт по пути Vcc → R1 → R2 → конденсатор (последовательно), заряжая конденсатор до Vcc с τ_charge = (R1 + R2) × C = 2 ms.
Когда переключатель замыкается, узел переключателя фиксируется на земле, и конденсатор разряжается через один лишь R2 на эту землю с τ_discharge = R2 × C = 1 ms.
Оба фронта фильтруются RC-цепью. Поскольку конденсатор находится на собственном узле, ниже по цепи от R2 относительно переключателя, он чисто переключается между Vcc (разомкнуто) и 0 В (замкнуто) – в установившемся режиме ни в одном из случаев через R1 не должен течь ток.
3.11.3. Выбор между ними¶
Программный способ используется по умолчанию. Он ничего не стоит в компонентах, порог легко настраивается, и он работает на любом выводе, который считывает CPU.
Аппаратный способ оправдывает затраты на детали, когда дребезг достигает чего-то иного, нежели код опроса CPU – прерывания, которое не должно срабатывать дважды, аппаратного счётчика, периферийного устройства без собственного фильтра.
Программное и аппаратное подавление дребезга также мирно сосуществуют: небольшой RC-фильтр подавляет самые сильные всплески, а программное окно подавления дребезга охватывает то, что осталось.