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-фільтр придушує найгірші імпульси, а програмне вікно усунення брязкоту покриває решту.