3.11. Entprellen

Ein Schalter wird als perfekter Öffner-oder-Schließer-Kontakt gezeichnet, doch die Kontakte eines echten Schalters schalten nicht sauber zwischen den beiden Zuständen um. Sie prellen – sie stellen den elektrischen Kontakt innerhalb weniger Millisekunden viele Male her und trennen ihn wieder, bevor sie sich beruhigen. Ein GPIO-Eingang, der den Pin liest, sieht das als eine Folge von Flanken; eine unachtsame Polling-Schleife zählt mehrere „Tastendrücke“ für einen einzigen echten Druck, und ein Interrupt-Handler läuft mehrmals pro tatsächlichem Druck.

Eine idealisierte Oszilloskop-Aufzeichnung eines Schaltereingangssignals. Das Signal beginnt hoch (offener Schalter), fällt ab, prellt innerhalb weniger Millisekunden mehrmals hin und her und beruhigt sich dann auf niedrigem Pegel (geschlossener Schalter).

Ein prellender Schalter erzeugt vor dem Beruhigen eine Folge schneller Übergänge.

Entprellen ist die Praxis, das Prellen herauszufiltern, sodass jeder physische Tastendruck als einzelnes Ereignis registriert wird. Dafür gibt es zwei Ansätze – Software (eine Zeitregel in der Firmware) oder Hardware (ein kleiner Filter auf der Leitung). Sie schließen einander nicht aus.

3.11.1. Software-Entprellen

Die Idee ist, sich zu merken, wann sich der Eingang zuletzt geändert hat, und weitere Änderungen innerhalb eines kurzen Zeitfensters nach diesem Zeitstempel zu verwerfen. Kontaktprellen dauert typischerweise unter 10 ms; ein echter Tastendruck dauert 50 – 100 ms; ein Fenster von 30 – 50 ms fängt alle Prellvorgänge ab, ohne echte Tastendrücke zu blockieren.

Lesen Sie in einer Polling-Schleife den Pin, vergleichen Sie ihn mit dem letzten stabilen Wert und akzeptieren Sie eine Änderung erst, nachdem das Entprellfenster verstrichen ist:

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)

Wenden Sie bei interrupt-gesteuerten Lesevorgängen dieselbe Zeitregel innerhalb des Handlers an und übergeben Sie den echten Tastendruck dann über micropython.schedule() an den Hauptkontext (siehe GPIO-Eingang):

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)

Die ISR filtert Prellvorgänge anhand des Zeitstempels und stellt den Callback in die Warteschlange; handle_press läuft zurück im Hauptkontext, wo Speicherzuweisung und langsame I/O sicher sind.

3.11.2. Hardware-Entprellen

Das Hardware-Entprellen filtert das Prellen elektrisch heraus, bevor es überhaupt den Pin erreicht. Das Standardwerkzeug dafür ist ein Kondensator.

Ein Kondensator ist ein Bauteil mit zwei Anschlüssen, das elektrische Ladung speichert. Physikalisch besteht er aus zwei leitfähigen Platten, die in kurzem Abstand voneinander angeordnet und durch einen Isolator (das Dielektrikum) getrennt sind.

Ein Kondensator, dargestellt als zwei parallele horizontale Platten mit einem Dielektrikum (Isolator) dazwischen. Eine Zuleitung verbindet jede Platte mit einem äußeren Anschluss -- A oben, B unten. Gleiche und entgegengesetzte Ladungen +Q und -Q sammeln sich auf den beiden Platten, wenn eine Spannung V an den Anschlüssen angelegt wird.

Ein Plattenkondensator: zwei Leiter, getrennt durch eine Isolierschicht.

Das Anlegen einer Spannung an seinen Anschlüssen treibt gleiche und entgegengesetzte Ladungen auf die beiden Platten; der Zusammenhang lautet

Q = C × V

wobei Q die gespeicherte Ladung (Coulomb), V die Spannung am Kondensator und C seine Kapazität (Farad) ist. Die Kapazität ist durch die Bauweise des Bauteils festgelegt; mehr Kapazität bedeutet mehr gespeicherte Ladung bei gleicher Spannung.

Die Folge: Ein Kondensator kann seine Spannung nicht augenblicklich ändern. Die ein- oder ausfließende Ladung muss durch den im Pfad vorhandenen Widerstand fließen, und dieser Widerstand bestimmt, wie schnell sich die Spannung ändern kann.

3.11.2.1. RC-Zeitkonstante

