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