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.

Wyidealizowany przebieg na oscyloskopie pokazujący sygnał wejściowy z przełącznika. Sygnał zaczyna się wysoko (przełącznik otwarty), spada nisko, kilka razy odbija się tam i z powrotem w ciągu kilku milisekund, po czym ustala się nisko (przełącznik zamknięty).

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

Kondensator narysowany jako dwie równoległe poziome płytki z dielektrykiem (izolatorem) między nimi. Wyprowadzenie łączy każdą płytkę z zewnętrznym zaciskiem -- A na górze, B na dole. Równe i przeciwne ładunki +Q i -Q gromadzą się na obu płytkach, gdy do zacisków przyłoży się napięcie V.

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

Wykres pokazujący wzrost napięcia kondensatora wzdłuż krzywej wykładniczej od 0 V w kierunku szyny zasilania. Czas τ = RC jest zaznaczony na osi x w miejscu, gdzie krzywa osiąga 63 % napięcia zasilania.

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

Wykres pokazujący spadek napięcia kondensatora wzdłuż krzywej wykładniczej od Vmax w kierunku 0 V. Czas τ = RC jest zaznaczony na osi x w miejscu, gdzie krzywa spada do 37 % napięcia początkowego.

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:

Wejście przełącznika ze sprzętową eliminacją drgań. Vcc łączy się przez rezystor podciągający 10 kΩ w dół do węzła. Ten węzeł łączy się z masą przez przełącznik w jednej gałęzi oraz przez rezystor szeregowy 10 kΩ do pinu w drugiej gałęzi. Kondensator 100 nF między pinem a masą dopełnia filtr dolnoprzepustowy.

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.