3.11. Uklanjanje podrhtavanja (debouncing)

Sklopka se crta kao savršeni otvoren-ili-zatvoren kontakt, ali kontakti stvarne sklopke ne prelaze čisto između tih dvaju stanja. Oni podrhtavaju – uspostavljaju i prekidaju električni kontakt mnogo puta unutar nekoliko milisekundi prije nego što se smire. GPIO ulaz koji čita pin to vidi kao niz rubova; nepažljiva petlja prozivanja broji nekoliko „pritisaka” za jedan stvarni pritisak, a rukovatelj prekida izvršava se nekoliko puta po stvarnom pritisku.

Idealizirani prikaz na osciloskopu koji pokazuje ulazni signal sklopke. Signal počinje visoko (otvorena sklopka), pada nisko, nekoliko se puta odbija naprijed-natrag unutar nekoliko milisekundi, a zatim se smiri na nisko (zatvorena sklopka).

Sklopka koja podrhtava proizvodi niz brzih prijelaza prije nego što se smiri.

Uklanjanje podrhtavanja je postupak filtriranja podrhtavanja tako da se svaki fizički pritisak zabilježi kao jedan događaj. Tomu pristupaju dva rješenja – softverski (vremensko pravilo u ugrađenom programu (firmware)) ili hardverski (mali filtar na žici). Ona se međusobno ne isključuju.

3.11.1. Softversko uklanjanje podrhtavanja

Zamisao je zapamtiti kada se ulaz posljednji put promijenio i odbaciti daljnje promjene unutar kratkog prozora od te vremenske oznake. Podrhtavanje kontakta obično traje manje od 10 ms; stvarni pritisak traje 50 – 100 ms; prozor od 30 – 50 ms hvata sva podrhtavanja bez blokiranja stvarnih pritisaka.

U petlji prozivanja pročitajte pin, usporedite ga s posljednjom stabilnom vrijednošću i prihvatite promjenu tek nakon što istekne prozor za uklanjanje podrhtavanja:

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)

Za čitanja vođena prekidima primijenite isto vremensko pravilo unutar rukovatelja, a zatim stvarni pritisak predajte glavnom kontekstu putem micropython.schedule() (vidi GPIO ulaz):

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 filtrira podrhtavanja prema vremenskoj oznaci i stavlja povratni poziv u red; handle_press izvršava se natrag u glavnom kontekstu, gdje su dodjela memorije i spori U/I sigurni.

3.11.2. Hardversko uklanjanje podrhtavanja

Hardversko uklanjanje podrhtavanja filtrira podrhtavanje električki, prije nego što uopće dosegne pin. Standardni alat je kondenzator.

Kondenzator je komponenta s dva priključka koja pohranjuje električni naboj. Fizički, to su dvije vodljive ploče postavljene na malu udaljenost jedna od druge, odvojene izolatorom (dielektrikom).

Kondenzator nacrtan kao dvije usporedne vodoravne ploče s dielektrikom (izolatorom) između njih. Po jedan vod povezuje svaku ploču s vanjskim priključkom -- A na vrhu, B na dnu. Jednaki i suprotni naboji +Q i -Q nakupljaju se na dvjema pločama kada se napon V primijeni na priključke.

Pločasti kondenzator: dva vodiča odvojena izolacijskim slojem.

Primjena napona na njegove priključke tjera jednake i suprotne naboje na dvije ploče; odnos glasi

Q = C × V

gdje je Q pohranjeni naboj (kuloni), V je napon na kondenzatoru, a C je njegov kapacitet (faradi). Kapacitet je određen konstrukcijom uređaja; veći kapacitet znači više pohranjenog naboja pri istom naponu.

Posljedica: kondenzator ne može trenutno promijeniti svoj napon. Naboj koji teče unutra ili van mora proći kroz bilo koji otpor na putu, a taj otpor određuje koliko se brzo napon može mijenjati.

3.11.2.1. RC vremenska konstanta

