3.11. Värähtelyn poisto

Kytkin piirretään täydellisenä auki- tai kiinni-koskettimena, mutta todellisen kytkimen koskettimet eivät napsahda puhtaasti näiden kahden tilan välillä. Ne värähtelevät – muodostavat ja katkaisevat sähkökontaktin useita kertoja muutaman millisekunnin aikana ennen vakautumistaan. Nastaa lukeva GPIO-tulo näkee tämän reunojen sarjana; huolimaton kyselysilmukka laskee useita ”painalluksia” yhdelle todelliselle painallukselle, ja keskeytyskäsittelijä suoritetaan useita kertoja yhtä todellista painallusta kohti.

Idealisoitu oskilloskooppikuvaaja, joka näyttää kytkimen tulo- signaalin. Signaali alkaa korkeana (kytkin auki), putoaa matalaksi, pomppii edestakaisin useita kertoja muutaman millisekunnin aikana ja vakautuu sitten matalaksi (kytkin kiinni).

Värähtelevä kytkin tuottaa nopeiden siirtymien sarjan ennen vakautumistaan.

Värähtelyn poisto on käytäntö, jossa värähtely suodatetaan niin, että jokainen fyysinen painallus rekisteröityy yhtenä tapahtumana. Tähän on kaksi ratkaisua – ohjelmistopohjainen (ajoitussääntö laiteohjelmistossa) tai laitteistopohjainen (pieni suodatin johdossa). Ne eivät sulje toisiaan pois.

3.11.1. Ohjelmistopohjainen värähtelyn poisto

Ideana on muistaa, milloin tulo viimeksi muuttui, ja hylätä lisämuutokset lyhyen ikkunan sisällä tästä aikaleimasta. Koskettimien värähtely kestää tyypillisesti alle 10 ms; todellinen painallus kestää 50 – 100 ms; 30 – 50 ms:n ikkuna nappaa kaikki värähtelyt estämättä todellisia painalluksia.

Kyselysilmukassa lue nasta, vertaa sitä viimeiseen vakaaseen arvoon ja hyväksy muutos vasta, kun värähtelyn poiston ikkuna on kulunut:

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)

Keskeytyspohjaisissa luennoissa sovella samaa ajoitussääntöä käsittelijän sisällä ja siirrä sitten todellinen painallus pääkontekstiin micropython.schedule()-funktion kautta (katso GPIO-tulo):

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 suodattaa värähtelyt aikaleiman perusteella ja asettaa takaisinkutsun jonoon; handle_press suoritetaan takaisin pääkontekstissa, jossa muistinvaraus ja hidas I/O ovat turvallisia.

3.11.2. Laitteistopohjainen värähtelyn poisto

Laitteistopohjainen värähtelyn poisto suodattaa värähtelyn sähköisesti, ennen kuin se edes saavuttaa nastan. Vakiotyökalu on kondensaattori.

Kondensaattori on kaksinapainen komponentti, joka varastoi sähkövarausta. Fyysisesti se koostuu kahdesta sähköä johtavasta levystä, joita pidetään lyhyen matkan päässä toisistaan ja jotka on erotettu eristeellä (dielektrikum).

Kondensaattori piirrettynä kahtena vaakasuorana, rinnakkaisena levynä, joiden välissä on eriste (dielektrikum). Johdin yhdistää kunkin levyn ulkoiseen liittimeen -- A päällä, B pohjassa. Yhtä suuret ja vastakkaiset varaukset +Q ja -Q kertyvät kahteen levyyn, kun liittimien yli kytketään jännite V.

Levykondensaattori: kaksi johdinta, jotka on erotettu eristekerroksella.

Liittimien yli kytketty jännite ajaa yhtä suuret ja vastakkaiset varaukset kahteen levyyn; suhde on

Q = C × V

jossa Q on varastoitu varaus (coulombeja), V on kondensaattorin yli oleva jännite ja C on sen kapasitanssi (faradeja). Kapasitanssi määräytyy laitteen rakenteen mukaan; suurempi kapasitanssi tarkoittaa enemmän varastoitua varausta samalla jännitteellä.

Seuraus: kondensaattori ei voi muuttaa jännitettään hetkessä. Sisään tai ulos virtaavan varauksen on kuljettava reitillä olevan vastuksen läpi, ja tuo vastus määrää, kuinka nopeasti jännite voi muuttua.

3.11.2.1. RC-aikavakio

Kondensaattorin lataaminen vastuksen läpi tuottaa tasaisen eksponentiaalisen nousun kohti syöttöjännitettä, ei askelmaista nousua. Tämän nousun tunnusomainen aika on RC-aikavakio:

