
Taster abfragen und richtig entprellen
Monday, der 15. June 2015Oft möchte man einen Arduino per Tastendruck steuern. Zum Glück ist das Anschließen eines Tasters sehr einfach und es wird mit der Arduino IDE sogar schon ein fertiger Sketch mitgeliefert, den man unter
Beispiele–>02.Digital–>Button
finden kann. Der Quellcode sieht so aus:
/* Button Turns on and off a light emitting diode(LED) connected to digital pin 13, when pressing a pushbutton attached to pin 2. The circuit: * LED attached from pin 13 to ground * pushbutton attached to pin 2 from +5V * 10K resistor attached to pin 2 from ground * Note: on most Arduinos there is already an LED on the board attached to pin 13. created 2005 by DojoDave <http://www.0j0.org> modified 30 Aug 2011 by Tom Igoe This example code is in the public domain. http://www.arduino.cc/en/Tutorial/Button */ // constants won't change. They're used here to // set pin numbers: const int buttonPin = 2; // the number of the pushbutton pin const int ledPin = 13; // the number of the LED pin // variables will change: int buttonState = 0; // variable for reading the pushbutton status void setup() { // initialize the LED pin as an output: pinMode(ledPin, OUTPUT); // initialize the pushbutton pin as an input: pinMode(buttonPin, INPUT); } void loop() { // read the state of the pushbutton value: buttonState = digitalRead(buttonPin); // check if the pushbutton is pressed. // if it is, the buttonState is HIGH: if (buttonState == HIGH) { // turn LED on: digitalWrite(ledPin, HIGH); } else { // turn LED off: digitalWrite(ledPin, LOW); } }
Neben einem Arduino braucht man natürlich noch einen Taster und einen Widerstand. Der Widerstand verbindet Pin 2 mit Masse und zieht die Spannung an dem Pin auf 0V. Wenn man den Taster betätigt wird der Pin an die Versorgungsspannung gelegt (5V) und die Spannung am Pin steigt quasi sofort auf 5V. Diese Spannung wird vom Arduino erkannt und kann über die Funktion digitalRead ausgelesen werden.
Der Sketch versetzt den Pin 2 in Inputmodus und Pin 13 in den Outputmodus. An Pin 2 befindet sich natürlich unser Taster und an Pin 13 ist auf dem Arduino sowieso schon eine LED eingebaut. In der Loop Schleife wird kontinuierlich über die Funktion digitalRead der Pin 2 überprüft. Die Variable buttonstate wird dann auf 0 oder 1 gesetzt, je nachdem welchen Wert digitalRead zurückgibt. Sollte die Variable auf 1 gesetzt werden, wird über de LED an geschaltet ansonsten wird sie ausgeschaltet.
Das ganze funktioniert an sich auch ganz gut, wenn man die Taste drückt leuchtet die LED und wenn man sie loslässt geht sie wieder aus. Zum ein und ausschalten eignet sich das allerdings noch nicht. Das Programm merkt sich Tastendrücke nicht. Am besten wäre es, wenn man bei jedem Tastendruck zwischen einem An- und Aus-Zustand wechseln könnte.
Einzelne Tastendrücke
Ob der Taster bereits gedrückt wurde oder nicht, speichern wir in eine Variable. Sowas könnte z.B. so aussehen:
/* Button Turns on and off a light emitting diode(LED) connected to digital pin 13, when pressing a pushbutton attached to pin 2. The circuit: * LED attached from pin 13 to ground * pushbutton attached to pin 2 from +5V * 10K resistor attached to pin 2 from ground * Note: on most Arduinos there is already an LED on the board attached to pin 13. */ // constants won't change. They're used here to // set pin numbers: const int buttonPin = 2; // the number of the pushbutton pin const int ledPin = 13; // the number of the LED pin // variables will change: int buttonState = LOW; // variable for reading the pushbutton status int buttonread = 0; void setup() { // initialize the LED pin as an output: pinMode(ledPin, OUTPUT); // initialize the pushbutton pin as an input: pinMode(buttonPin, INPUT); Serial.begin(9600); } void loop() { // read the state of the pushbutton value: buttonread = digitalRead(buttonPin); // check if the pushbutton is pressed. // if it is, the buttonState is HIGH: if (buttonread == HIGH) { //Check if Button was pressed before and being pressed now if (buttonState == LOW) { // turn LED on: digitalWrite(ledPin, HIGH); buttonState = HIGH; Serial.println("Button pressed"); } } else { if (buttonState == HIGH) { digitalWrite(ledPin, LOW); buttonState = LOW; } } }
- Am Anfang wird buttonState mit LOW initialisiert. Diese Variable speichert, ob der Taster schon gedrückt wurde und LOW zeigt an, dass noch nicht gedrückt wurde.
- Es wird wieder mit digitalRead das Betätigen des Tasters abgefragt. Ist buttonState bereits im Zustand LOW, dann wird die LED eingeschaltet, buttonState wechselt dann auf HIGH und wir bekommen eine Meldung über den Serial Port mit dem Befehl Serial.println . Auch beim loslassen des Tasters bleibt die LED an.
- Drückt man nochmal auf den Taster, dann ist der Zustand von buttonState bereits HIGH und die else if Bedingung ist erfüllt und wird ausgeführt. Innerhalb dieser Bedingung wird der Zustand von buttonState wieder auf LOW gesetzt und die LED ausgeschaltet.
An sich funktioniert das auch, aber…
Häufig kommen mehrere Nachrichten über die serielle Schnittstelle, obwohl man den Taster nur einmal gedrückt hat. Eigentlich sollte das nicht passieren, selbst wenn man die Taste gedrückt hält, sollte der Code für buttonState == LOW nur einmal ausgeführt werden.
Das obige Bild z.B. ist nach einem einzigen Tastendruck. Was ist passiert?
Prellen
Wenn man den Taster betätigt schließt man zwar den Stromkreis, aber dies geschieht nicht sofort. Die mechanischen Bauteile im Taster sind nicht perfekt und es kann ein bisschen dauern bis der Stromkreis komplett geschlossen ist. Dieses Verhalten nennt man auch „Prellen„. Wie man sich vorstellen kann, ist das ziemlich schlecht. Eine Tastatur würde z.B. pro Tastendruck mehrere Zeichen hintereinander ausgeben. Die Korrektur dieses Verhalten heißt dementsprechend „Entprellen“ und es gibt dafür mehrere Ansätze, sowohl durch elektrisch als auch Softwaretechnisch.
Die einfachste Softwarelösung besteht darin, nach dem Einlesen des Tasters einen kurzen Moment zu warten und dann, falls dieser HIGH war, den Taster noch einmal einzulesen. Sollte der Taster immer noch auf HIGH sein, dann kann der Arduino sich sehr sicher sein, dass es ein echter Tastendruck war.
if (buttonread == HIGH) { //Check if Button was pressed before and being pressed now delay(5); if ((buttonState == LOW) && (digitalRead(buttonPin)) ) { if (digitalRead(buttonPin)) { // turn LED on: digitalWrite(ledPin, HIGH); buttonState = HIGH; Serial.println("Button pressed"); } } }
Wie lange man genau warten muss, hängt von Fall zu Fall ab und ist nicht besonders kritisch. Für gewöhnlich reichen 5 bis 50 Millisekunden.