Möchte man den Schalter verwenden, um den Status der LED (an/aus) zu ändern, so wird man feststellen, dass dies nicht ohne weiteres zuverlässig möglich ist. Der Grund und zwei Lösungen dafür erfährst Du hier!
...Unter der Haube
Ein Schalter funktioniert mechanisch und beim Drücken und Loslassen tut er etwas ähnliches wie ein Ball der auf den Boden fällt: im Rheinland würde man sagen, er „titscht“; in den anderen Bundesländern würde man es vielleicht „prellen“ nennen. Das bedeutet, dass ein einmaliges Drücken des Schalters im schlimmsten Fall als mehrmaliges Drücken erkannt/interpretiert wird.
Veranschaulichung von Wikipedia (User Arctanx), wie aus Sicht des Arduinos das Loslassen eines Schalters aussieht. Mehr Informationen findet man im Wiki-Artikel „Prellen„.
1. Lösung (einfach, aber kleiner Haken)
Um die in der Grafik zu sehenden Schwankungen einfach zu ignorieren, kann man ein Delay einbauen.
int ledStatus=LOW; //zum Zwischenspeichern des LED-Status
void setup() {
pinMode(2, INPUT_PULLUP); //Schalter
pinMode(13, OUTPUT); //interne LED
}
void loop() {
int schalterWert = digitalRead(2);
if (schalterWert == LOW) { //Falls Schalter gedrückt
//ändere den Status der LED
if(ledStatus==LOW){ledStatus=HIGH;}else{ledStatus=LOW;}
}
//...und setze diesen
digitalWrite(13, ledStatus);
delay(100);
}
Dadurch wird das Prellen des Schalters gar nicht erst erkannt. Leider hat es zwei ungünstige Nachteile:
- Schnelles Schalter-Drücken wird nicht erkannt.
- Ein Gedrückt-Halten des Schalters sorgt für ein Blinken der LED.
2. Lösung (schwieriger aber ohne Haken)
Das zweite Beispiel ist hier schon deutlich komplexer und es wird nicht erwartet, dass man dieses auf Anhieb versteht. Dennoch findet man durch die Kommentare im Quelltext Erklärungen. Die Idee hinter dem Quelltext besteht darin, dass man einer Änderung des Button-Status erst vertraut, wenn diese längere als 50ms vorliegt. Insbesondere werden dadurch die (im Bild zu sehenden) Schwankungen des Button-Status ignoriert, da diese kürzer als 50ms vorliegen.
Die Funktion millis() zählt einfach nur die Millisekunden seit Start des Programms. Die Variable in Zeile 10 speichert den Zeitpunkt der letzten Änderung des Zustandes. In Zeile 30 wird dann entsprechend überprüft, ob seit der letzten Änderung mehr als 50ms vergangen sind.
int buttonPin = 2;
int ledPin = 13;
//Variablen zum speichern der Zustände
int ledStatus = HIGH; //der LED-Status
int buttonStatus; //zum zwischenspeichern des aktuellen Schalter-Status
int letzterButtonStatus = LOW; //zum zwischenspeichern des letzten Schalter-Status
//long ist ein Datentyp für große Zahlen; unsigned bedeutet, dass nur positive Zahlenwerte angenommen werden können.
unsigned long letzteAenderung = 0; //der letzte Zeitpunkt, an dem eine Änderung stattfand
unsigned long pause = 50; //Pause, die nach Schalter-Aktion folgen soll
void setup() {
pinMode(buttonPin, INPUT_PULLUP); //Schalter
pinMode(ledPin, OUTPUT); //interne LED
digitalWrite(ledPin, ledStatus); //LED erst einmal anschalten
}
void loop() {
//aktuellen Schalter-Messwert lesen
int gelesen = digitalRead(buttonPin);
//...Wenn der Schalter-Status sich geändert hat (durch drücken oder auch prellen)
if (gelesen != letzterButtonStatus) {
// setze den Timer zurück
letzteAenderung = millis();
}
if ((millis() - letzteAenderung) > pause) {
//Der aktuell-gelesene Wert kann nun als zuverlässig angesehen werden, da dieser länger als 50ms vorliegt.
if (gelesen != buttonStatus) { //falls sich der Status verändert hat...
buttonStatus = gelesen; //...setze diesen als buttonStatus
//...und verändere den LED-Status, falls der Knopf gedrückt wurde
if (buttonStatus == HIGH) {
if(ledStatus==HIGH){ledStatus=LOW;}else{ledStatus=HIGH;}
}
}
}
//Setze den neuen LED-Status
digitalWrite(ledPin, ledStatus);
//merke Dir für den nächsten Loop, was der aktuelle ButtonStatus ist.
letzterButtonStatus = gelesen;
}...Unter der Haube
Arbeiten mit der Methode millis()
Die Methode millis() zählt die Anzahl der Millisekunden seit Start des Programms (also seitdem entweder Strom durch den Arduino fließt oder seitdem das letzte mal der Reset-Knopf gedrückt wurde bzw. ein neues Programm hochgeladen wurde).
Dies stellt auch in anderen Bereichen eine Alternative zur Verwendung der delay-Methode dar. Da delay hält immer den gesamten Programmablauf auf. Man kann auf diese Weise schlecht zwei völlig unabhängige Prozesse gleichzeitig steuern.
Steuert man stattdessen Aktionen abhängig von der Zeit (im Sinne von „alle 300ms soll die Lampe ihren Status ändern, also bei 300, 600, 900 ms usw.“), so kann man auch mehrere Aktionen gleichzeitig laufen lassen. Entwickelt man die Idee weiter, so arbeitet man mit Timern, was hohe Ähnlichkeit damit hat, wie in der Küche eine Eieruhr zu stellen, um bei Ablauf der Uhr eine Aktion auszuführen, wonach wiederum die Eieruhr neu gestellt wird und der Prozess von vorne beginnt.
Erweitere Dein Know-How mit dem Artikel über Multitasking.
Weiter zum nächsten Tutorial!
…dass den Abschluss des Basic-Tutorials darstellt.