τ = R × C

Yhden τ:n jälkeen kondensaattori on saavuttanut noin 63 % syöttöjännitteestä. 5 τ:n jälkeen se on yli 99 % – käytännössä ”täyteen ladattu”.

Kuvaaja, joka näyttää kondensaattorin jännitteen nousevan eksponentiaalista käyrää pitkin arvosta 0 V kohti syöttöjännitettä. Aika τ = RC on merkitty x-akselille kohtaan, jossa käyrä saavuttaa 63 % syöttöjännitteestä.

Kondensaattori latautuu eksponentiaalista käyrää pitkin. τ = RC on aika, jossa saavutetaan 63 % loppujännitteestä.

Purkautuminen vastuksen läpi noudattaa peilikuvaa: jännite laskee eksponentiaalisesti alkuarvostaan kohti nollaa, pudoten 37 %:iin alkujännitteestä yhden τ:n jälkeen ja alle 1 %:iin 5 τ:n jälkeen.

Kuvaaja, joka näyttää kondensaattorin jännitteen laskevan eksponentiaalista käyrää pitkin arvosta Vmax kohti 0 V:tä. Aika τ = RC on merkitty x-akselille kohtaan, jossa käyrä putoaa 37 %:iin alkujännitteestä.

Kondensaattori purkautuu eksponentiaalista vaimenemista pitkin. τ = RC on aika, jossa pudotaan 37 %:iin alkujännitteestä.

3.11.2.2. Värähtelyn poiston kytkentä

Tulonastan ja maan väliin sijoitettu kondensaattori, jota syötetään sarjavastuksen kautta, muodostaa alipäästösuodattimen. Nopeilla piikeillä ei ole aikaa ladata tai purkaa kondensaattoria tuon vastuksen läpi; nasta pysyy lähellä sitä jännitettä, jossa se oli ennen piikkiä. Hitaat muutokset – tarkoituksellinen painallus – lataavat tai purkavat kondensaattoria, ja lukema seuraa.

R1 nostaa kytkimen yläpuolen Vcc:hen ja tuottaa raa’an kytkinsignaalin, joka värähtelee. R2 ja C alipäästösuodattavat tuon signaalin nastaan:

Kytkimen tulo laitteistopohjaisella värähtelyn poistolla. Vcc kytkeytyy 10 kΩ:n ylösvetovastuksen kautta liitoskohtaan. Tuo liitoskohta kytkeytyy maahan kytkimen kautta yhdessä haarassa ja 10 kΩ:n sarjavastuksen kautta nastaan toisessa haarassa. 100 nF:n kondensaattori nastan ja maan välillä täydentää alipäästösuodattimen.

Laitteistopohjainen värähtelyn poisto: R2 ja C alipäästösuodattavat raa’an kytkinsignaalin ennen kuin se saavuttaa nastan.

Tyypilliset arvot: R1 = 10 (ylösveto), R2 = 10 (sarja), C = 100 nF.

Kun kytkin on auki, virta kulkee Vcc → R1R2 → kondensaattori (sarjassa) ladaten kondensaattorin Vcc:hen aikavakiolla τ_charge = (R1 + R2) × C = 2 ms.

Kun kytkin sulkeutuu, kytkinsolmu kiinnittyy maahan ja kondensaattori purkautuu pelkän R2:n kautta tuohon maahan aikavakiolla τ_discharge = R2 × C = 1 ms.

Molemmat reunat ovat RC-suodatettuja. Koska kondensaattori on omassa solmussaan, R2:n jälkeen kytkimestä katsottuna, se heilahtelee puhtaasti Vcc:n (auki) ja 0 V:n (kiinni) välillä – kummassakaan tapauksessa virtaa ei tarvitse kulkea R1:n läpi tasapainotilassa.

3.11.3. Valinta niiden välillä

  • Ohjelmisto on oletus. Se ei maksa mitään komponentteina, kynnysarvoa on helppo virittää, ja se toimii millä tahansa nastalla, jonka CPU lukee.

  • Laitteisto on osien arvoinen, kun värähtely saavuttaa jotain muuta kuin CPU:n kyselykoodin – keskeytyksen, joka ei saa laueta kahdesti, laitteistopohjaisen laskurin tai oheislaitteen, jolla ei ole omaa suodatinta.

Ohjelmisto- ja laitteistopohjainen värähtelyn poisto elävät myös sovussa: pieni RC-suodatin vaimentaa pahimmat piikit, ja ohjelmistopohjainen värähtelyn poiston ikkuna kattaa loput.