Raspberry Pi.GPIO Library
RPi.GPIO ist eine plattformspezifische Python-Funktionsbibliothek für Raspberry Pi. Als GPIO (General Purpose Input/Output) wird ein in seiner Eigenschaft als Ein-oder Ausgabe zur Laufzeit programmierbarer Hardwarekontaktstift bezeichnet, der direkt an einem IC-Pin angeschlossen ist. Auf der PI 3B+ Platine ist eine DIL-40 Kontaktleiste, die den Zugriff auf die GPIOs ergmöglicht.
GPIO Schnittstellenbelegung (Pi3B+)
GPIO name | Pin | DIL - 40 | Pin | GPIO name |
---|---|---|---|---|
3.3 VDC | 1 | 2 | 5.0 VDC | |
GPIO2 | 3 | 4 | 5.0 VDC | |
GPIO3 | 5 | 6 | Ground | |
GPIO4 | 7 | 8 | GPIO14 | |
Ground | 9 | 10 | GPIO15 | |
GPIO17 | 11 | 12 | GPIO18 | |
GPIO27 | 13 | 14 | Ground | |
GPIO22 | 15 | 16 | GPIO23 | |
3.3 VDC | 17 | 18 | GPIO24 | |
GPIO10 | 19 | 20 | Ground | |
GPIO9 | 21 | 22 | GPIO25 | |
GPIO11 | 23 | 24 | GPIO28 | |
Ground | 25 | 26 | GPIO27 | |
DNC | 27 | 28 | DNC | |
GPIO5 | 29 | 30 | Ground | |
GPIO6 | 31 | 32 | GPIO12 | |
GPIO13 | 33 | 34 | Ground | |
GPIO19 | 35 | 36 | GPIO16 | |
GPIO26 | 37 | 38 | GPIO20 | |
Ground | 39 | 40 | GPIO21 |
Eigenschaften
PIO-Typ | Pins | Belastbarkeit | Anmerkungen |
---|---|---|---|
DNC | 27, 28 | (Do Not Connect), Schnittstelle nicht belegt, für zukünftige Entwicklung | |
Power 3.3 | 1,17 | Imax 50 mA, | HIGH-Referenz für 3.3 CMOS-Logik, keine Stromquelle |
Power 5.0 | 2, 4 | +VCC, Imax abh. vom verwendeten Netzteil | 5.0V TTL-Logik (74AHCT541 an 3.3V betreibbar) |
GPIO | 7, 11, 12, 13, 15, 16, 18, 22, 29, 31, 32, 33, 35, 36, 37, 38, 40 | Als Eingang: Steuerspannung Umax =3.3V darf nicht überschritten werden. Als Ausgang typ. Strom 2-3mA, Imax=16mA, jeweils pro GPIO-Pin | Gesamt-Laststrom über alle verwendeten GPIOs soll 50mA kurzzeitig nicht überschreiten |
I2C | 3, 5 | Anschluss an bidirektionalen 2-Draht-Bus (Taktleitung SCL und Datenleitung SDA) | |
UART | 8, 10 | serielle Schnittstelle (send TXT0, receive RXD0) | |
SPI | 19, 21, 23, 24, 26 | Eingangsspannung der Fremdschnittstelle unter 3.3V | serielle 2- bzw. 3-Draht-Busleitung für Synchronous Serial Protocol (MOSI, MISO, SCLK, CE0, CE1) |
Ground | 6, 9 14 20, 30, 34, 39 | Schaltungsmasse |
pi@raspberrypi:~$ gpio readall
RPi.GPO Funktionen
Importieren
Die Funktionsbibliothek GPIO wird mit folgender Anweisung am Anfang eines Python-Programms eingebunden:
import RPi.GPIO as GPIO
Mit dieser Anweisung kann die Bibliothek im nachfolgenden Coding als GPIO referenziert werden. Die geladene Version der Bibliothek RPI.GPIO gibt GPIO.VERSION zurück.
Zu beachten: Die Nutzung der Bibliothek setzt root-Rechte (Nutzer pi) voraus. Andere Nutzer müssen in die Gruppe GPIO eingetragen werden:
sudo usermod -a -G gpio <Username>
PIN Belegungsschema
RPi.GPIO bietet zwei Möglichkeiten, um die PIN-Belegung anzusprechen:
GPIO.setmode(GPIO.BOARD)
GPIO.setmode(GPIO.BCM)
Eine der beiden Varianten muss gewählt werden. Der Parameter BOARD stellt unabhängig von der Board Version des Pi die PIN-Nummernbelegung der 40-pol. Stiftleiste (THT GPIO pin header) zur Verfügung. Der BCM Parameter adressiert die Broadcom SOC Channel (Kurz-)Bezeichnungen, die GPIO im Namen enthalten. In den folgenden Beispiele mit python-Funktionsaufrufen der steht "nr" als Platzhalter unabhängig vom gewählten Nummerierungsmodus für den Parameter I/O-Kanal.
Setup von Ein-/Ausgabekanälen
Die Raspberry CPU stellt in der board revision 3B+ am pin header neben Spannungs-und Massekontakten (power, ground) 17 solcher frei programmierbaren I/O pins zur Verfügung. Dazu kommen weitere GPIO-Pins für die Kommunikationsprotokolle SPI, und I2C sowie für die serielle UART-Schnittstelle.
Die I/O-Eigenschaft legen die folgenden Anweisungen fest:
GPIO.setup(nr, GPIO.OUT) legt Kanal nr als Ausgabe fest
GPIO.setup(nr, GPIO.IN) legt nr als Inputkanal fest
GPIO.OUT legt einen Ausgangskanal fest, GPIO.IN einen Eingabekanal. Der Parameter nr muss bei setmode(GPIO.BCM) numerisch sein, z.B. 15, bei setmode(GPIO.BOARD) dagegen alfanumerisch. Die Entsprechung zu 15 würde dann GPIO22 lauten.
Ein-/Ausgabegruppen bestimmen
Ein-Ausgabekanäle können wie beschrieben einzeln, aber wie folgt auch gruppenweise festgelegt werden:
channel_list = [nr_1,nr_2...]
Die Gruppenmember nr_1...nr_n können in dieser Zuweisung beliebig gewählt werden, zu beachten ist, dass die korrekte Notation für BOARD bzw. BCM beachtet wird:
Channel_list = [22,15,18] bzw.
Channel_list = [GPIO25,GPIO22,GPIO24]
Die gemeinsame I/O-Eigenschaft - beispielsweise als Ausgang - kann dann gesetzt werden mit:
GPIO.setup(channel_list, GPIO.OUT)
Inputkanal lesen
Der Inputlevel kann die Werte 0 oder GPIO.LOW oder False bzw. 1 oder GPIO.HIGH oder True annehmen, entsprechen den 0V- und 3.3V-Pegeln.. Die internen Logikbausteine schalten tatsächlich jedoch schon bei etwa 0,8V auf LOW, bei über 1,3 V auf High. (Ist ein Inputpin nicht extern beschaltet, zum Beispiel nicht via Vorwiderstand auf ein defaultlevel gezogen, kann er auch einen zufällig sich ändernden Wert annehmen, siehe unter Pull-up/Pull-down-Widerstände). Offene Eingänge sind empfindlich für induzierte Überspannungen und statische Entladungen. Das Auslesen des Inputlevels geschieht mit der folgenden Anweisung:
GPIO.input(nr] nr kann entweder ein einzelner Kanalname oder ein vordefinierter Name für eine Kanalgruppe sein. Beispiele: GPIO.input(22) GPIO.input(GPIO25) und GPIO.input(Channel_list)
Input Varianten
Polling
Abtasten des Signals anhand eines Triggerlevels oder zu festgelegten Zeitabständen
Eine Momentaufnahme des Werts von Kanal nr liefert die Abfrage:
if GPIO.input(nr):
print('Input HIGH')
else:
print('Input LOW')
Ein Eingangskanal nr kann daraufhin abgehorcht werden, ob eine Wertänderung auf HIGH eintritt. Unterstellt, dass nr mit einem Taster beschaltet ist, der beim Drücken auf HIGH zieht, kann dies mit folgendem Pythoncode geschehen:
import RPi.GPIO as GPIO
import time #Python Standard Library
while GPIO.input(nr) == GPIO.LOW
time.sleep(0.01) #wait 10 ms
Die Bibliothek time muss für die sleep Funktion hinzugeladen werden. Sie sorgt dafür, dass die CPU nur alle 10 Millisekunden mit der Abfrage belastet wird. Solange immer wieder das Level LOW festgestellt wird, passiert sonst nichts.
Interrupts
Interrupts nutzen Werteänderungen an der steigenden oder fallenden Signalflanke (edge), wie sie ein manueller Schalter, Taster oder ein Bauelement (z. B. ein TTL-Logikbaustein) liefert. Bei manuellen Schaltern, Relais etc. ist sicherzustellen, dass eine saubere Flanke vorliegt (pass. Anstiegszeit, kontrolliertes Prellverhalten), da es sonst zu mehrfacher Auslösung von Interrupt-Events kommen kann. RPi.GPIO unterstützt die Entprellung von Schaltern (switch bounce) softwareseitig durch den Parameter bouncetime in der Funktion GPIO.add_event_detect():
GPIO.add_event_detect(nr, GPIO.RISING, bouncetime=100) #ignore further rising edges for 100 ms
Wie die Beispiele zeigen, handelt es sich um digitale Signalzustände. Bei analogen Eingangssignalen unterschiedlicher Amplitude und Frequenz, bei Lade-/Entladekurven muss eine Signalvorbehandlung erfolgen, die erst einen Event definiert (Triggerlevel und -frequenz). Für die Abfrage eines Tasterzustands liefert RPi.GPIO drei Funktionen:
Flankendetektor
Die Funktion wait_for_edge() wartet auf steigende Signalflanken und kann das Polling im obigen Beispiel ersetzen:
GPIO.wait_for_edge(nr, GPIO.RISING)
analog stehen auch Funktionen für die abfallende Flanke oder für steigend und fallend zur Verfügung:
GPIO.wait_for_edge(nr, GPIO.FALLING)
GPIO.wait_for_edge(nr, GPIO.BOTH)
Event Time-out
Das Warten auf Signalflanken (kein Event) kann durch einen Time-out begrenzt werden:
nr = GPIO.wait_for_edge(nr, GPIO_RISING, timeout=10000)
if nr is None:
break
else:
continue
Modaler Event Detektor
Die Funktion event_detected() kann in einem Loop gemeinsam mit anderen Aufgaben sicherstellen, daß ein Event zu einem Zeitpunkt nicht verpaßt wird, währenddessen die CPU mit einer anderen Task beschäftigt ist:
GPIO.add_event_detect(nr, GPIO.RISING)
do_something()
if GPIO.event_detected(nr):
button_pressed = True
Events können erkannt werden für die Zustandsänderungen
GPIO.RISING, GPIO_FALLING, und GPIO.BOTH. Die Erkennung kann abgebrochen werden mit der Anweisung:
GPIO.remove_event_detect(nr)
Rückruffunktion
Events können auch mit der Rückruffunktion add_event_detect() in einem Parallelprozeß zum Hauptprogramm aufgefangen werden. Die Struktur des Ablaufs verdeutlicht folgendes snippet:
def my_callback(nr):
(...)
GPIO.add_event_detect(nr, GPIO.RISING, callback=my_callback)
(...)
Pull-up /Pull-down- Widerstände
Eingangskanäle ohne externe Beschaltung sind hochohmig und unterliegen somit Leitungseinstreuungen, so daß sie zufällige Werteänderungen (floating) zeigen, die aussagelos sind und Auswertelogiken stören können. Um dies zuvermeiden, werden Eingangskanäle normalerweise extern durch einen geeignet dimensionierten Vorwiderstand auf ein vordefiniertes Potential gezogen. Für RPi kann der Pull-up-Widerstand für 3.3V-Potential mit 10 Kiloohm bemessen werden. Die externe Beschaltung eines Pull-up-/-down-Widerstand kann ersetzt werden durch die folgende Anweisung an das RPi.GPIO:
GPIO.setup(nr, GPIO.IN, pull_up_down=GPIO.PUD_UP)
setzt für den Eingangskanal nr einen Pull-up-Widerstand;
analog kann dieser Eingang auf 0V-Potential gezogen werden mit der Anweisung
GPIO.setup(nr, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
Ausgangslevel setzen
Die folgenden Anweisung setzt den Ausgangskanal nr auf einen Wert value:
GPIO.output(nr, value) wobei value boolsche Werte
0, 1 bzw. True False als auch Ausgangspotentiale
GPIO.LOW bzw GPIO.HIGH sein können.
Auch hier können Ausgangswerte gruppenweise gesetzt werden:
PGIO.output(channel_list, GPIO.LOW)
Die Werte für jeden einzelnen Member der Gruppe können unterschiedlich belegt werden (Reihenfolge!):
GPIO.output(channel_list, GPIO.HiGH, GPIO.LOW, GPIO.LOW setzt die Ausgänge 22 auf
HIGH und 15, 18 auf LOW
Rücksetzen von I/O-Kanälen
Am Ende des Programms/beim Programmabbruch mit Strg+C sollten die I/O-Kanäle zurückgesetzt werden, denn die I/O-Eigenschaften der GPIO bleiben bestehen. Alle genutzten Kanäle und auch der GPIO-Nummerierungsmodus werden zurückgesetzt mit:
GPIO.cleanup()
Cleanup kann auch auf Kanalgruppen angewandt werden:
GPIO.cleanup( (channel_list) )
# kontrollierter Abbruch des Programms durch Taste Strg-C except KeyboardInterrupt: GPIO.cleanup() sys.exit()
Das Auslesen des Status eines Ausgangspins nr kann mit der GPIO.input()-Funktion erfolgen:
GPIO.output(nr, not GPIO.input(nr))
Pulsweitenmodulation (Pulse Width Modulation PWM)
Bei der Pulsweitenmodulation (Pulse Width Modulation PWM) bildet ein PWM-Generator ein Rechtecksignal mit variablem Tastgrad (duty cycle). Die RPi.GPIO-Bibliothek erzeugt eine Instanz eines PWM-Generators z.B. am Pin 22 mit der Frequenz 50 (in Hertz) durch folgenden Aufruf:
p = GPIO.PWM(22, 50)
Die Instanz kann gestartet werden durch
p.start(dc) wobei
dc (duty cycle, Tastgrad) in % zwischen größer 0 und 100 angegeben werden kann.
Der Generator wird mit
p.stop() angehalten.
Frequenz und Tastgrad können geändert werden mit:
p.ChangeFrequency(freq), wobei freq die neue Frequenz in Hertz darstellt.
Die Änderung des Tastgrads erfolgt mit
p.ChangeDutyCycle(dc), wobei der neue Tastgrad in % zwischen größer 0 und 100 liegen kann.
Ein gepulstes Rechteck mit niedriger Frequenz am Ausgang kann im einfachsten Fall für Blink- und Dimmanwendungen genutzt werden. Eine Leuchtdiode kann an Pin 12 mit einem wie folgt dimensionierten PWM zum Blinken gebracht werden:
p = GPIO.PWM(12, 1).
Dieselbe LED benötigt zum Auf-und Abschwellen der Leuchtkraft einen Endlos-Loop, in dem der Tastgrad kontinuierlich auf- und abgefahren wird. Bei hohem Tastgrad befindet sich das Leuchtmaximum:
GPIO.PWM(12, 50)
p.start(0)
try:
while 1:
for dc in range(0, 101, 5):
p.ChangeDutyCycle(dc)
time.sleep(0.1)
for dc in range(100, -1, -5):
p.ChangeDutyCycle(dc)
time.sleep(0.1)
sleep ist eine Funktion der Standardbibliothek time, die ebenso wie RPi.GPIO importiert werden muß.
I/O Pin-Prüfung
GPIO.setmode(GPIO.BOARD)
func = GPIO.gpio_function(nr)
Die Funktion gibt zu Pin nr einen Wert zurück aus: GPIO.IN, GPIO.OUT, GPIO.SPI, GPIO.I2C, GPIO.HARD_PWM, GPIO.SERIAL, GPIO.UNKNOWN
Fehler- und Warnmeldungen
Zur Laufzeit können die von Python-scripten gesetzten I/O-Eigenschaften kollidieren. Aus diesem Grund wird eine Warnung ausgegeben, wenn versucht wird, den defaultwert (input) zu ändern. Die Ausgabe dieser Warnung kann gesteuert werden. Das Setzen des Parameters False führt dazu, dass die Ausgabe unterdrückt wird:
GPIO.setwarnings([True, False])
Quellen:
Sourceforge raspberry-gpio-python/Wiki
The Python Standard Library
ARM PrimeCell GPIO (PL061) Technical Reference Manual
IIC, Inter-IC bzw. Inter Integrated Circuit Bus
GPIO
BROADCOM BCM2835 ARM Peripherals