In den ersten Beispielen haben wir die GPIO-Pins als Ausgänge kennengelernt, die wir auf HIGH geschaltet haben, um eine LED leuchten zu lassen. Aber GPIO steht für General Purpose Input/Output. Man kann die Pins also auch als Eingang programmieren. Dann kann festgestellt werden, ob am Eingang eine Spannung anliegt (HIGH) oder eben nicht (LOW). Der Raspberry Pi hat nur digitale Eingänge (Abhilfe zur Messung analoger Spannungen werden wir später kennenlernen), dennoch muss die anliegende Spannung nicht exakt 3,3V sein, um als HIGH erkannt zu werden, und nicht 0V, um als LOW erkannt zu werden. Bis ca. 1,4V wird als LOW erkannt, alles über 1,9V wird sicher als HIGH erkannt. Problematisch sind nur der kleine Bereich um ½ von 3,3V und ein freier Pin, an dem nichts angeschlossen ist.
Wir werden mehrere digitale Sensoren kennenlernen, die in unserem Programm einen Alarm oder eine bestimmte Aktion auslösen sollen (z.B. Bewegungsmelder). Der einfachste dieser Sensoren ist der Taster (engl. button), ein federbelasteter Schalter, der einen Schaltkreis bei Tastendruck schließt und beim Loslassen wieder öffnet.
Wenn wir einen Kontakt des Tasters mit einem GPIO-Pin verbinden und die andere mit 3,3V, so wird bei Tastendruck eindeutig das Signal HIGH erfasst. Das Problem beginnt nach dem Loslassen des Tasters. Welchen Zustand hat der GPIO dann? Einen undefinierten! Damit kann man nicht programmieren. Im ausgeschalteten Zustand sollte der GPIO also dauerhaft auf GND Potenzial liegen. Das würde jedoch zu einem Kurzschluss führen, wenn der Taster gedrückt wird. Abhilfe schafft ein Widerstand, der so groß sein muss, dass nur ein kleiner Strom fließt. Üblich sind Widerstände von 4,7 k (=4700 Ohm) oder 10 kΩ (=10.000 Ohm). Man nennt diese Widerstände Pull-down-Resistor.
Man kann den GPIO aber auch so programmieren, dass er normalerweise HIGH anzeigt und den Tastendruck gegen GND als Änderung auf LOW erkennt. Dann heißt der Widerstand Pull-up-Resistor. Und um das Ganze noch unübersichtlicher für Anfänger zu machen, haben die Raspberry Pi GPIOs einen internen Pull-up oder Pull-down-Resistor, der im Programm aktiviert oder deaktiviert werden kann. Zum Glück werden die ersten Schaltungen dadurch sehr einfach.
Der Schaltplan: Taster am Raspberry Pi
Der Programmcode: Taster am Raspberry Pi
from gpiozero import LED, Button
from signal import pause
led = LED(12)
button = Button(16)
button.when_pressed = led.on
button.when_released = led.off
pause()
Aus dem Modul gpiozero werden, mit Komma getrennt, die Klassen LED und Button importiert, dann die Objekte led und button mit den jeweiligen GPIO-Nummern instanziiert.
Anstelle der sleep()-Funktion aus dem Modul time wird pause aus dem Modul signal verwendet. sleep() würde kompletten Stillstand bedeuten, der Tastendruck würde in der Zeit nicht bemerkt. Ohne pause() würde das Programm beendet und nichts mehr geschehen.
Die Instanziierung von button war sehr einfach, weil wir nur die GPIO-Nummer angegeben haben und ansonsten die Voreinstellungen (siehe Klassendefinition nächste Zeile) verwendet haben. Wer davon abweichen möchte, muss weitere Parameter als Schlüsselwort-Argumente eingeben.
class gpiozero.Button(pin, *, pull_up=True, active_state=None, bounce_time=None,
hold_time=1, hold_repeat=False, pin_factory=None)
Weitere Einzelheiten zu gpiozero findet man hier.
Erweiterung des Versuchsaufbaus: Eine Ampelzyklus soll mit einem Raspberry Pi gestartet werden, wenn ein Taster betätigt wird.
Der Versuchsaufbau orientiert sich am ersten Beispiel. Anstelle einer LED wird die LED-Ampel verwendet. Diese hat eingebaute Vorwiderstände. Wir instanziieren drei LED-Objekte und definieren eine Funktion trafficLight, die bei Tastendruck aufgerufen wird.
Der Programmcode: Ampelzyklus am Raspberry Pi
from gpiozero import LED, Button
from signal import pause
from time import sleep
redled = LED(16)
yellowled = LED(20)
greenled = LED(21)
button = Button(12)
def trafficLight():
redled.on()
sleep(1)
yellowled.on()
sleep(1)
greenled.on()
redled.off()
yellowled.off()
sleep(1)
yellowled.on()
greenled.off()
sleep(1)
redled.on()
yellowled.off()
sleep(1)
redled.off()
button.when_pressed = trafficLight
pause()
Erweiterung: Reaktionsspiel mit zwei Tastern am Raspberry Pi
Man benötigt zwei Taster, einen Buzzer sowie eine rote und eine gelbe LED. Nach dem Start des Reaction Game leuchtet zunächst die gelbe LED. Mit time = uniform(5, 10) leuchtet nach einer zufälligen Zeit zwischen fünf und zehn Sekunden die rote LED auf. Dann können zwei Spieler jeweils ihren Taster so schnell wie möglich drücken. Wer zu früh drückt, wird beim Mogeln erwischt, der Buzzer ertönt für eine halbe Sekunde.
Der Programmcode: Reaktionsspeil mit zwei Tastern am Raspberry Pi
#! /usr/bin/python3
# Reaction Game - push button, when red LED lights-up
# based on gpiozero documentation, Basic Recipes
# enhanced to recognize cheating by Bernd Albrecht
# Red LED lights-up 5 - 10 sec after the yellow LED
from gpiozero import Button, LED, Buzzer
from time import sleep
from random import uniform
from sys import exit
led_red = LED(16)
led_yellow = LED(20)
buzzer = Buzzer(12)
player_1 = Button(23)
player_2 = Button(18)
led_yellow.on()
time = uniform(5, 10)
sleep(time)
if player_1.is_pressed:
print("Player 1 is cheating!")
buzzer.on()
sleep(0.5)
buzzer.off()
led_yellow.off()
exit()
if player_2.is_pressed:
print("Player 2 is cheating!")
buzzer.on()
sleep(0.5)
buzzer.off()
led_yellow.off()
exit()
led_red.on()
led_yellow.off()
while True:
if player_1.is_pressed:
print("Player 1 wins!")
break
if player_2.is_pressed:
print("Player 2 wins!")
break
led_red.off()