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.