Den Code verstehen
Der Code ist übersichtlich, aber für das Anzeigen des Prellvorgangs vollkommen ausreichend. Es wird innerhalb der loop-Schleife der gemessene Pegel am Taster-Pin an die serielle Schnittstelle übertragen. Sowohl der Serial Monitor als auch der Serial Plotter können diese Daten darstellen. Bei mir sah das Prellen nach mehreren Versuchen wie in der folgenden Abbildung aus. Es ist sehr gut zu erkennen, dass der HIGH-Pegel nach dem Loslassen des Tasters nicht sofort auf einen LOW-Pegel geht, sondern erst noch einmal kurz in Richtung HIGH-Pegel zuckt, bevor er endgültig einen stabilen LOW-Pegel vorweist. Das ist der Beweis dafür, dass ein Taster nicht nur beim Schließen, sondern auch beim Öffnen prellen kann.
Abb. 5: Der Serial Plotter bringt das Prellen ans Licht
Das ist zwar jetzt alles schön und gut, doch wie kann dem unerwünschten Prellen nun begegnet werden? Es gibt diesbezüglich mehrere Ansätze, die sowohl über Soft- als auch über Hardware realisierbar sind. Da es mir in diesem Bastelprojekt vor allem um den Softwareaspekt geht, lasse ich eine Hardwarelösung außen vor.
Anti-Prell-Lösung #1
Eine sehr einfache Lösung besteht im Einfügen einer kurzen Pause in der Verarbeitung durch einen delay-Befehl von zum Beispiel 10ms, wie das hier innerhalb der loop-Funktion zu sehen ist:
void loop() { boolean tasterStatus = digitalRead(tasterPin); if(tasterStatus != prevTasterState) { // Änderung erkannt prevTasterState = tasterStatus; delay(10); // Entprellen if(tasterStatus == HIGH) { impulse++; // Impuls zählen Serial.println(impulse); } } }
Anti-Prell-Lösung #2
Versuchen wir es nun mit einer anderen Lösung. Was hältst du davon, wenn wir eine Schaltung aufbauen, die einen Taster an einem digitalen Eingang besitzt und eine LED an einem anderen digitalen Ausgang? Bei jedem Tastendruck soll die angeschlossene LED an- oder ausgeschaltet werden. Sie toggelt im Takt des Tastendrucks. Ohne eine Gegenmaßnahme des Entprellens würde die LED bei einem Tastendruck entweder an oder aus bleiben, weil zum Beispiel kurz hintereinander ein AN-AUS oder AUS-AN erfolgt. Wenn also mehrere Impulse beim Drücken des Tasters von der Schaltung beziehungsweise der Software registriert werden, wechselt die LED mehrfach ihren Zustand. Bei einem prellfreien Taster sollten sich die Zustände wie im folgenden Diagramm darstellen:
Abb. 6: Das Toggeln der LED durch den Taster
Es ist zu sehen, dass sich immer bei der ansteigenden Flanke des Tasterimpulses der Zustand der LED ändert.
Was wir brauchen
Für dieses Bastelprojekt benötigen wir die folgenden Bauteile:
Tabelle 2: Bauteilliste | |
Bauteil | Bild |
---|---|
LED rot 1x |
|
Widerstand 330Ω 1x |
|
Widerstand 10KΩ 1x |
|
Mikrotaster 1x |
|
Der Schaltplan
Der Schaltplan gleicht dem der Abfrage eines Tasters aus einem vorherigen Bastelprojekt:
Abb. 7: Der Schaltplan für das Toggeln der LED über den Taster
Der Schaltungsaufbau
Der Schaltungsaufbau gleicht dem aus dem Bastelprojekt 3 über die Abfrage des Tasterstatus. Mit diesen technischen Grundlagen wenden wir uns dem Sketch zu.
Der Arduino-Sketch
Der folgende Sketch wird immer dann den Status der angeschlossenen LED wechseln, wenn der Taster gedrückt wird. Hält man den Taster für längere Zeit gedrückt, ändert sich der Status nach dem Wechsel nicht mehr.
int tasterPin = 2; // Taster-Pin 2 int ledPin = 8; // LED-Pin 8 int ledStatus; // LED-Status int tasterStatusActual; // Speichert aktuellen Tasterstatus int prevTasterStatus; // Speichert letzten Tastersstatus int debouncedTasterStatus; // Speichert debounced Tasterstatus int debounceInterval = 50; // 50ms Intervall unsigned long lastDebounceTime = 0; // Zeit, wann LED-Status sich // geändert hat void setup( ) { pinMode(ledPin, OUTPUT); // Taster-Pin als Eingang pinMode(tasterPin, INPUT); // LED-Pin als Ausgang } void loop() { tasterStatusActual = digitalRead(tasterPin); // Tasterstatus lesen unsigned long currentTime = millis(); // Debounce-Zeit lesen if(tasterStatusActual != prevTasterStatus) lastDebounceTime = currentTime; if(currentTime - lastDebounceTime > debounceInterval){ if(tasterStatusActual != debouncedTasterStatus){ debouncedTasterStatus = tasterStatusActual; // LED toggeln, wenn Tasterstatus gleich HIGH-Pegel if(debouncedTasterStatus == HIGH) ledStatus = !ledStatus; } } digitalWrite(ledPin, ledStatus); // LED ansteuern prevTasterStatus = tasterStatusActual; // Letzten Tasterstatus sichern }
Schauen wir uns die Erklärungen zu diesem Sketch an.
Den Code verstehen
Ich möchte an diesem Beispiel zeigen, was ich über ein Warteschleifenverfahren realisiert habe. Zu Beginn der loop-Schleife wird immer der gerade vorherrschende Tastenpegel in die Variable tasterStatusActual eingelesen. Der gerade vorherrschende Zeitstempel seit Sketch-Start wird über die millis-Funktion in die Variable currentTime eingelesen. Wenn sich der aktuelle Tasterstatus vom vorherigen unterscheidet, wird die Debounce-Zeit auf den neuesten Stand gebracht. Diese wird in der folgenden Abfrage benötigt, um darüber zu entscheiden, ob das vorgegebene Intervall abgelaufen ist:
if(currentTime - lastDebounceTime > debounceInterval){...}
Ist das der Fall, wird der aktuelle Tasterstatus mit dem Debounced-Tasterstatus verglichen und erst wenn sie unterschiedlich sind, kommt es zur Abfrage, ob ein HIGH-Pegel zur Statusänderung vorliegt. Denn erst dann soll die LED in ihrem Status geändert werden, was über die Invertierung des Status in der Variablen ledStatus erfolgt:
if(debouncedTasterStatus == HIGH) ledStatus = !ledStatus;
Abschließend muss lediglich die LED über eben diese Variable ledStatus angesteuert werden:
digitalWrite(ledPin, ledStatus);
... und der aktuellen Tasterstatus in den vorherigen Status überführt werden: