01 Digitaler Input / Output
Digitaler Input/Output
Unter digitalem Input/Output versteht man Schaltungen, welche lediglich zwei Zustände kennen: EIN oder AUS. Im Falle des Arduino entspricht der Zustand EIN dabei einer elektrischen Spannung von 5V und AUS einer Spannung von 0V. Je nachdem ob man diese Zustände einliesst oder ausgibt spricht man von Input oder Output. Am Arduino verwenden wir vor allem die Digitalen PINs (D0-D13) für digitale Schaltungen. Es können jedoch auch die Analogen PINs verwendet werden, falls noch mehr Ein- bzw. Ausgänge benötigt werden.
Die entsprechenden Funktionen für das Einlesen bzw. Ausgeben lauten:
digitalRead(PIN)
digitalWrite(PIN, Wert)
PIN = Der zu lesende oder zu schreibende Pin
Wert = HIGH (EIN) oder LOW (AUS)
Im Folgenden werden wir einen Tastendruck mit dem Arduino einlesen. Dabei gibt es prinzipiell zwei Möglichkeiten, welche hier illustriert sind:
Der Unterschied zwischen negativer und positiver Logik besteht in der Tatsache, dass bei einer negativen Logik der Wert am digitalen Pin auf 0V (LOW) gezogen wird, wenn man den Taster drückt. Wird der Taster dagegen nicht gedrückt so fliesst ein kleiner Strom nach 5V und zieht den Wert am digitalen Pin nach oben (HIGH). Bei der positiven Logik ist dies genau anders herum. Das ist auch der Grund warum wir bei dieser Schaltung sog. Pullup- bzw. Pulldown Widerstände verwenden. Diese sorgen dafür, dass die Spannung abfällt = pulldown (oder ansteigt = pullup) wenn der Taster nicht gedrückt ist und wir somit wir auch wirklich 5V bzw. 0V einlesen werden wenn wir den Taster drücken.
Um einen Taster am Arduino einzulesen kann eine der beiden Logiken verwendet werden – beide funktionieren. Der Code lautet dann wie folgt:
#define TASTER 7 // Taster an digitalPin 7
#define LED 13 // LED an digitalPin 13
void setup()
{
pinMode(TASTER, INPUT); // TasterPin als Input nutzen
pinMode(LED, OUTPUT); // LEDPin als Output nutzen
}
void loop()
{
digitalWrite(LED, digitalRead(TASTER)); // LED anmachen, wenn Taster gedrückt
}
Debounce
Es kann passieren, dass der Befehl digitalRead() zu schnell hintereinander gelesen wird und wir deshalb mehrere "Pushs" erhalten. Dies kann vermieden werden, wenn wir ein sog. Debouncing hinzufügen. Diese arbeitet mit der Funktion millis() um sich den letzten Zeitpunkt des Drückens zu merken und ein kleine Verzögerung hinzuzufügen.
#define BUTTON 2 // Taster an Pin 2
#define LED 13 // LED an Pin 13
int ledState = HIGH; // Aktueller Status der LED
int buttonState; // Aktueller Status des Tasters
int lastButtonState = LOW; // Der letzte Staus des Tasters
long lastDebounceTime = 0; // Die letzte Zeit als der Taster gedrückt wurde
long debounceDelay = 50; // Die Verzögerung des Tasters
void setup()
{
pinMode(BUTTON, INPUT);
pinMode(LED, OUTPUT);
}
void loop()
{
int reading = digitalRead(BUTTON); // Taster einlesen und in reading speichern
if (reading != lastButtonState) // Vergleich ob der Status sich verändert hat
{
lastDebounceTime = millis(); // Speichern der Zeit
}
if ((millis() - lastDebounceTime) > debounceDelay) // Checken der vergangenen Zeit
{
buttonState = reading; // Zuweisen der Wertes
}
digitalWrite(LED, buttonState); // Die LED ein oder aus schalten
lastButtonState = reading; // Speichert den aktuellen Status
}
Interner PullUp Widerstand
Bis jetzt haben wir einen extra 10kOhm Widerstand verwendet um die Spannung am PIN anzuheben wenn der Taster nicht gedrückt wurde. Der Microkontroller verfügt aber auch über eigene, interne Pullup Widerstände, die sich per Programmierung aktivieren lassen. Diese Methode funktioniert nur bei einer negativen Logik ist dann aber sehr komfortabel, da nur noch ein Taster und kein Widerstand benötigt wird. Denn internen PullUp aktiviert man, indem direkt nach dem Aufruf von pinMode() im setup() die Funktion digitalWrite(pin, HIGH) gerufen wird.
#define TASTER 2
void setup()
{
pinMode(TASTER, INPUT);
digitalWrite(TASTER, HIGH);
}
Aufgaben
1. Nutzt den Taster um zwischen zwei LEDs hin- und her zu wechseln.
2. Programmiert den Code so, dass erst nach viermaligem drücken der Wechsel erfolgt.
3. Programmiert einen Papagei, welcher eine eingegebene Sequenz wiederholt.
#define BUTTON 2 // Button PIN definieren
#define LED_ONE 12 // LED 1 an PIN 12
#define LED_TWO 11 // LED 2 an PIN 11
boolean whichLed = false; // Hier speichern wir, welche LED angesteuert werden soll
boolean buttonState = false; // Hier speichern wir den momentanen Button Zustand
long debounceDelay = 200; // Diese Zeit bestimmt die Verzögerung beim Drücken des Buttons
long lastDebounceTime = 0; // Hier speichern wir den Zeitpunkt, an welchem der Button gedrückt wurde
void setup()
{
pinMode(BUTTON, INPUT); // PINs als Aus-/Eingänge setzen
pinMode(LED_ONE, OUTPUT); // ...
pinMode(LED_TWO, OUTPUT); // ...
}
void loop()
{
// Wenn der Button gedrückt wird und seit dem leten Mal die Zeit lastDebounceTime
// vergangen ist, dann akzeptiere den Tastendruck. buttonState verhindert das wiederholte
// Ausführen des Events.
if(digitalRead(BUTTON) == LOW && (millis()-lastDebounceTime)>debounceDelay && buttonState == false)
{
whichLed =! whichLed; // Die leuchtende LED wechseln
lastDebounceTime = millis(); // Den aktuellen Zeitpunkt speichern
buttonState = true; // buttonState auf true setzen
}
// Wenn der Button wieder losgelassen wird, kann buttonState wieder freigegeben werden
if(digitalRead(BUTTON) == HIGH)
{
buttonState = false; // buttonState auf false setzen
}
if(whichLed == true) // Erste LED anschalten, zweite aus
{
digitalWrite(LED_ONE, HIGH);
digitalWrite(LED_TWO, LOW);
Serial.println("Here");
}
else // Zweite LED anschalten, erste aus
{
digitalWrite(LED_ONE, LOW);
digitalWrite(LED_TWO, HIGH);
}
}
#define BUTTON 2 // Button PIN definieren
#define LED_ONE 12 // LED 1 an PIN 12
#define LED_TWO 11 // LED 2 an PIN 11
boolean whichLed = false; // Hier speichern wir, welche LED angesteuert werden soll
boolean buttonState = false; // Hier speichern wir den momentanen Button Zustand
long debounceDelay = 200; // Diese Zeit bestimmt die Verzögerung beim Drücken des Buttons
long lastDebounceTime = 0; // Hier speichern wir den Zeitpunkt, an welchem der Button gedrückt wurde
int counter = 0; // Dieser counter zählt, wie oft der Button gedrückt wurde
void setup()
{
pinMode(BUTTON, INPUT); // PINs als Aus-/Eingänge setzen
pinMode(LED_ONE, OUTPUT); // ...
pinMode(LED_TWO, OUTPUT); // ...
}
void loop()
{
// Wenn der Button gedrückt wird und seit dem leten Mal die Zeit lastDebounceTime
// vergangen ist, dann akzeptiere den Tastendruck. buttonState verhindert das wiederholte
// Ausführen des Events.
if(digitalRead(BUTTON) == LOW && (millis()-lastDebounceTime)>debounceDelay && buttonState == false)
{
counter++; // Den counter um 1 erhöhen
lastDebounceTime = millis(); // Den aktuellen Zeitpunkt speichern
buttonState = true; // buttonState auf true setzen
}
// Wenn der Button wieder losgelassen wird, kann buttonState wieder freigegeben werden
if(digitalRead(BUTTON) == HIGH)
{
buttonState = false; // buttonState auf false setzen
}
// Wenn der counter auf 4 steht (der Button also 4 mal gedrückt wurde), wechsele die
// LED und setze den counter wieder auf 0.
if(counter == 4)
{
whichLed =! whichLed; // Die leuchtende LED wechseln
counter = 0;
}
if(whichLed == true) // Erste LED anschalten, zweite aus
{
digitalWrite(LED_ONE, HIGH);
digitalWrite(LED_TWO, LOW);
}
else // Zweite LED anschalten, erste aus
{
digitalWrite(LED_ONE, LOW);
digitalWrite(LED_TWO, HIGH);
}
}
#define BUTTON 2
#define LED_ONE 13
int buttonState [40];
long buttonTime [40];
int lastButtonState = HIGH;
long lastTimePressed = 0;
int timeOutDelay = 2000;
int counter = 0;
boolean replay = false;
int sequenceLenght = 0;
void setup()
{
pinMode(BUTTON, INPUT);
digitalWrite(BUTTON, HIGH);
pinMode(LED_ONE, OUTPUT);
}
void loop()
{
int reading = digitalRead(BUTTON);
if(reading != lastButtonState)
{
replay = false;
buttonState[counter] = reading;
buttonTime[counter] = millis();
lastTimePressed = millis();
lastButtonState = reading;
counter++;
}
if((millis() - lastTimePressed) > timeOutDelay)
{
sequenceLenght = counter;
counter = 0;
replay = true;
}
if(replay == true)
{
for(int i=0; i<sequenceLenght-1; i++)
{
digitalWrite(LED_ONE, !buttonState[i]);
delay(buttonTime[i+1]-buttonTime[i]);
}
replay = false;
digitalWrite(LED_ONE, LOW);
}
}
Serielle Kommunikation
Da das Arduino über eine
serielle Schnittstelle verfügt können wir diese auch nutzen um uns momentane Werte des Arduino abzurufen oder später auch direkt mit dem Computer zu kommunizieren. Um die Serielle Schnittstelle zu nutzen benötigen wir im setup() lediglich die Funktion Serial.begin() aufzurufen. Danach können wir uns mit der Funktion Serial.print() bzw. Serial.println() beliebige Werte ausgeben lassen. Die Arduino IDE hat dazu auch einen eigenen Monitor. Ein Beispiel für die serielle Kommunikation sieht so aus:
void setup()
{
Serial.begin(9600); // Serielle Schmittstelle mit 9600 kbs initialisieren
}
void loop()
{
Serial.print("Atuelle Systemzeit: ")
Serial.print(millis());
Serial.println();
delay(100);
}
Weitere Informationen
Arduino: DigitalPins
Tom Igoe: Digital Input & Output