Digitale Eingänge am Mikrocontroller: Taster, Logikpegel, Pull-up/Pull-down und Entprellen
https://bildung.social/@oerinformatik/
https://oer-informatik.de/mcu-digitale-eingaenge
Mikrocontroller, digitaler Eingang, digitalRead, Taster, Logikpegel, Pull-up-Widerstand, Pull-down-Widerstand, INPUT_PULLUP, Öffner, Drahtbruch, Prellen, Entprellen
tl/dr; (ca. 31 min Lesezeit): Ein Taster am Eingang braucht mehr als zwei Drähte: Hier erfährst Du, ab welcher Spannung ein Eingang
HIGHliest, warum ein offener Eingang einen Pull-up- oder Pull-down-Widerstand braucht, wie Du Pegel und Ströme an Taster-Widerstands-Netzwerken berechnest, wann ein Öffner sicherer ist als ein Schließer, wie Du viele Taster an wenige Pins bringst und wie Du prellende Kontakte in Hardware und Software entprellst. Für ESP32-C6, ESP32, ESP8266 (NodeMCU) und Arduino Uno [AI-Assisted]. (Zuletzt geändert am 10.11.2026)
Dieser Artikel ist Teil einer Artikelreihe über Mikrocontroller-Grundlagen: Erste Schritte / Digitale Ausgänge / Digitale Eingänge / Variablen und Datentypen / Pinbelegung der Boards
Schon fit in diesem Thema? Nutze die Kann-Liste und die Leitfragen unter dem Artikel als Checkliste, ob Du die relevanten Kompetenzen bereits hast.
Als Grundlagen digitaler Eingänge kann ich nach Durchlesen des Artikels…
… Logikpegel und Schaltschwellen eines Eingangs aus dem Datenblatt bestimmen und die Aufgabe eines Schmitt-Triggers erklären.
… Pull-up- und Pull-down-Widerstände im Stromlaufplan erkennen, benennen und erklären, warum sie bei offenem Kontakt einen definierten Pegel sicherstellen – auch an den Busleitungen SDA und SCL.
… Taster so mit Pull-up- oder Pull-down-Widerständen beschalten, dass bei Betätigung ein 0- oder 1-Signal entsteht, den Pegel bei betätigtem und unbetätigtem Taster bestimmen und mit
digitalRead()einlesen.… Spannungen und Ströme an Taster-Spannungsteiler-Schaltungen und Widerstands-Taster-Netzwerken für den betätigten und unbetätigten Zustand berechnen.
… interne Pull-up-Widerstände mit
INPUT_PULLUP(beim ESP32 auch Pull-down-Widerstände mitINPUT_PULLDOWN) nutzen.… Öffner und Schließer unterscheiden und beurteilen, wie sich ein Drahtbruch auswirkt.
… die Anschlusstechnik mehrerer Taster an einer Platine mit Steckverbinder beschreiben und eine Tasterabfrage über eine Tastenmatrix oder einen Portexpander skizzieren.
… das Prellen mechanischer Kontakte erklären und Entprellschaltungen mit RC-Glied und Schmitt-Trigger oder RS-Flipflop sowie einen entprellten Reset beschreiben, beurteilen und auf Fehler prüfen.
… Tastendrücke in Software entprellen und Flanken erkennen.
Ein Mikrocontroller muss wissen, was um ihn herum passiert: Hat jemand einen Taster gedrückt? Ist die Tür zu? Hat der Endschalter angesprochen? Das erfährt er über digitale Eingänge. Sie kennen wie die Ausgänge nur zwei Zustände, HIGH und LOW. Damit ein Eingang aber verlässlich den richtigen Zustand liest, braucht er eine passende Beschaltung – sonst meldet er Tastendrücke, die es nie gab, oder zählt einen Druck zehnmal.
Am Ende steht diese Schaltung auf dem Steckbrett: ein Taster mit externem Pull-down-Widerstand, der eine LED schaltet.
Zum Üben gibt es eigene Übungsaufgaben zu digitalen Eingängen.
Dieser Artikel baut auf der Kann-Liste der Artikel Erste Schritte mit dem Mikrocontroller und Digitale Ausgänge auf.
Schritt 1: Logikpegel und Schaltschwellen
Ein Pin wird nach dem Reset als Eingang betrieben; ausdrücklich legst Du das mit pinMode(pin, INPUT); fest. digitalRead(pin) liefert dann HIGH oder LOW. Welche Spannung als welcher Pegel gilt, steht im Datenblatt als Input Low Voltage U_\mathrm{IL,max} und Input High Voltage U_\mathrm{IH,min}:
- Bis U_\mathrm{IL,max} erkennt der Eingang sicher Low (0).
- Ab U_\mathrm{IH,min} erkennt er sicher High (1).
- Dazwischen liegt der verbotene Bereich: Der Eingang kann 0 oder 1 lesen, und seine Eingangsstufe zieht erhöhten Querstrom.
| Board | Betriebsspannung U_\mathrm{B} | U_\mathrm{IL,max} | U_\mathrm{IH,min} | 5 V am Eingang erlaubt? |
|---|---|---|---|---|
| ESP32-C6 | 3,3 V | 0{,}25 \cdot U_\mathrm{B} \approx 0{,}83\ \mathrm{V} | 0{,}75 \cdot U_\mathrm{B} \approx 2{,}48\ \mathrm{V} | nein |
| ESP32 (DevKit V4) | 3,3 V | 0{,}25 \cdot U_\mathrm{B} \approx 0{,}83\ \mathrm{V} | 0{,}75 \cdot U_\mathrm{B} \approx 2{,}48\ \mathrm{V} | nein |
| ESP8266 (NodeMCU) | 3,3 V | 0{,}25 \cdot U_\mathrm{B} \approx 0{,}83\ \mathrm{V} | 0{,}75 \cdot U_\mathrm{B} \approx 2{,}48\ \mathrm{V} | nein |
| Arduino Uno (ATmega328P) | 5 V | 0{,}3 \cdot U_\mathrm{B} = 1{,}5\ \mathrm{V} | 0{,}6 \cdot U_\mathrm{B} = 3{,}0\ \mathrm{V} | ja |
Die ESP-Boards sind nicht 5-V-tolerant: Ein Taster oder Sensor, der 5 V an einen Eingang legt, kann den Chip zerstören. Pull-up-Widerstände und Taster gehören dort an 3,3 V. Umgekehrt erkennt ein Uno die 3,3 V eines Sensors gerade noch als High (über 3,0 V), aber ohne Reserve; dafür gibt es Pegelwandler (Artikel Logikfamilien und Pegel).
Schmitt-Trigger: Ein Signal, das langsam ansteigt oder verrauscht ist, bleibt lange im verbotenen Bereich. Ein Eingang mit nur einer Schaltschwelle würde dort mehrmals hin- und herkippen. Ein Schmitt-Trigger hat zwei Schwellen: Er schaltet beim Ansteigen erst bei der oberen Schwelle U_\mathrm{T+} auf High und beim Fallen erst bei der unteren Schwelle U_\mathrm{T-} zurück. Der Abstand der beiden Schwellen heißt Hysterese; kleine Schwankungen darunter ändern den Ausgang nicht. Die Port-Eingänge des ATmega328P haben einen solchen Schmitt-Trigger eingebaut, für die Entprellung in Schritt 7 nimmt man einen eigenen Baustein (z. B. 74HC14). Wie Schmitt-Trigger arbeiten, zeigt der Artikel Komparator und Schmitt-Trigger.
Ein CMOS-Eingang ist sehr hochohmig: Sein Eingangsleckstrom liegt im Bereich von höchstens etwa 1 µA. Daraus folgt das wichtigste Problem dieses Artikels: Ein offener Eingang – etwa ein Taster ohne weitere Beschaltung, der gerade nicht gedrückt ist – hat gar keinen festen Pegel. Er „floatet“: Die Leitung wirkt wie eine Antenne, schon das Feld einer Hand oder ein Netzkabel in der Nähe schaltet ihn zufällig zwischen 0 und 1, und eine Ladung, die beim letzten Tastendruck auf die Leitung kam, bleibt eine Weile stehen.
Schritt 2: Pull-up- und Pull-down-Widerstände
Damit der Eingang bei offenem Kontakt einen definierten Pegel hat, zieht ein Widerstand ihn auf ein festes Potenzial:
- Ein Pull-up-Widerstand liegt zwischen Eingang und Versorgungsspannung. Der Taster schaltet den Eingang gegen Masse. Unbetätigt liest der Controller High, betätigt Low – das Signal ist low-aktiv.
- Ein Pull-down-Widerstand liegt zwischen Eingang und Masse. Der Taster schaltet den Eingang gegen die Versorgungsspannung. Unbetätigt liest der Controller Low, betätigt High – das Signal ist high-aktiv.
| Beschaltung | Taster unbetätigt | Taster betätigt | aktiver Pegel |
|---|---|---|---|
| Pull-up, Taster gegen GND | U_\mathrm{E} = U_\mathrm{B} → 1 | U_\mathrm{E} = 0\ \mathrm{V} → 0 | low-aktiv |
| Pull-down, Taster gegen U_\mathrm{B} | U_\mathrm{E} = 0\ \mathrm{V} → 0 | U_\mathrm{E} = U_\mathrm{B} → 1 | high-aktiv |
Den Eingang direkt mit U_\mathrm{B} zu verbinden, geht nicht: Beim Drücken des Tasters entstünde ein Kurzschluss. Der Widerstand begrenzt den Strom.
Warum liegt bei offenem Taster die volle Spannung am Eingang? In den hochohmigen Eingang fließt praktisch kein Strom, also fällt am Pull-up-Widerstand keine Spannung ab: U_{R1} = R_1 \cdot I \approx 0. Mit einem Leckstrom von 1 µA fallen an 10 kΩ nur 10 mV ab – vernachlässigbar.
Wie groß wählst Du den Widerstand? Bei betätigtem Taster fließt der Querstrom I = U_\mathrm{B} : R, solange der Taster gedrückt ist. Ein kleiner Widerstand macht den Eingang störfest, kostet aber Strom; ein großer spart Strom, macht den Eingang aber empfindlich für Störungen und zusammen mit der Leitungskapazität langsam. Übliche Werte liegen zwischen 4,7 kΩ und 47 kΩ. Bei 3,3 V und 10 kΩ fließen 0,33 mA, bei 5 V 0,5 mA.
Pull-ups an SDA und SCL: Beim I²C-Bus treiben alle Teilnehmer die beiden Leitungen nur aktiv auf Low (Ausgänge mit offenem Drain bzw. Kollektor). Den High-Pegel stellen allein zwei Pull-up-Widerstände her, typisch 4,7 kΩ bei 100 kHz, kleiner bei höherer Taktrate oder vielen Teilnehmern. So entsteht kein Kurzschluss, wenn zwei Teilnehmer gleichzeitig senden, und jeder Teilnehmer kann die Leitung auf Low halten. Fehlen die Pull-ups, bleibt der Bus stumm. Viele Sensor-Breakouts bringen die Widerstände schon mit. Mehr dazu im Artikel I²C-Bus.
Praktischer Aufbau mit Pull-down: Taster 2 liegt zwischen 3,3 V (Uno: 5 V) und dem Eingang BUTTON2_PIN, ein 10-kΩ-Widerstand zieht den Eingang auf GND. LED 1 zeigt an, ob der Taster gedrückt ist. Taster 2 ist hier bewusst anders beschaltet als in der Standard-Pinbelegung der Reihe (dort sind alle Taster low-aktiv); deshalb steht im Programm pinMode(BUTTON2_PIN, INPUT); ohne internen Widerstand.
Die Fritzing-Datei zum Nachbauen: mcu-digitale-eingaenge-pulldown-steckbrett-esp32c6.fzz
Das Programm fragt den Eingang in jedem Durchlauf von loop() ab (Polling) und schaltet LED 1 entsprechend:
Taster 2 liegt zwischen 3,3 V (Pin „3V3“) und GPIO2, der Pull-down-Widerstand (10 kΩ) zwischen GPIO2 und GND. LED 1 hängt mit 220 Ω an GPIO4. Unbetätigt liest GPIO2 0 V (LOW), betätigt 3,3 V (HIGH).
//-------------------------------------------------------------------------------------
// Liste der Ein- und Ausgabeelemente
// Board: ESP32-C6 Dev Kit N8-M
//-------------------------------------------------------------------------------------
// Datentyp | Name der Variable | Anschlusspin | Name, Verhalten
const int BUTTON2_PIN = 2; // Button 2, active LOW, INPUT_PULLUP
const int LED1_PIN = 4; // LED 1, active HIGH (strapping pin, ok as output)
// Taster 2 ist in diesem Beispiel bewusst anders beschaltet als in der Liste:
// Taster gegen 3,3 V (Uno: 5 V), externer Pull-down 10 kOhm gegen GND -> active HIGH
void setup() {
pinMode(BUTTON2_PIN, INPUT); // ohne internen Widerstand, der Pull-down ist extern
pinMode(LED1_PIN, OUTPUT);
}
void loop() {
if (digitalRead(BUTTON2_PIN) == HIGH) { // betätigt: HIGH (high-aktiv)
digitalWrite(LED1_PIN, HIGH); // LED 1 an
} else {
digitalWrite(LED1_PIN, LOW); // LED 1 aus
}
}Die Listen der Ein- und Ausgabeelemente für weitere Boards (ESP32 Dev Kit V1/V2, WeMos-Board mit OLED) stehen im Artikel Pinbelegung der Mikrocontroller-Boards.
Schritt 3: Interne Pull-up- und Pull-down-Widerstände
Die meisten Controller haben zuschaltbare Widerstände eingebaut. Du aktivierst sie mit pinMode():
pinMode(pin, INPUT); // kein interner Widerstand: externer Pull-up oder Pull-down nötig
pinMode(pin, INPUT_PULLUP); // interner Pull-up (alle vier Boards)
pinMode(pin, INPUT_PULLDOWN); // interner Pull-down (nur ESP32-C6 und ESP32)| Board | interner Pull-up | interner Pull-down | Hinweise |
|---|---|---|---|
| ESP32-C6 | an allen GPIO | an allen GPIO | Richtwert einige 10 kΩ |
| ESP32 (DevKit V4) | ja, außer GPIO34–39 | ja, außer GPIO34–39 | GPIO34–39 sind reine Eingänge ohne interne Widerstände |
| ESP8266 (NodeMCU) | ja, außer D0 (GPIO16) | nur D0 mit INPUT_PULLDOWN_16 |
INPUT_PULLDOWN gibt es nicht (Übersetzungsfehler); D3, D4, D8 sind Boot-Pins |
| Arduino Uno | an allen Pins, 20–50 kΩ | keiner | INPUT_PULLDOWN gibt es nicht (Übersetzungsfehler) |
Weil alle Boards einen internen Pull-up haben, schließt die Reihe alle Taster gegen GND an und nutzt INPUT_PULLUP – so läuft dasselbe Programm überall. Gedrückt heißt dann LOW. Den Aufbau mit Taster 1 und LED 1 kennst Du aus dem Artikel Erste Schritte; außer dem Taster brauchst Du kein Bauteil.
Taster 1 liegt zwischen GPIO1 und GND, ein Widerstand ist nicht nötig. LED 1 hängt mit 220 Ω an GPIO4. Der ESP32-C6 hat an jedem GPIO einen zuschaltbaren Pull-up und Pull-down.
//-------------------------------------------------------------------------------------
// Liste der Ein- und Ausgabeelemente
// Board: ESP32-C6 Dev Kit N8-M
//-------------------------------------------------------------------------------------
// Datentyp | Name der Variable | Anschlusspin | Name, Verhalten
const int BUTTON1_PIN = 1; // Button 1, active LOW, INPUT_PULLUP
const int LED1_PIN = 4; // LED 1, active HIGH (strapping pin, ok as output)
void setup() {
pinMode(BUTTON1_PIN, INPUT_PULLUP); // interner Pull-up: unbetätigt HIGH
pinMode(LED1_PIN, OUTPUT);
}
void loop() {
bool pressed = (digitalRead(BUTTON1_PIN) == LOW); // betätigt: LOW (low-aktiv)
digitalWrite(LED1_PIN, pressed ? HIGH : LOW); // LED 1 leuchtet, solange Taster 1 gedrückt ist
}Die Listen der Ein- und Ausgabeelemente für weitere Boards (ESP32 Dev Kit V1/V2, WeMos-Board mit OLED) stehen im Artikel Pinbelegung der Mikrocontroller-Boards.
Die internen Widerstände sind recht hochohmig. Für lange Leitungen zu einem Bedienfeld oder in störender Umgebung (Motoren, Relais) ist ein externer, niederohmigerer Widerstand besser, z. B. 4,7 kΩ.
Schritt 4: Spannungen an Taster-Widerstands-Netzwerken berechnen
In echten Schaltungen liegt oft noch ein Widerstand in Reihe zum Taster: als Schutzwiderstand, der den Strom begrenzt, falls der Pin versehentlich als Ausgang auf High steht, oder als Teil eines RC-Glieds (Schritt 7). Dann ist der Eingang bei betätigtem Taster nicht mehr genau 0 V, sondern Pull-up und Schutzwiderstand bilden einen Spannungsteiler.
Beispiel (Uno): Pull-up R_1 = 4{,}7\ \mathrm{k\Omega} an U_\mathrm{B} = 5\ \mathrm{V}, Taster mit Schutzwiderstand R_\mathrm{S} = 330\ \mathrm{\Omega} gegen Masse.
\def\arraystretch{2.3} \begin{array}{rcl|l} U_\mathrm{E} & = & U_\mathrm{B} \cdot \frac{R_\mathrm{S}}{R_1 + R_\mathrm{S}} & \\ U_\mathrm{E} & = & 5\ \mathrm{V} \cdot \frac{330\ \mathrm{\Omega}}{4\,700\ \mathrm{\Omega} + 330\ \mathrm{\Omega}} & \\ U_\mathrm{E} & \approx & 0{,}328\ \mathrm{V} & \end{array}
0{,}328\ \mathrm{V} liegt deutlich unter U_\mathrm{IL,max} = 1{,}5\ \mathrm{V}: Der Controller liest sicher Low. Der Schutzwiderstand darf also nicht zu groß werden – sonst landet U_\mathrm{E} im verbotenen Bereich. Bei 3,3 V ist die Grenze enger (U_\mathrm{IL,max} \approx 0{,}83\ \mathrm{V}), rechne deshalb mit der Schwelle Deines Boards. Wie Spannungsteiler berechnet werden, zeigt der Artikel Spannungsteiler.
Mehrere Taster an einem Analogeingang: Mit verschiedenen Widerständen in Reihe zu den Tastern lassen sich mehrere Taster über eine Leitung abfragen. Jeder Taster erzeugt mit dem gemeinsamen Pull-up eine eigene Spannung U_\mathrm{ADC} = U_\mathrm{B} \cdot \frac{R_n}{R_\mathrm{PU} + R_n}:
| betätigt | Widerstand gegen Masse R_n | U_\mathrm{ADC} |
|---|---|---|
| kein Taster | unendlich | 5,00 V |
| S1 | 0 Ω | 0 V |
| S2 | 2,2 kΩ | 0,902 V |
| S3 | 4,7 kΩ | 1,60 V |
Werden zwei Taster gleichzeitig gedrückt, liegen ihre Widerstände parallel; die Spannung wird kleiner als die des Tasters mit dem kleineren Widerstand, und meist erkennt das Programm nur diesen Taster. Wie das Programm die gemessene Spannung mit analogRead() einem Taster zuordnet, zeigt der Artikel Analoge Eingänge.
Schritt 5: Öffner, Schließer und der Drahtbruch
Taster und Schalter gibt es mit zwei Arten von Kontakten:
- Der Schließer (normally open, NO) ist in Ruhe offen und schließt beim Betätigen. Die meisten Taster in Mikrocontroller-Projekten sind Schließer.
- Der Öffner (normally closed, NC) ist in Ruhe geschlossen und öffnet beim Betätigen.
Mit Pull-up und Kontakt gegen GND liest der Controller beim Schließer unbetätigt HIGH und betätigt LOW; beim Öffner ist es genau umgekehrt. Im Programm musst Du die Abfrage deshalb an die Kontaktart anpassen.
Spannend wird der Unterschied, wenn die Leitung zum Taster bricht oder ein Stecker abfällt. Mit Pull-up liest der Eingang dann dauerhaft HIGH:
| Kontakt (Pull-up, gegen GND) | unbetätigt | betätigt | bei Drahtbruch | Wirkung des Drahtbruchs |
|---|---|---|---|---|
| Schließer | HIGH |
LOW |
HIGH |
sieht aus wie „nicht betätigt“ – der Fehler bleibt unbemerkt |
| Öffner | LOW |
HIGH |
HIGH |
sieht aus wie „betätigt“ – das Gerät geht in den sicheren Zustand |
Ein Beispiel aus der Werkstatt der CSB-Rad GmbH: Beim Lastenrad meldet ein Bremsschalter der Motorsteuerung, dass gebremst wird; dann muss der Motor sofort abschalten. Wäre der Bremsschalter ein Schließer, bliebe ein abgerissenes Kabel unbemerkt – der Motor würde beim Bremsen weiterschieben. Als Öffner meldet der Kabelbruch „Bremse betätigt“, der Motor bleibt aus, und der Fehler fällt sofort auf. Deshalb nimmt man für alles, was ausschalten oder stoppen soll (Not-Halt, Endschalter, Bremse), einen Öffner: Er ist drahtbruchsicher. Für Funktionen, die nur etwas einschalten, genügt der Schließer.
Eine Abfrage für einen Öffner an BUTTON1_PIN mit internem Pull-up sieht so aus:
// Öffner gegen GND: unbetätigt LOW, betätigt oder Drahtbruch HIGH
if (digitalRead(BUTTON1_PIN) == HIGH) {
motorAus(); // sicherer Zustand
}Es gibt auch Taster mit beiden Kontakten (Wechsler). Steht an einem Taster mit mehr als zwei Anschlüssen nicht NO oder NC, findest Du mit dem Durchgangsprüfer heraus, welche Anschlüsse in Ruhe verbunden sind.
Schritt 6: Mehrere Taster anschließen
Bedienelemente sitzen oft auf einer eigenen Platine (Frontplatte, Tastenfeld), die über einen Steckverbinder mit der Controllerplatine verbunden ist. Je nach Zahl der Taster und der freien Pins gibt es vier Lösungen:
| Anschlusstechnik | Leitungen für n Taster | Vorteile | Nachteile |
|---|---|---|---|
| je Taster ein Eingang, gemeinsame Masse | n + 1 | einfach, gleichzeitiges Drücken erkennbar | viele Pins und Adern |
| Tastenmatrix (Zeilen × Spalten) | z + s (z. B. 4 × 4 = 16 Taster an 8 Leitungen) | wenige Leitungen für viele Taster | Programm muss Zeilen nacheinander abfragen; Entkoppeldioden bei Mehrfachbetätigung |
| Widerstandsnetzwerk am Analogeingang | 3 (Signal, U_\mathrm{B}, GND) | sehr wenige Leitungen | Toleranzen, Mehrfachbetätigung kaum erkennbar |
| Portexpander oder Schieberegister | 4 bis 5 (z. B. U_\mathrm{B}, GND, SDA, SCL) | viele Taster an wenigen Pins, erweiterbar | zusätzlicher Baustein, Abfrage über Bus |
Am Steckverbinder fasst Du gleichartige Anschlüsse zusammen: Alle Taster bekommen eine gemeinsame Masseleitung, die Pull-up-Widerstände sitzen auf der Controllerplatine (dort, wo der Eingang ist) oder sind intern zugeschaltet. Bei langen Leitungen helfen kleine Kondensatoren gegen Störungen (Schritt 7). Reicht die Polzahl des Steckverbinders nicht, weichst Du auf eine Matrix oder einen Portexpander aus.
Tastenmatrix: Die Taster sitzen an den Kreuzungen von Zeilen- und Spaltenleitungen. Das Programm schaltet nacheinander je eine Zeile als Ausgang auf LOW, alle anderen bleiben hochohmig; die Spalten sind Eingänge mit Pull-up. Liest eine Spalte LOW, ist der Taster an der Kreuzung von aktiver Zeile und dieser Spalte gedrückt. Drückt jemand drei Taster in einem Rechteck, entstehen Geisterkontakte; Dioden in Reihe zu jedem Taster verhindern das.
Tasterabfrage über einen Portexpander: Ein I²C-Portexpander (z. B. PCF8574 mit acht Anschlüssen P0 … P7) hat schwache interne Pull-ups. Die Taster schalten seine Anschlüsse gegen Masse; der Controller liest über den Bus ein Byte, in dem jedes Bit für einen Taster steht. Liest er z. B. 1111\,1011_2, ist der Taster an P2 betätigt (low-aktiv). Viele Expander melden eine Änderung über einen Interrupt-Ausgang (INT), sodass der Controller nicht ständig abfragen muss. Ein zweiter Expander am selben Bus braucht eine andere Adresse: Seine Adresseingänge (A0 … A2) werden anders auf U_\mathrm{B} oder Masse gelegt. Alternativ schiebt ein Parallel-Seriell-Schieberegister (z. B. 74HC165) die Tasterzustände in den Controller. Wie Du einzelne Bits aus dem gelesenen Byte herausfilterst, zeigt der Artikel Register und Bitoperationen.
Willst Du eine Schaltung um einen weiteren Taster erweitern, gehst Du immer gleich vor: freien Pin (oder Expander-Anschluss) suchen, Sonderfunktionen des Pins prüfen (Boot-Pins, reine Eingänge), Beschaltung (Pull-up) ergänzen, Stromlaufplan und Liste der Ein- und Ausgabeelemente nachführen und die Software anpassen.
Schritt 7: Prellen und Entprellen in Hardware
Ein mechanischer Kontakt schließt nicht sauber. Beim Betätigen federn die Kontaktflächen zurück, öffnen und schließen mehrmals, bis sie nach etwa 1 … 10 ms (bei schlechten Kontakten auch länger) ruhig aufliegen. Dieses Prellen sieht der Controller als Folge kurzer Impulse. Ein Programm, das Tastendrücke zählt, zählt dann statt einem Druck mehrere.
Es gibt drei Wege zum Entprellen, zwei davon in Hardware:
1. RC-Glied mit Schmitt-Trigger: Ein Kondensator am Eingang glättet die Impulse. Beim Betätigen entlädt der Taster den Kondensator über einen kleinen Widerstand R_2 schnell; die kurzen Unterbrechungen reichen nicht, um ihn über R_1 wieder nennenswert zu laden. Beim Loslassen lädt sich der Kondensator über R_1 + R_2 langsam auf. Ein Schmitt-Trigger (z. B. Inverter 74HC14) wandelt die langsam steigende Kondensatorspannung in eine steile Flanke um. Ein normales Gatter ohne Hysterese würde im Übergangsbereich mehrfach schalten oder sogar schwingen.
Die Zeitkonstante muss größer als die Prellzeit sein. Beispiel: R_1 = 47\ \mathrm{k\Omega}, R_2 = 1\ \mathrm{k\Omega}, C = 220\ \mathrm{nF}, U_\mathrm{B} = 5\ \mathrm{V} und obere Schaltschwelle U_\mathrm{T+} = 2{,}9\ \mathrm{V}. Nach dem Loslassen dauert es
\def\arraystretch{2.3} \begin{array}{rcl|l} t & = & (R_1 + R_2) \cdot C \cdot \ln\frac{U_\mathrm{B}}{U_\mathrm{B} - U_\mathrm{T+}} & \\ t & = & 48\ \mathrm{k\Omega} \cdot 220\ \mathrm{nF} \cdot \ln\frac{5\ \mathrm{V}}{2{,}1\ \mathrm{V}} & \\ t & \approx & 10{,}56\ \mathrm{ms} \cdot 0{,}8675 \approx 9{,}16\ \mathrm{ms} & \end{array}
bis der Schmitt-Trigger umschaltet – lang genug für einen Taster mit wenigen Millisekunden Prellzeit, kurz genug, dass niemand die Verzögerung merkt. Das Laden eines Kondensators erklärt der Artikel Kondensator und Spule: Schaltvorgänge.
2. RS-Flipflop mit Wechsler: Ein Taster mit Umschaltkontakt (Wechsler) setzt ein RS-Flipflop aus zwei NAND-Gattern über den einen Kontakt und setzt es über den anderen zurück; beide Eingänge haben Pull-up-Widerstände. Beim ersten Berühren des einen Kontakts kippt das Flipflop. Die folgenden Prellimpulse öffnen den Kontakt nur kurz – der Eingang geht dann auf High, und das ist bei NAND-Flipflops der Zustand „Speichern“. Der Wechsler prellt nie zurück bis zum anderen Kontakt, deshalb bleibt der Ausgang stabil. Diese Lösung entprellt ohne Verzögerung, braucht aber einen Wechsler und zwei Leitungen; mit einem einfachen Schließer funktioniert sie nicht. Mehr zu Flipflops im Artikel Flipflops.
Entprellter Reset: Ein Reset-Taster muss in Hardware entprellt werden, denn während des Resets läuft kein Programm. Die Reset-Beschaltung mit Pull-up-Widerstand (z. B. 10 kΩ) und Kondensator (z. B. 100 nF) gegen Masse ist selbst ein RC-Glied: Der Taster entlädt den Kondensator über einen kleinen Schutzwiderstand, nach dem Loslassen lädt er sich langsam auf und hält den Reset-Eingang einige Millisekunden auf Low. Der Reset-Eingang vieler Controller hat einen Schmitt-Trigger. Für einen sauberen Impuls fester Mindestlänge gibt es Reset-Bausteine (supervisor). Mehr zur Reset-Beschaltung zeigt der Artikel Aufbau eines Mikrocontrollers.
Typische Fehler in Entprellschaltungen: Gatter ohne Schmitt-Trigger-Eingang hinter dem RC-Glied; Zeitkonstante kleiner als die Prellzeit; fehlender Widerstand R_2, sodass der Kontakt den Kondensator schlagartig entlädt (hoher Spitzenstrom, Kontaktabbrand); RS-Flipflop mit Schließer statt Wechsler oder ohne Pull-up-Widerstände; Kondensator so groß, dass kurze Tastendrücke verloren gehen.
Schritt 8: Entprellen in Software und Flanken erkennen
Heute ist der dritte Weg der Normalfall: Das Programm entprellt selbst. Es kostet kein Bauteil. Hardware-Entprellung brauchst Du nur, wenn das Signal direkt einen Interrupt- oder Zählereingang ansteuert oder wenn (wie beim Reset) kein Programm läuft.
Zwei Ideen stecken in der Software-Lösung:
- Flankenerkennung: Meist interessiert nicht, ob der Taster gedrückt ist, sondern dass er gerade gedrückt wurde. Das Programm merkt sich den letzten Pegel und reagiert nur, wenn sich der Pegel ändert. Mit Pull-up ist der Wechsel von
HIGHnachLOWdie fallende Flanke (Taster gedrückt), der Wechsel vonLOWnachHIGHdie steigende Flanke (Taster losgelassen). - Wartezeit: Nach einer erkannten Änderung wartet das Programm, bis das Prellen vorbei ist (z. B. 20 ms), und liest dann erneut. Erst wenn der neue Pegel noch anliegt, gilt die Änderung.
Das folgende Programm schaltet LED 1 bei jedem Druck auf Taster 1 um und zählt die Drücke im seriellen Monitor mit:
Taster 1 an GPIO1 gegen GND, LED 1 an GPIO4 – derselbe Aufbau wie im vorigen Schritt. Für die Ausgabe im seriellen Monitor muss beim C6 unter „Werkzeuge“ die Option „USB CDC On Boot“ zur benutzten USB-Buchse passen.
//-------------------------------------------------------------------------------------
// Liste der Ein- und Ausgabeelemente
// Board: ESP32-C6 Dev Kit N8-M
//-------------------------------------------------------------------------------------
// Datentyp | Name der Variable | Anschlusspin | Name, Verhalten
const int BUTTON1_PIN = 1; // Button 1, active LOW, INPUT_PULLUP
const int LED1_PIN = 4; // LED 1, active HIGH (strapping pin, ok as output)
const unsigned long DEBOUNCE_MS = 20; // Wartezeit zum Entprellen in ms
int lastState = HIGH; // letzter gültiger Pegel (unbetätigt: HIGH)
bool ledOn = false; // Zustand von LED 1
int pressCount = 0; // Zahl der Tastendrücke
void setup() {
Serial.begin(115200);
pinMode(BUTTON1_PIN, INPUT_PULLUP);
pinMode(LED1_PIN, OUTPUT);
}
void loop() {
int state = digitalRead(BUTTON1_PIN);
if (state != lastState) { // Pegel hat sich geändert: Flanke
delay(DEBOUNCE_MS); // Prellen abwarten ...
state = digitalRead(BUTTON1_PIN); // ... und erneut lesen
if (state != lastState) { // Änderung ist stabil
lastState = state;
if (state == LOW) { // fallende Flanke: Taster wurde gedrückt
pressCount++;
ledOn = !ledOn; // LED 1 umschalten
digitalWrite(LED1_PIN, ledOn ? HIGH : LOW);
Serial.print("Tastendruck Nr. ");
Serial.println(pressCount);
}
}
}
}Die Listen der Ein- und Ausgabeelemente für weitere Boards (ESP32 Dev Kit V1/V2, WeMos-Board mit OLED) stehen im Artikel Pinbelegung der Mikrocontroller-Boards.
Ohne Flankenerkennung würde die LED bei gedrücktem Taster tausendfach pro Sekunde umschalten; ohne Wartezeit würde sie beim Prellen mehrmals umschalten und je nach Zahl der Prellimpulse an oder aus bleiben. Probiere es aus: Setze DEBOUNCE_MS auf 0 und drücke mehrmals – bei vielen Tastern zählt der serielle Monitor dann mehr Drücke, als Du gemacht hast.
delay() hat einen Nachteil: Während der 20 ms tut der Controller nichts anderes. Bei vielen Tastern oder zeitkritischen Aufgaben merkt sich das Programm deshalb nur den Zeitpunkt der letzten Änderung und vergleicht ihn mit der aktuellen Zeit von millis(). Wie das geht, zeigt der Artikel Zeit ohne delay(): millis(). Soll der Controller auf einen Tastendruck sofort reagieren, ohne ständig abzufragen, hilft ein Interrupt: Interrupts.
Unterschiede der Boards
| Thema | ESP32-C6 | ESP32 (DevKit V4) | ESP8266 (NodeMCU) | Arduino Uno |
|---|---|---|---|---|
| Pegel am Eingang | 3,3 V, nicht 5-V-tolerant | 3,3 V, nicht 5-V-tolerant | 3,3 V, nicht 5-V-tolerant | 5 V |
| Schwellen Low / High | 0,83 V / 2,48 V | 0,83 V / 2,48 V | 0,83 V / 2,48 V | 1,5 V / 3,0 V |
INPUT_PULLUP |
alle GPIO | alle außer GPIO34–39 | alle außer D0 | alle Pins |
INPUT_PULLDOWN |
alle GPIO | alle außer GPIO34–39 | nur D0 (INPUT_PULLDOWN_16) |
– |
| Taster 1 / Taster 2 | GPIO1 / GPIO2 | GPIO32 / GPIO33 | D3 (FLASH-Taster) / D5 | 2 / 3 |
| Vorsicht bei | Strapping-Pins GPIO4/5/8/9/15 | Strapping-Pins GPIO0/2/5/12/15 | Boot-Pins D3, D4, D8 | Pins 0/1 (serieller Monitor) |
Boot- und Strapping-Pins liest der Controller beim Start ein. Ein Taster oder Pull-down daran kann verhindern, dass das Board normal startet. Die Pinbelegung der Reihe meidet sie für Taster; Details stehen im Artikel Pinbelegung der Mikrocontroller-Boards.
Unter der Haube: Was macht digitalRead()?
digitalRead() liest am Ende nur ein Bit aus einem Eingangsregister: Beim Uno ist es das Bit eines Ports im Register PINB, PINC oder PIND. pinMode(pin, INPUT_PULLUP) löscht das Richtungsbit im Register DDRx und setzt das Bit im Register PORTx – bei einem Eingang schaltet dieses Bit den internen Pull-up zu. Die ESP-Controller haben für jeden Pin eigene Konfigurationsbits für Pull-up und Pull-down. Wie Du Eingänge direkt über Register liest und einzelne Bits maskierst, zeigt der Vertiefungsartikel Register und Bitoperationen.
Wie geht es weiter?
Taster sind digital, viele Sensoren liefern aber eine Spannung: Weiter geht es mit Variablen und Datentypen und analogen Eingängen. Nicht blockierendes Entprellen lernst Du bei millis(). Zum Üben gibt es die Übungsaufgaben zu digitalen Eingängen.
Leitfragen
- Ab welcher Spannung liest ein Eingang sicher High, und was passiert dazwischen?
Das Datenblatt nennt U_\mathrm{IH,min} (ab hier sicher High) und U_\mathrm{IL,max} (bis hier sicher Low), bei den ESP-Boards 0,75 bzw. 0,25 der Betriebsspannung, beim Uno 0,6 bzw. 0,3. Dazwischen liegt der verbotene Bereich: Der gelesene Wert ist zufällig, und die Eingangsstufe zieht Querstrom. siehe Abschnitt „Schritt 1“
- Wozu dient ein Schmitt-Trigger?
Er hat zwei Schaltschwellen (Hysterese) und macht aus einem langsam ansteigenden oder verrauschten Signal eine einzige steile Flanke. Ein Gatter mit nur einer Schwelle würde im Übergangsbereich mehrfach kippen. siehe Abschnitt „Schritt 1“
- Warum braucht ein Taster am Eingang einen Pull-up- oder Pull-down-Widerstand?
Ein CMOS-Eingang ist sehr hochohmig. Bei offenem Kontakt hätte er keinen festen Pegel und würde durch Störungen zufällig zwischen 0 und 1 wechseln. Der Widerstand zieht ihn auf ein festes Potenzial; weil kaum Strom fließt, fällt an ihm keine nennenswerte Spannung ab. Beim Drücken begrenzt er den Strom. siehe Abschnitt „Schritt 2“
- Welchen Pegel liest der Controller bei Pull-up- und bei Pull-down-Beschaltung?
Pull-up mit Taster gegen Masse: unbetätigt High, betätigt Low (low-aktiv). Pull-down mit Taster gegen U_\mathrm{B}: unbetätigt Low, betätigt High (high-aktiv). siehe Abschnitt „Schritt 2“
- Wozu dienen die Pull-up-Widerstände an SDA und SCL?
Die I²C-Teilnehmer ziehen die Leitungen nur aktiv auf Low (offener Drain bzw. Kollektor). Den High-Pegel erzeugen allein die Pull-up-Widerstände. So gibt es keinen Kurzschluss, wenn mehrere Teilnehmer gleichzeitig treiben. siehe Abschnitt „Schritt 2“
- Welche internen Widerstände bieten die Boards, und wie schaltest Du sie ein?
Mit pinMode(pin, INPUT_PULLUP) den internen Pull-up (alle vier Boards, beim ESP32 nicht an GPIO34–39, beim NodeMCU nicht an D0), mit INPUT_PULLDOWN den internen Pull-down (nur ESP32-C6 und ESP32). Der Uno hat keinen Pull-down. siehe Abschnitt „Schritt 3“
- Wie berechnest Du die Eingangsspannung, wenn ein Widerstand in Reihe zum Taster liegt?
Pull-up und Reihenwiderstand bilden bei betätigtem Taster einen Spannungsteiler: U_\mathrm{E} = U_\mathrm{B} \cdot R_\mathrm{S} : (R_1 + R_\mathrm{S}). Das Ergebnis vergleichst Du mit U_\mathrm{IL,max} bzw. U_\mathrm{IH,min} des Boards. siehe Abschnitt „Schritt 4“
- Warum nimmt man für Not-Halt, Endschalter und Bremse einen Öffner?
Bei einem Drahtbruch liest der Eingang mit Pull-up dauerhaft High. Beim Öffner bedeutet das „betätigt“: Das Gerät geht in den sicheren Zustand, und der Fehler fällt auf. Beim Schließer sähe der Drahtbruch wie „nicht betätigt“ aus und bliebe unbemerkt. siehe Abschnitt „Schritt 5“
- Welche Möglichkeiten gibt es, viele Taster mit wenigen Leitungen anzuschließen?
Tastenmatrix (Zeilen und Spalten), Widerstandsnetzwerk an einem Analogeingang, Portexpander am I²C-Bus oder Schieberegister. Am Steckverbinder werden gleichartige Anschlüsse wie die Masse zusammengefasst. siehe Abschnitt „Schritt 6“
- Was ist Prellen, und wie entprellst Du in Hardware und in Software?
Mechanische Kontakte öffnen und schließen beim Betätigen mehrmals, bevor sie ruhig aufliegen. In Hardware glättet ein RC-Glied die Impulse und ein Schmitt-Trigger macht daraus eine Flanke (Zeitkonstante größer als die Prellzeit), oder ein RS-Flipflop mit Wechsler speichert den ersten Kontakt. In Software erkennt das Programm die Flanke, wartet die Prellzeit ab und liest erneut. siehe Abschnitt „Schritt 7“ und Abschnitt „Schritt 8“
Links und weitere Informationen
als Nachschlagewerk: Arduino-Sprachreferenz zu digitalRead() und pinMode()
für die Pins aller Boards: Pinbelegung der Mikrocontroller-Boards
für Register und Bitmasken: Register und Bitoperationen
für die Schaltschwellen: Komparator und Schmitt-Trigger
als Primärquelle: Datenblätter der Chips bei Espressif und Microchip (ATmega328P)
Hinweis zur Nachnutzung als Open Educational Resource (OER)
Dieser Artikel und seine Texte, Bilder, Grafiken, Code und sonstiger Inhalt sind - sofern nicht anders angegeben - lizenziert unter CC BY 4.0. Nennung gemäß TULLU-Regel bitte wie folgt: “Digitale Eingänge am Mikrocontroller: Taster, Logikpegel, Pull-up/Pull-down und Entprellen” von oer-informatik.de (H. Stein), Lizenz: CC BY 4.0. Der Artikel wurde unter https://oer-informatik.de/mcu-digitale-eingaenge veröffentlicht, die Quelltexte sind in weiterverarbeitbarer Form verfügbar im Repository unter https://gitlab.com/oer-informatik/mcu/arduino-esp. Erstellt mit KI-Assistenz; von mir umfassend redaktionell überarbeitet, geprüft und freigegeben. Stand: 10.11.2026.
[Kommentare zum Artikel lesen, schreiben] / [Artikel teilen] / [gitlab-Issue zum Artikel schreiben]
