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ă.

O reprezentare idealizată a unei urme de osciloscop care arată semnalul de intrare al unui comutator. Semnalul pornește la nivel ridicat (comutator deschis), scade la nivel coborât, oscilează înainte și înapoi de câteva ori într-un interval de câteva milisecunde, apoi se stabilizează la nivel coborât (comutator închis).

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 reprezentat ca două plăci orizontale paralele cu un dielectric (izolator) între ele. Câte un conductor conectează fiecare placă la un terminal extern -- A în partea de sus, B în partea de jos. Sarcini egale și opuse +Q și -Q se acumulează pe cele două plăci atunci când o tensiune V este aplicată la borne.

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 grafic care arată tensiunea unui condensator crescând de-a lungul unei curbe exponențiale de la 0 V către șina de alimentare. Timpul τ = RC este marcat pe axa x în punctul în care curba atinge 63 % din tensiunea de alimentare.

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 grafic care arată tensiunea unui condensator scăzând de-a lungul unei curbe exponențiale de la Vmax către 0 V. Timpul τ = RC este marcat pe axa x în punctul în care curba coboară la 37 % din tensiunea de pornire.

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:

O intrare de comutator cu eliminare hardware a oscilațiilor. Vcc se conectează printr-un rezistor de ridicare (pull-up) de 10 kΩ până la o joncțiune. Acea joncțiune se conectează la masă prin comutator pe o ramură și printr-un rezistor în serie de 10 kΩ la Pin pe cealaltă ramură. Un condensator de 100 nF între Pin și masă completează filtrul trece-jos.

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 (pull-up), R2 = 10 (serie), C = 100 nF.

Când comutatorul este deschis, curentul circulă Vcc → R1R2 → 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.