Punjenje kondenzatora kroz otpornik proizvodi glatki eksponencijalni porast prema naponu napajanja, a ne skok. Karakteristično vrijeme tog porasta je RC vremenska konstanta:

τ = R × C

Nakon jednog τ, kondenzator je dosegnuo oko 63 % napona napajanja. Nakon 5 τ, prelazi 99 % – u praksi „potpuno napunjen”.

Graf koji pokazuje porast napona kondenzatora uzduž eksponencijalne krivulje od 0 V prema naponu napajanja. Vrijeme τ = RC označeno je na osi x na mjestu gdje krivulja dosegne 63 % napona napajanja.

Kondenzator se puni uzduž eksponencijalne krivulje. τ = RC je vrijeme potrebno da se dosegne 63 % konačnog napona.

Pražnjenje kroz otpornik slijedi zrcalnu sliku: napon eksponencijalno pada od svoje početne vrijednosti prema nuli, padajući na 37 % početnog napona nakon jednog τ, te na ispod 1 % nakon 5 τ.

Graf koji pokazuje pad napona kondenzatora uzduž eksponencijalne krivulje od Vmax prema 0 V. Vrijeme τ = RC označeno je na osi x na mjestu gdje krivulja padne na 37 % početnog napona.

Kondenzator se prazni uzduž eksponencijalnog opadanja. τ = RC je vrijeme potrebno da padne na 37 % početnog napona.

3.11.2.2. Sklop za uklanjanje podrhtavanja

Kondenzator između ulaznog pina i mase, napajan kroz serijski otpornik, tvori niskopropusni filtar. Brzi šiljci nemaju vremena napuniti ili isprazniti kondenzator kroz taj otpornik; pin ostaje blizu napona na kojem je bio prije šiljka. Spore promjene – namjeran pritisak – pune ili prazne kondenzator i očitanje ih prati.

R1 povlači visoku stranu sklopke prema Vcc, proizvodeći sirovi signal sklopke koji podrhtava. R2 i C zatim niskopropusno filtriraju taj signal u pin:

Ulaz sklopke s hardverskim uklanjanjem podrhtavanja. Vcc se povezuje kroz pull-up otpornik od 10 kΩ prema čvorištu. To se čvorište povezuje s masom kroz sklopku na jednoj grani, te kroz serijski otpornik od 10 kΩ do Pina na drugoj grani. Kondenzator od 100 nF između Pina i mase dovršava niskopropusni filtar.

Hardversko uklanjanje podrhtavanja: R2 i C niskopropusno filtriraju sirovi signal sklopke prije nego što dosegne pin.

Tipične vrijednosti: R1 = 10 (pull-up), R2 = 10 (serijski), C = 100 nF.

Kada je sklopka otvorena, struja teče Vcc → R1R2 → kondenzator (u seriji), puneći kondenzator na Vcc s τ_charge = (R1 + R2) × C = 2 ms.

Kada se sklopka zatvori, čvor sklopke spaja se na masu i kondenzator se prazni samo kroz R2 na tu masu s τ_discharge = R2 × C = 1 ms.

Oba ruba su RC-filtrirana. Budući da kondenzator sjedi na vlastitom čvoru, nizvodno od R2 od sklopke, čisto se njiše između Vcc (otvoreno) i 0 V (zatvoreno) – nikakva struja ne mora teći kroz R1 u stacionarnom stanju ni u jednom slučaju.

3.11.3. Odabir između njih

  • Softver je zadani izbor. Ne košta ništa u komponentama, prag se lako podešava, a radi na bilo kojem pinu koji CPU čita.

  • Hardver je vrijedan dijelova kada podrhtavanje dosegne nešto drugo osim CPU-ovog koda prozivanja – prekid koji se ne smije dvostruko aktivirati, hardverski brojač, periferiju bez vlastitog filtra.

Softversko i hardversko uklanjanje podrhtavanja također supostoje mirno: mali RC filtar potiskuje najgore šiljke, a softverski prozor za uklanjanje podrhtavanja pokriva ono što preostane.