3.11. Eliminacja drgań styków#

Przełącznik rysuje się jako idealny styk otwarty lub zamknięty, ale styki rzeczywistego przełącznika nie przeskakują czysto między tymi dwoma stanami. Drgają – zwierają i rozwierają kontakt elektryczny wiele razy w ciągu kilku milisekund, zanim się ustabilizują. Wejście GPIO odczytujące pin widzi to jako serię zboczy; nieostrożna pętla odpytująca zlicza kilka „naciśnięć” dla jednego rzeczywistego naciśnięcia, a obsługa przerwania uruchamia się kilka razy na jedno faktyczne naciśnięcie.

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).

Drgający przełącznik wytwarza serię szybkich przejść, zanim się ustabilizuje.#

Eliminacja drgań styków to praktyka filtrowania drgań tak, aby każde fizyczne naciśnięcie rejestrowało się jako pojedyncze zdarzenie. Rozwiązują to dwa podejścia – programowe (reguła czasowa w oprogramowaniu układowym) lub sprzętowe (mały filtr na przewodzie). Nie wykluczają się one wzajemnie.

3.11.1. Programowa eliminacja drgań#

Idea polega na zapamiętaniu, kiedy wejście ostatnio się zmieniło, i odrzucaniu dalszych zmian w krótkim oknie czasowym od tego znacznika czasu. Drgania styków trwają zwykle poniżej 10 ms; rzeczywiste naciśnięcie zajmuje 50 – 100 ms; okno 30 – 50 ms wychwytuje wszystkie drgania, nie blokując rzeczywistych naciśnięć.

W pętli odpytującej odczytaj pin, porównaj go z ostatnią stabilną wartością i akceptuj zmianę dopiero po upływie okna eliminacji drgań:

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)

W przypadku odczytów sterowanych przerwaniami zastosuj tę samą regułę czasową wewnątrz obsługi, a następnie przekaż rzeczywiste naciśnięcie do głównego kontekstu za pomocą micropython.schedule() (zobacz Wejście GPIO):

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 filtruje drgania na podstawie znacznika czasu i kolejkuje wywołanie zwrotne; handle_press działa z powrotem w głównym kontekście, gdzie alokacja i wolne operacje I/O są bezpieczne.

3.11.2. Sprzętowa eliminacja drgań#

Sprzętowa eliminacja drgań filtruje drgania elektrycznie, zanim w ogóle dotrą one do pinu. Standardowym narzędziem jest kondensator.

Kondensator to dwuzaciskowy element przechowujący ładunek elektryczny. Fizycznie są to dwie przewodzące płytki utrzymywane w niewielkiej odległości od siebie, oddzielone izolatorem (dielektrykiem).

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.

Kondensator płaski: dwa przewodniki rozdzielone warstwą izolacyjną.#

Przyłożenie napięcia do jego zacisków wymusza powstanie równych i przeciwnych ładunków na obu płytkach; zależność ta wynosi

Q = C × V

gdzie Q to zgromadzony ładunek (kulomby), V to napięcie na kondensatorze, a C to jego pojemność (farady). Pojemność jest ustalona przez konstrukcję elementu; większa pojemność oznacza więcej ładunku zgromadzonego przy tym samym napięciu.

Konsekwencja: kondensator nie może zmienić swojego napięcia natychmiast. Ładunek wpływający lub wypływający musi przejść przez jakąkolwiek rezystancję znajdującą się na drodze, a ta rezystancja określa, jak szybko może zmieniać się napięcie.

3.11.2.1. Stała czasowa RC#

Ładowanie kondensatora przez rezystor wytwarza gładki wykładniczy wzrost w kierunku napięcia zasilania, a nie skok. Charakterystycznym czasem tego wzrostu jest stała czasowa RC:

τ = R × C

Po jednym τ kondensator osiąga około 63 % napięcia zasilania. Po 5 τ przekracza 99 % – w praktyce jest „w pełni naładowany”.

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.

Kondensator ładuje się wzdłuż krzywej wykładniczej. τ = RC to czas potrzebny do osiągnięcia 63 % napięcia końcowego.#

Rozładowanie przez rezystor przebiega jak lustrzane odbicie: napięcie spada wykładniczo od swojej wartości początkowej w kierunku zera, opadając do 37 % napięcia początkowego po jednym τ i poniżej 1 % po 5 τ.

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.

Kondensator rozładowuje się wzdłuż wykładniczego zaniku. τ = RC to czas potrzebny do spadku do 37 % napięcia początkowego.#

3.11.2.2. Układ eliminacji drgań#

Kondensator między pinem wejściowym a masą, zasilany przez rezystor szeregowy, tworzy filtr dolnoprzepustowy. Szybkie impulsy nie mają czasu, by naładować lub rozładować kondensator przez ten rezystor; pin pozostaje bliski napięciu, na którym był przed impulsem. Powolne zmiany – celowe naciśnięcie – ładują lub rozładowują kondensator, a odczyt podąża za nimi.

R1 podciąga wysoką stronę przełącznika do Vcc, wytwarzając surowy sygnał przełącznika, który drga. R2 i C następnie filtrują dolnoprzepustowo ten sygnał do pinu:

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.

Sprzętowa eliminacja drgań: R2 i C filtrują dolnoprzepustowo surowy sygnał przełącznika, zanim dotrze on do pinu.#

Typowe wartości: R1 = 10 (podciąganie), R2 = 10 (szeregowy), C = 100 nF.

Gdy przełącznik jest otwarty, prąd płynie Vcc → R1R2 → kondensator (szeregowo), ładując kondensator do Vcc ze stałą τ_charge = (R1 + R2) × C = 2 ms.

Gdy przełącznik się zamyka, węzeł przełącznika zostaje zwarty do masy, a kondensator rozładowuje się przez sam R2 do tej masy ze stałą τ_discharge = R2 × C = 1 ms.

Oba zbocza są filtrowane RC. Ponieważ kondensator znajduje się na własnym węźle, za R2 od strony przełącznika, przełącza się on czysto między Vcc (otwarty) a 0 V (zamknięty) – w stanie ustalonym w żadnym przypadku przez R1 nie musi płynąć prąd.

3.11.3. Wybór między nimi#

  • Rozwiązanie programowe jest domyślne. Nie kosztuje nic w komponentach, próg łatwo dostroić, a działa na każdym pinie, który odczytuje CPU.

  • Rozwiązanie sprzętowe jest warte poniesienia kosztu części, gdy drgania docierają do czegoś innego niż kod odpytujący CPU – do przerwania, które nie może zadziałać podwójnie, do sprzętowego licznika, do urządzenia peryferyjnego bez własnego filtra.

Programowa i sprzętowa eliminacja drgań również dobrze współistnieją: mały filtr RC tłumi najgorsze impulsy, a programowe okno eliminacji drgań pokrywa to, co pozostało.