3.11. Pergésmentesítés

A kapcsolót tökéletes nyitott vagy zárt érintkezőként szokás ábrázolni, ám egy valódi kapcsoló érintkezői nem váltanak tisztán a két állapot között. Pattognak – néhány ezredmásodpercen belül sokszor zárnak és bontanak elektromos kapcsolatot, mielőtt megállapodnának. A lábat olvasó GPIO bemenet ezt élek sorozataként látja; egy figyelmetlen lekérdező hurok egyetlen tényleges megnyomásra több „megnyomást” számol, egy megszakításkezelő pedig egyetlen megnyomásra többször fut le.

An idealised scope trace showing a switch input signal. The signal starts high (open switch), drops low, bounces back and forth several times within a few milliseconds, then settles low (closed switch).

Egy pattogó kapcsoló a megállapodás előtt gyors átmenetek sorozatát hozza létre.

A pergésmentesítés a pattogás kiszűrésének gyakorlata, hogy minden fizikai megnyomás egyetlen eseményként jelenjen meg. Két megközelítés oldja meg ezt – a szoftveres (egy időzítési szabály a firmware-ben) vagy a hardveres (egy kis szűrő a vezetéken). Ezek nem zárják ki egymást.

3.11.1. Szoftveres pergésmentesítés

A lényeg, hogy megjegyezzük, mikor változott utoljára a bemenet, és elutasítsuk a további változásokat ezen időbélyeg rövid időablakán belül. Az érintkezőpattogás jellemzően 10 ms alatt tart; egy valódi megnyomás 50–100 ms-ig; egy 30–50 ms-os időablak minden pattogást elkap anélkül, hogy a valódi megnyomásokat blokkolná.

Egy lekérdező hurokban olvasd be a lábat, hasonlítsd össze az utolsó stabil értékkel, és csak akkor fogadj el változást, ha a pergésmentesítési időablak letelt:

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)

Megszakítás-vezérelt olvasásnál alkalmazd ugyanazt az időzítési szabályt a kezelőn belül, majd a valódi megnyomást add át a fő kontextusnak a micropython.schedule() segítségével (lásd GPIO bemenet):

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)

Az ISR időbélyeg alapján szűri a pattogásokat és sorba állítja a visszahívást; a handle_press a fő kontextusban fut, ahol a memóriafoglalás és a lassú I/O biztonságos.

3.11.2. Hardveres pergésmentesítés

A hardveres pergésmentesítés elektromosan szűri ki a pattogást, még mielőtt az elérné a lábat. A szokásos eszköz egy kondenzátor.

A kondenzátor egy kétkivezetéses alkatrész, amely elektromos töltést tárol. Fizikailag két, egymástól rövid távolságra tartott vezető lemez, amelyeket egy szigetelő (a dielektrikum) választ el.

A capacitor drawn as two parallel horizontal plates with a dielectric (insulator) between them. A lead connects each plate to an external terminal -- A on top, B on bottom. Equal and opposite charges +Q and -Q accumulate on the two plates when a voltage V is applied across the terminals.

Egy síkkondenzátor: két vezető, amelyeket egy szigetelő réteg választ el.

Ha feszültséget kapcsolunk a kapcsaira, az egyenlő nagyságú és ellentétes előjelű töltéseket hajt a két lemezre; az összefüggés a következő

Q = C × V

ahol a Q a tárolt töltés (coulombban), a V a kondenzátoron eső feszültség, a C pedig a kapacitása (faradban). A kapacitást az eszköz felépítése rögzíti; nagyobb kapacitás azonos feszültségen több tárolt töltést jelent.

A következmény: egy kondenzátor nem tudja azonnal megváltoztatni a feszültségét. A be- vagy kiáramló töltésnek át kell haladnia az útban lévő ellenálláson, és ez az ellenállás határozza meg, milyen gyorsan változhat a feszültség.

3.11.2.1. RC időállandó

Egy kondenzátor ellenálláson keresztüli feltöltése sima, exponenciális emelkedést eredményez a tápfeszültség felé, nem pedig ugrást. Ennek az emelkedésnek a jellemző ideje az RC időállandó:

