In diesem Beitrag hab ich schonmal ganz allgemein über den Raspberry Pi geschrieben, und in diesem Beitrag über ein paar allgemeine Grundlagen zur GPIO-Schnittstelle des Raspberry Pi. Dieses mal soll es nun etwas konkreter werden: Im folgenden Beitrag zeige ich anhand von Python-Beispiel-Scripten, wie man Ausgänge schalten und Eingänge lesen kann.
Inhalt
Vorbereitung
Neuere Raspbian-Images liefern eigentlich alles mit, was man benötigt, um mit der Steuerung der GPIO loslegen zu können. Sollte in Eurem Image doch noch etwas fehlen (leicht an der daraus resultierenden Fehlermeldung beim Testen zu erkennen), setzt Ihr einfach folgenden Befehl ab:
$ sudo apt-get update && sudo apt-get install python-dev && sudo apt-get install python-rpi.gpio
Vorbemerkungen zu Python
Zum Programmieren in Python eignet sich so gut wie jeder normale Texteditor. Etwas leichter wird es, wenn dieser Editor Syntax-Highlighting für Python unterstützt, sodass z.B. Befehle automatisch in einer anderen Farbe dargestellt werden, als Kommentare. Außerdem sollte der Editor das Zeilenumbruch-Zeichen des Zielsystems (hier Linux) unterstützen.
Auf meinem Mac verwende ich die kostenfreie App TextWrangler aus dem Mac App Store, die meine Ansprüche vollständig erfüllt. Für Windows fällt mir da das ebenfalls kostenfreie Notepad++ ein.
In meinen Skripten sehen die ersten zwei Zeilen eigentlich immer so aus:
#!/usr/bin/env python #coding: utf8
Die erste Zeile ist der Shebang. Er hilft dem System, den entsprechenden Code korrekt zu interpretieren und auszuführen. Zeile zwei legt den Zeichensatz fest, in dem die Scripte geschrieben sind. Ich wähle hier UTF-8, um mit Umlauten (ä, ö, ü, ß) arbeiten zu können. Das ist auch nötig, wenn man Umlaute nur in den Kommentaren verwendet.
Grundlegendes zum Umgang mit den GPIO
Das eigentliche Script beginnt mit dem Importieren der Module time
und RPi.GPIO
. time
bringt etliches an Funktionen, die mit Zeit zutun haben, mit (siehe Doku). RPi.GPIO
übernimmt für uns das Handling der GPIO (siehe Doku).
import time import RPi.GPIO as GPIO
Auf Zeile 8 legen wir die Zählweise der Pins fest. Ich bevorzuge BOARD
, denn damit kann ich die Pins einfach körperlich abzählen (bzw. einen Blick auf die Grafiken in diesem Beitrag werfen) und die Nummern entsprechend verwenden.
# Zählweise der Pins festlegen GPIO.setmode(GPIO.BOARD)
Alternativ zu dieser Zählweise kann man auch BCM
verwenden. Hier wird nachfolgend dann nicht mehr die Pin-Nummer, sondern die GPIO-Nummer angegeben.
Ausgang schalten
Nachfolgend der gesamte Code, der unseren Ausgang schalten soll. Ich verwende für dieses Script den 22. Pin (GPIO 25) und konfiguriere diesen auf Zeile 11 als Ausgang.
Im eigentlichen Programmablauf passiert folgendes: Innerhalb einer Schleife wird der Ausgang eingeschaltet, dann wird eine Zeit von 2 Sekunden abgewartet, anschließend der Ausgang wieder ausgeschaltet, wieder 2 Sekunden gewartet und der Schleifenzähler, der auf Zeile 14 auf 3 gesetzt wurde, um einen Zähler verringert. Wenn der Zähler nach dem Durchlauf noch größer 0 ist, beginnt das wieder von vorn.
#!/usr/bin/env python #coding: utf8 import time import RPi.GPIO as GPIO # Zählweise der Pins festlegen GPIO.setmode(GPIO.BOARD) # Pin 22 (GPIO 25) als Ausgang festlegen GPIO.setup(22, GPIO.OUT) # Ausgang 3 mal ein-/ausschalten i = 3 while i > 0: # Ausgang einschalten GPIO.output(22, GPIO.HIGH) # zwei Sekunden warten time.sleep(2) # Ausgang ausschalten GPIO.output(22, GPIO.LOW) # zwei Sekunden warten time.sleep(2) # Zähler für die Schleife herunter zählen i = i - 1 # Ausgänge wieder freigeben GPIO.cleanup()
Das Script könnt Ihr einfach kopieren und beispielsweise als gpio_ausgang.py
abspeichern. Dann nur noch ausführbar machen:
$ chmod +x gpio_ausgang.py
und anschließend starten:
$ sudo ./gpio_ausgang.py
Um die Funktion zu testen könnt Ihr ein beliebiges Bauteil anschließen, das sich in irgendeiner Form einschalten lässt – Vielleicht eine LED. Ich verwende ein 2-Kanal-Relais-Modul, das ich mit 3 Steckbrücken angeschlossen habe.
Die Relais sind jedoch low-aktiv – heißt: wenn man den Ausgang des Raspberry Pi ausschaltet, zieht das Relais an. Schaut man sich das Schaltbild des Relais-Moduls an, wird auch schnell klar, warum das so ist. Das muss uns hier aber nicht weiter interessieren. Es reicht erstmal, wenn wir wissen, dass es so ist. Angeschlossen wird es in meinem Beispiel so:
Die Spannungsversorgung erfolgt mit 5V und GND, Relais 1 auf dem Modul wird über den Anschluss IN1
an den GPIO25
vom Raspberry Pi angeschlossen.
Eingang lesen
Der Code zum lesen eines Einganges sieht vom Grunde her nicht viel anders aus. Dieses mal verwende ich den GPIO24
(Pin 18), der auf Zeile 10 als Eingang konfiguriert wird. Außerdem wird per Software ein Pull-Down-Widerstand hinzugeschaltet. Dieser bewirkt, dass der Eingang stets ein definiertes Signal liefert. Lässt man ihn weg und schließt einen Draht an den Pin 18 an, dessen anderes Ende frei in der Luft hängt, kann es durchaus passieren, dass der Eingang bereits Signale „empfängt“ und somit einen undefinierten Zustand einnimmt.
In einer Dauerschleife wird der Eingang abgefragt. Solange er HIGH
ist, erfolgt eine Ausgabe im Terminal. Der Raspberry Pi ist ziemlich schnell und man kann kaum so schnell gucken, wie das Terminal-Fenster vollgeschrieben wird. Um das besser darzustellen hab ich noch einen Schleifenzähler eingebaut (Zeile 13), der bei jeder Terminalausgabe mit ausgegeben wird (Zeile 20) und am Ende eines Durchlaufs hochgezählt wird (Zeile 22).
#!/usr/bin/env python #coding: utf8 import RPi.GPIO as GPIO # Zählweise der Pins festlegen GPIO.setmode(GPIO.BOARD) # Pin 18 (GPIO 24) als Eingang festlegen GPIO.setup(18, GPIO.IN, pull_up_down = GPIO.PUD_DOWN) # Schleifenzähler i = 0 # Endlosschleife while 1: # Eingang lesen if GPIO.input(18) == GPIO.HIGH: # Wenn Eingang HIGH ist, Ausgabe im Terminal erzeugen print "Eingang HIGH " + str(i) # Schleifenzähler erhöhen i = i + 1
Das Script könnt Ihr einfach kopieren und beispielsweise als gpio_eingang.py
abspeichern. Dann nur noch ausführbar machen:
$ chmod +x gpio_eingang.py
und anschließend starten:
$ sudo ./gpio_eingang.py
Das Script läuft solange, bis es mit der Tastenkombination Strg+C
abgebrochen wird.
Testen könnt Ihr das, indem Ihr einfach 3,3V am Pin 18 anlegt. Dazu stellt Ihr einfach mit einer Steckbrücke eine Verbindung zu Pin 1 her.
Angeschlossen wird das in meinem Beispiel so:
Flanken eines Eingangs abfragen (Interrupt)
Das zuvor gezeigte Beispiel, einen Eingang dauerhaft in einer Schleife abzufragen, ist natürlich nicht sehr elegant. Daher modifizieren wir den Code dahingehend, dass ein Ereignis ausgelöst wird, wenn der Eingang sich ändert.
Steigende Flanke
Auf den Zeile 26 und 27 wird das Ereignis deklariert. In diesem Fall wird Pin 18 überwacht auf die steigende Flanke (GPIO.RISING
) überwacht. Mit callback
wird definiert, was dann passieren soll. In diesem Beispiel wird die Funktion doIfHigh
aufgerufen. Da es nicht möglich ist, einer callback
-Funktion Parameter zu übergeben, schreiben wir den gewünschten GPIO in eine Variable (channel
), die wir in der Zielfunktion auslesen und entsprechend darauf reagieren können. bouncetime
gibt an, in welchem Zeitintervall der Eingang abgefragt wird und verhindert, dass das Ereignis bei prellenden Schaltern oder meiner Steckbrücke mehrfach ausgelöst wird. Wikipedia hält hierzu einen interessanten Artikel bereit.
Auf Zeile 17 wird die Funktion mit den Befehlen definiert, die bei einer positiven Flanke abgearbeitet werden sollen.
#!/usr/bin/env python #coding: utf8 import time import RPi.GPIO as GPIO # Zählweise der Pins festlegen GPIO.setmode(GPIO.BOARD) # Pin 18 (GPIO 24) als Eingang festlegen GPIO.setup(18, GPIO.IN, pull_up_down = GPIO.PUD_DOWN) # Schleifenzähler i = 0 # Ereignis-Funktion für Eingang HIGH def doIfHigh(channel): # Zugriff auf Variable i ermöglichen global i # Wenn Eingang HIGH ist, Ausgabe im Terminal erzeugen print "Eingang " + str(channel) + " HIGH " + str(i) # Schleifenzähler erhöhen i = i + 1 # Ereignis deklarieren channel = 18 GPIO.add_event_detect(channel, GPIO.RISING, callback = doIfHigh, bouncetime = 200) # Eigentlicher Programmablauf while 1: time.sleep(0.1)
Fallende Flanke
Die fallende Flanke wird mit GPIO.FALLING
abgefragt, funktioniert sonst aber genau wie die steigende.
GPIO.add_event_detect(channel, GPIO.FALLING, callback = doIfHigh, bouncetime = 200)
Steigende und fallende Flanke
Um beide Flanken abzufragen verwendet man GPIO.BOTH
.
GPIO.add_event_detect(channel, GPIO.BOTH, callback = doIfHigh, bouncetime = 200)
Hierzu passen wir das Beispiel nochmal ein wenig an, damit bei fallender Flanke ein anderer Text ausgegeben wird:
#!/usr/bin/env python #coding: utf8 import time import RPi.GPIO as GPIO # Zählweise der Pins festlegen GPIO.setmode(GPIO.BOARD) # Pin 18 (GPIO 24) als Eingang festlegen GPIO.setup(18, GPIO.IN, pull_up_down = GPIO.PUD_DOWN) # Schleifenzähler i = 0 # Ereignis-Funktion für Eingang HIGH def doIfHigh(channel): # Zugriff auf Variable i ermöglichen global i if GPIO.input(channel) == GPIO.HIGH: # Wenn Eingang HIGH ist, Ausgabe im Terminal erzeugen print "Eingang " + str(channel) + " HIGH " + str(i) else: # Wenn Eingang LOW ist, Ausgabe im Terminal erzeugen print "Eingang " + str(channel) + " LOW " + str(i) # Schleifenzähler erhöhen i = i + 1 # Ereignis deklarieren channel = 18 GPIO.add_event_detect(channel, GPIO.BOTH, callback = doIfHigh, bouncetime = 200) # Eigentlicher Programmablauf while 1: time.sleep(0.1)
Status eines Ausgangs abfragen
Manchmal ist es nötig, in manchen Situationen vielleicht auch einfacher, den Status eines Ausgangs abzufragen. Dies geschieht vom Grunde her genauso, wie man einen Eingang abfragt nur dass man die Pin-Nummer des Ausgangs angibt. Hierzu ergänzen wir das Script gpio_ausgang.py
um eine Zusätzliche Abfrage (Zeile 19-22).
#!/usr/bin/env python #coding: utf8 import time import RPi.GPIO as GPIO # Zählweise der Pins festlegen GPIO.setmode(GPIO.BOARD) # Pin 22 (GPIO 25) als Ausgang festlegen GPIO.setup(22, GPIO.OUT) # Ausgang 3 mal ein-/ausschalten i = 3 while i > 0: # Ausgang einschalten GPIO.output(22, GPIO.HIGH) # Abfragen, ob Ausgang high ist if GPIO.input(22) == GPIO.HIGH: # Wenn Ausgang HIGH ist, Ausgabe im Terminal erzeugen print "Ausgang HIGH" # zwei Sekunden warten time.sleep(2) # Ausgang ausschalten GPIO.output(22, GPIO.LOW) # zwei Sekunden warten time.sleep(2) # Zähler für die Schleife herunter zählen i = i - 1 # Ausgänge wieder freigeben GPIO.cleanup()
- Proxmox: „Failed to connect to Server“ mit Safari auf MacOS - 28. Januar 2023
- Loxone: Benachrichtigung per Telegram - 15. Januar 2022
- Telegram: Nachrichten per Bot von der Heimautomation aufs Handy - 2. Januar 2022
Pingback: GPIO Eingänge: Werte wechseln ständig zwischen 0 und 1 – Smarthome
Pingback: Drucker automatisch starten – MyBlog