Das Aufladen eines Kondensators über einen Widerstand erzeugt keinen Sprung, sondern einen sanften exponentiellen Anstieg in Richtung Versorgungsspannung. Die charakteristische Zeit dieses Anstiegs ist die RC-Zeitkonstante:

τ = R × C

Nach einem τ hat der Kondensator etwa 63 % der Versorgungsspannung erreicht. Nach 5 τ sind es über 99 % – für praktische Zwecke „vollständig geladen“.

Ein Diagramm, das den Anstieg der Kondensatorspannung entlang einer Exponentialkurve von 0 V in Richtung Versorgungsschiene zeigt. Die Zeit τ = RC ist auf der x-Achse dort markiert, wo die Kurve 63 % der Versorgungsspannung erreicht.

Ein Kondensator lädt sich entlang einer Exponentialkurve auf. τ = RC ist die Zeit, um 63 % der Endspannung zu erreichen.

Das Entladen über einen Widerstand folgt dem Spiegelbild: Die Spannung fällt exponentiell von ihrem Anfangswert in Richtung null, sinkt nach einem τ auf 37 % der Startspannung und nach 5 τ auf unter 1 %.

Ein Diagramm, das den Abfall der Kondensatorspannung entlang einer Exponentialkurve von Vmax in Richtung 0 V zeigt. Die Zeit τ = RC ist auf der x-Achse dort markiert, wo die Kurve auf 37 % der Startspannung fällt.

Ein Kondensator entlädt sich entlang eines exponentiellen Abfalls. τ = RC ist die Zeit, um auf 37 % der Startspannung zu fallen.

3.11.2.2. Die Entprellschaltung

Ein Kondensator zwischen einem Eingangspin und Masse, gespeist über einen Reihenwiderstand, bildet einen Tiefpassfilter. Schnelle Spitzen haben nicht genug Zeit, um den Kondensator durch diesen Widerstand zu laden oder zu entladen; der Pin bleibt nahe der Spannung, die vor der Spitze anlag. Langsame Änderungen – ein bewusster Tastendruck – laden oder entladen den Kondensator, und der gelesene Wert folgt.

R1 zieht die High-Seite des Schalters auf Vcc hoch und erzeugt so ein prellendes Roh-Schaltersignal. R2 und C filtern dieses Signal dann per Tiefpass in den Pin:

Ein Schaltereingang mit Hardware-Entprellung. Vcc ist über einen 10-kΩ-Pull-up-Widerstand mit einem Knotenpunkt verbunden. Dieser Knotenpunkt ist über den Schalter im einen Zweig mit Masse verbunden und über einen 10-kΩ-Reihenwiderstand im anderen Zweig mit dem Pin. Ein 100-nF-Kondensator zwischen Pin und Masse vervollständigt den Tiefpassfilter.

Hardware-Entprellung: R2 und C filtern das Roh-Schaltersignal per Tiefpass, bevor es den Pin erreicht.

Typische Werte: R1 = 10 (Pull-up), R2 = 10 (Reihe), C = 100 nF.

Wenn der Schalter offen ist, fließt Strom von Vcc → R1R2 → Kondensator (in Reihe) und lädt den Kondensator mit τ_charge = (R1 + R2) × C = 2 ms auf Vcc.

Wenn der Schalter schließt, wird der Schalterknoten auf Masse geklemmt, und der Kondensator entlädt sich allein über R2 zu dieser Masse mit τ_discharge = R2 × C = 1 ms.

Beide Flanken sind RC-gefiltert. Da der Kondensator an seinem eigenen Knoten sitzt, hinter R2 vom Schalter aus gesehen, schwingt er sauber zwischen Vcc (offen) und 0 V (geschlossen) – im stationären Zustand muss in keinem Fall Strom durch R1 fließen.

3.11.3. Die Wahl zwischen beiden

  • Software ist die Standardlösung. Sie kostet keine Bauteile, der Schwellenwert lässt sich leicht abstimmen, und sie funktioniert an jedem Pin, den die CPU liest.

  • Hardware lohnt die Bauteile, wenn das Prellen etwas anderes als den Polling-Code der CPU erreicht – einen Interrupt, der nicht doppelt auslösen darf, einen Hardware-Zähler oder ein Peripheriegerät ohne eigenen Filter.

Software- und Hardware-Entprellung koexistieren auch problemlos: Ein kleiner RC-Filter unterdrückt die schlimmsten Spitzen, und ein Software-Entprellfenster deckt den Rest ab.