τ = R × C

Egy τ elteltével a kondenzátor a tápfeszültség körülbelül 63 %-át éri el. 5 τ után már több mint 99 %-nál tart – gyakorlati szempontból „teljesen feltöltött”.

A graph showing a capacitor's voltage rising along an exponential curve from 0 V toward the supply rail. The time τ = RC is marked on the x-axis where the curve reaches 63 % of the supply voltage.

Egy kondenzátor exponenciális görbe mentén töltődik. A τ = RC az az idő, amely alatt eléri a végső feszültség 63 %-át.

Az ellenálláson keresztüli kisütés a tükörképet követi: a feszültség exponenciálisan csökken a kezdeti értékéről nulla felé, egy τ elteltével a kiindulási feszültség 37 %-ára, 5 τ után pedig 1 % alá esik.

A graph showing a capacitor's voltage falling along an exponential curve from Vmax toward 0 V. The time τ = RC is marked on the x-axis where the curve drops to 37 % of the starting voltage.

Egy kondenzátor exponenciális lecsengés mentén sül ki. A τ = RC az az idő, amely alatt a kiindulási feszültség 37 %-ára esik.

3.11.2.2. A pergésmentesítő áramkör

Egy bemeneti láb és a föld közé kötött, soros ellenálláson keresztül táplált kondenzátor aluláteresztő szűrőt alkot. A gyors tüskéknek nincs idejük feltölteni vagy kisütni a kondenzátort ezen az ellenálláson keresztül; a láb közel marad ahhoz a feszültséghez, amelyen a tüske előtt volt. A lassú változások – egy szándékos megnyomás – feltöltik vagy kisütik a kondenzátort, és az olvasott érték követi azt.

Az R1 felhúzza a kapcsoló magas oldalát Vcc-re, így egy nyers, pattogó kapcsolójelet hoz létre. Az R2 és a C ezután aluláteresztő szűrővel szűri ezt a jelet a lábra:

A switch input with hardware debouncing. Vcc connects through a 10 kΩ pull-up resistor down to a junction. That junction connects to ground through the switch on one branch, and through a 10 kΩ series resistor to the Pin on the other branch. A 100 nF capacitor between Pin and ground completes the low-pass filter.

Hardveres pergésmentesítés: az R2 és a C aluláteresztő szűrővel szűri a nyers kapcsolójelet, mielőtt az elérné a lábat.

Tipikus értékek: R1 = 10 (felhúzó), R2 = 10 (soros), C = 100 nF.

Amikor a kapcsoló nyitott, az áram a Vcc → R1R2 → kondenzátor (sorba kapcsolva) útvonalon folyik, és Vcc-re tölti a kondenzátort τ_charge = (R1 + R2) × C = 2 ms időállandóval.

Amikor a kapcsoló zár, a kapcsoló csomópontja a földre szorul, és a kondenzátor egyedül az R2 ellenálláson keresztül ürül erre a földre τ_discharge = R2 × C = 1 ms időállandóval.

Mindkét él RC-szűrt. Mivel a kondenzátor a saját csomópontján ül, az R2 után a kapcsoló felől nézve, tisztán leng a Vcc (nyitott) és 0 V (zárt) között – egyik esetben sem kell áramnak átfolynia az R1 ellenálláson állandósult állapotban.

3.11.3. Választás közöttük

  • A szoftveres az alapértelmezett. Nem kerül alkatrészbe, a küszöbérték könnyen hangolható, és bármelyik lábon működik, amelyet a CPU olvas.

  • A hardveres akkor éri meg az alkatrészeket, amikor a pattogás valami máshoz jut el, nem a CPU lekérdező kódjához – egy megszakításhoz, amely nem szabad, hogy kétszer lépjen működésbe, egy hardveres számlálóhoz, vagy egy saját szűrővel nem rendelkező perifériához.

A szoftveres és a hardveres pergésmentesítés békésen meg is fér egymás mellett: egy kis RC szűrő elnyomja a legrosszabb tüskéket, egy szoftveres pergésmentesítési időablak pedig lefedi a maradékot.