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.
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).
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”.
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 τ.
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:
Hardversko uklanjanje podrhtavanja: R2 i C niskopropusno filtriraju sirovi signal sklopke prije nego što dosegne pin.¶
Tipične vrijednosti: R1 = 10 kΩ (pull-up), R2 = 10 kΩ (serijski), C = 100 nF.
Kada je sklopka otvorena, struja teče Vcc → R1 → R2 → 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.