3.11. Eliminarea oscilațiilor de contact (debouncing)¶
Un comutator este reprezentat ca un contact perfect deschis sau închis, dar contactele unui comutator real nu comută curat între cele două stări. Ele vibrează – realizează și întrerup contactul electric de mai multe ori în câteva milisecunde înainte de a se stabiliza. O intrare GPIO care citește pinul vede acest lucru ca o serie de muchii; o buclă de interogare neglijentă numără mai multe „apăsări” pentru o singură apăsare reală, iar o rutină de tratare a întreruperilor rulează de mai multe ori la fiecare apăsare reală.
Un comutator care vibrează produce o serie de tranziții rapide înainte de a se stabiliza.¶
Eliminarea oscilațiilor de contact este practica de filtrare a vibrațiilor astfel încât fiecare apăsare fizică să fie înregistrată ca un singur eveniment. Două abordări rezolvă acest lucru – prin software (o regulă de temporizare în firmware) sau prin hardware (un mic filtru pe fir). Ele nu se exclud reciproc.
3.11.1. Eliminarea oscilațiilor prin software¶
Ideea este să rețineți momentul în care intrarea s-a schimbat ultima dată și să respingeți modificările ulterioare aflate într-o fereastră scurtă față de acea marcă temporală. Vibrația de contact durează de obicei sub 10 ms; o apăsare reală durează 50 – 100 ms; o fereastră de 30 – 50 ms surprinde toate vibrațiile fără a bloca apăsările reale.
Într-o buclă de interogare, citiți pinul, comparați-l cu ultima valoare stabilă și acceptați o modificare doar după ce a trecut fereastra de eliminare a oscilațiilor:
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)
Pentru citirile bazate pe întreruperi, aplicați aceeași regulă de temporizare în interiorul rutinei de tratare, apoi predați apăsarea reală contextului principal prin micropython.schedule() (consultați Intrare 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 filtrează vibrațiile după marca temporală și pune în coadă funcția de retroapelare (callback); handle_press rulează înapoi în contextul principal, unde alocarea și operațiile I/O lente sunt sigure.
3.11.2. Eliminarea oscilațiilor prin hardware¶
Eliminarea oscilațiilor prin hardware filtrează vibrațiile electric, înainte ca acestea să ajungă vreodată la pin. Instrumentul standard este un condensator.
Un condensator este o componentă cu două terminale care stochează sarcină electrică. Din punct de vedere fizic, este alcătuit din două plăci conductoare ținute la o distanță mică una de cealaltă, separate de un izolator (dielectricul).
Un condensator cu plăci paralele: doi conductori separați de un strat izolator.¶
Aplicarea unei tensiuni la bornele sale antrenează sarcini egale și opuse pe cele două plăci; relația este
Q = C × V
unde Q este sarcina stocată (coulombi), V este tensiunea la bornele condensatorului, iar C este capacitatea sa (farazi). Capacitatea este fixată de construcția dispozitivului; o capacitate mai mare înseamnă mai multă sarcină stocată la aceeași tensiune.
Consecința: un condensator nu își poate schimba tensiunea instantaneu. Sarcina care intră sau iese trebuie să treacă prin orice rezistență se află pe traseu, iar acea rezistență stabilește cât de rapid se poate modifica tensiunea.
3.11.2.1. Constanta de timp RC¶
Încărcarea unui condensator printr-un rezistor produce o creștere exponențială lină către tensiunea de alimentare, nu un salt. Timpul caracteristic al acestei creșteri este constanta de timp RC:
τ = R × C
După o singură constantă τ, condensatorul a atins aproximativ 63 % din tensiunea de alimentare. După 5 τ, depășește 99 % – „complet încărcat” în scopuri practice.
Un condensator se încarcă de-a lungul unei curbe exponențiale. τ = RC este timpul necesar pentru a atinge 63 % din tensiunea finală.¶
Descărcarea printr-un rezistor urmează imaginea în oglindă: tensiunea scade exponențial de la valoarea sa inițială către zero, coborând la 37 % din tensiunea de pornire după o singură constantă τ și la sub 1 % după 5 τ.
Un condensator se descarcă de-a lungul unei degradări exponențiale. τ = RC este timpul necesar pentru a coborî la 37 % din tensiunea de pornire.¶
3.11.2.2. Circuitul de eliminare a oscilațiilor¶
Un condensator între un pin de intrare și masă, alimentat printr-un rezistor în serie, formează un filtru trece-jos. Vârfurile rapide nu au timp să încarce sau să descarce condensatorul prin acel rezistor; pinul rămâne aproape de orice tensiune avea înainte de vârf. Modificările lente – o apăsare deliberată – încarcă sau descarcă condensatorul, iar citirea urmează.
R1 ridică partea ridicată a comutatorului la Vcc, producând un semnal brut de comutator care vibrează. R2 și C filtrează apoi acel semnal trece-jos către pin:
Eliminarea hardware a oscilațiilor: R2 și C filtrează trece-jos semnalul brut al comutatorului înainte ca acesta să ajungă la pin.¶
Valori tipice: R1 = 10 kΩ (pull-up), R2 = 10 kΩ (serie), C = 100 nF.
Când comutatorul este deschis, curentul circulă Vcc → R1 → R2 → condensator (în serie), încărcând condensatorul la Vcc cu τ_charge = (R1 + R2) × C = 2 ms.
Când comutatorul se închide, nodul comutatorului este forțat la masă, iar condensatorul se descarcă numai prin R2 către acea masă cu τ_discharge = R2 × C = 1 ms.
Ambele muchii sunt filtrate RC. Deoarece condensatorul se află pe propriul nod, în aval de R2 față de comutator, oscilează curat între Vcc (deschis) și 0 V (închis) – niciun curent nu trebuie să circule prin R1 în regim staționar în niciunul dintre cazuri.
3.11.3. Alegerea între ele¶
Software-ul este opțiunea implicită. Nu costă nimic în componente, pragul este ușor de reglat și funcționează pe orice pin pe care îl citește procesorul.
Hardware-ul merită componentele atunci când vibrația ajunge la altceva decât codul de interogare al procesorului – o întrerupere care nu trebuie să se declanșeze de două ori, un contor hardware, un periferic fără filtru propriu.
Eliminarea oscilațiilor prin software și prin hardware coexistă, de asemenea, în mod pașnic: un mic filtru RC suprimă cele mai grave vârfuri, iar o fereastră de eliminare a oscilațiilor prin software acoperă ceea ce rămâne.