GPIO mit Python

Nachdem die bisherigen Kapitel dieses Tutorials eher von allgemeiner Natur waren, wird es diesmal etwas Raspberry Pi spezifischer, in dem wir uns den GPIO Pins zu wenden.

1Python Programmierkurs
2Python: Methoden
3Kontrollstrukturen
4Strings in Python
5Container
6Objekte in Python
7Module
8Exceptions in Python
9Typkonvertierung
10Python und Dateien
11Datum und Zeit mit Python verarbeiten
12Multithreading
13Netzwerk in Python
14Logging in Python
15GPIO
16Automatische Tests
17Datenbanken mit Python
18Python: Generatoren und List Comprehension
19Python: Webseiten mit Flask
20Python virtuelle Umgebungen
21Interrupts & Signale
22NumPy
23Matplotlib
24match
25Reguläre Ausdrücke Python Tutorial Teil 25

Material

Folgendes Material benutze ich in diesem Beitrag

  • Raspberry Pi 4 (theoretisch müsste es auch mit dem 3B klappen)
  • eine rote Leuchtdiode
  • Einen 330 Ohm Vorwiderstand (220 Ohm würden auch reichen, hab ich aber gerade keinen frei)
  • Ein Breadboard
  • einige Jumper Kabel weiblich-männlich (f-m)
  • zwei Jumper-Kabel männlich-männlich (m-m)
  • ein Taster zweipolig, quadratisch, steckbar

Falls du lieber eine LED in einer anderen Farbe benutzen möchtest, solltest du den Vorwiderstand mit einer anderen Ohmzahl wählen.

GPIO

Der GPIO Header beim Raspberry Pi 4B besteht aus zwei parallelen 20-poligen Stiftleisten. Die Belegung der Pins haben andere Hersteller von Single Board Computern inzwischen übernommen, so dass man von einem de facto Standard sprechen kann. Das Pinout ist in dieser Grafik dargestellt. Zur besseren Orientierung habe ich mir einen Stacking-Header mit Farbcodierung auf die GPIO Leiste gesteckt. Einige SBC Hersteller machen sowas von Werk aus, ich hoffe, die Raspberry Pi Foundation zieht mit denen gleich.

Raspberry Pi 4 GPIO Pinout (Bild von pinout.xyz)
Raspberry Pi 4 GPIO Pinout (Bild von pinout.xyz)

Uns interessiert in diesem Beispiel vor allem der GPIO Pin 23. Er ist durch nichts anderes belegt und eignet sich für die Ansteuerung einer Leuchtdiode. Ich benutze für diesen Kursteil den Raspberry Pi mit DietPiOS.

Vorbereitung

Zunächst müssen wir die notwendige Bibliothek für Python 3 installieren.

sudo apt install python3-rpi.gpio

Damit der User dietpi Zugriff auf die GPIO Header erhält, muss er in die Gruppe gpio eingetragen werden

sudo usermod -aG  gpio dietpi

Wenn du dies mit dem User dietpi ausführst, musst du dich jetzt zunächst einmal aus- und dann wieder einloggen, damit die Modifikation wirksam wird.

Die Schaltung

Für unsere GPIO Versuche wollen wir eine rote LED zum Blinken bringen. Dazu verbinden wir die Kathode der LED über einen Vorwiderstand mit einem der Masse (GND) Pins des Raspberry Pi und die Anode mit dem Pin 23 der GPIO Header (der achte Pin vom äußersten +5V Pin aus gezählt.)

Grafik des  Hardwareaufbau mit roter LED, Vorwiderstand und Taster auf einem Breadboard
Grafik des Hardwareaufbau mit roter LED, Vorwiderstand und Taster auf einem Breadboard

Widerstand

Ein Widerstand ist ein passives Bauelement, dass dafür sorgt, dass bei einer bestimmten Spannung die gewünschte Stromstärke fließt. Die Formel U = R * I auch bekannt als „Ohmsches Gesetz“ ist die bestimmt irgendwann mal zu Ohren gekommen. Der elektrische Widerstand wird in Ohm (Formelzeichen Ω) angegeben.

Damit die LED nicht durch zu viel Strom kaputt geht, schalten wir einen 330Ω Vorwiderstand (220Ω würden rechnerisch auch reichen, ich habe aber gerade 330er da). Die farbigen Ringe auf dem Widerstand geben den Widerstandswert an, orange=3, orange=3, schwarz=0, schwarz= Multiplikator *1, rot= Toleranz ±2%.

Widerstand 330Ω

Leuchtdiode

Eine Diode ist ein Bauelement nur in einer Richtung passieren lässt. Deshalb ist es wichtig, auf die Polarität zu achten. Bei der Leuchtdiode (LED) ist ein Anschlusskontakt immer länger als der andere. Dies ist die Anode oder + Pol und muss mit dem GPIO Pin des Raspi verbunden werden. Demzufolge ist der kurze Kontakt der -Pol oder Kathode, die auf Masse gelegt wird (Merkregel: kurz ist die Kathode)

rote Leuchtdiode

Taster

Ein Taster (engl. Button) lässt Strom nur durch, solange er gedrückt wird.Ich benutzen ihn, um das Auslesen von GPIO Pins zu demonstrieren. Ein Taster leitet den Strom nur solange du ihn drückst.

Taster mit zwei Kontaktstiften
Drucktaster

Hardware Zusammenbauen

Nach den Grundlagen geht es jetzt an den Zusammenbau unserer kleinen Schaltung.Mit dem schwarzen Jumperkabel verbindest du einen der GND-Pins (Ich benutze den Dritten von außen) mit der Masse-Schiene des Breadboards. Die LED steckst du mit beiden Kontakten irgendwo in zwei benachbarte Kontakte auf dem Breadboard, du musst dir nur merken, welches die Anode ist.Den einen Draht des Widerstands steckst du in einen weiteren Kontakt auf der Masse-Schiene, den anderen in einen Kontakt in derselben Spalte , in der die Kathode der LED steckt. Zu guter Letzt verbindest du mit einem roten (ich hatte nur orange da) Jumperkabel(m-f) den GPIO Pin 23 mit der Spalte, in der die Anode der LED steckt. Damit ist der Stromkreis geschlossen. Sollte im weiteren Verlauf etwas nicht klappen, dann ist die wahrscheinlichste Ursache, dass die Polarität der LED falsch angeschlossen ist.
Den Taster platzierst über zwei Kontaktreihen des Breadboards.Danach verbindest du mit einem Jumper-Kabel (m-m, schwarz)einen Kontakt des Tasters mit der Masse-schiene des Breadboards. Mit einem weiteren Jumper (f-m, grün) verbindest den anderen Tasterkontakt auf derselben Seite des „Grabens“ mit Pin 16 des Raspberry Pi.

zusammengebaute Schaltung mit Raspberry Pi 4B, Breadboard, roter LED und Widerstand und Taster

GPIO ansteuern

Das klassische Programmbeispiel für diesen Versuchsaufbau ist es, die LED blinken zu lassen. Bei der Ansteuerung der Pins hilft uns das Package RPi.GPIO. Sehen wir uns mal folgendes Programm an:

import RPi.GPIO as GPIO
from time import sleep

__PIN__ = 23   # GPIO Pin, den wir nutzen
__WAIT__ = 0.5 # Warten für 0,5 Sekunden

GPIO.setwarnings(False)

# benutze Broadcom Pin Nummerierung
GPIO.setmode(GPIO.BCM)

# Pin 23 als Output schalten.
GPIO.setup(__PIN__,GPIO.OUT)

#Zustand der LED setzen
def setLED(state):

  GPIO.output(__PIN__,state)

# Dauerschleife, die die LED im Wechsel ein- und ausschaltet.
# Wird gestoppt mit CTRL-C
def blinkloop():
  try:
    while True:

# Pin auf HIGH setzen schaltet die LED ein
      setLED(GPIO.HIGH)
      print('LED ein')

      sleep(__WAIT__)

# Pin auf LOW setzen schaltet die LED aus
      setLED(GPIO.LOW)
      print('LED aus')
      sleep(__WAIT__)
  except KeyboardInterrupt:
    pass
  finally:
    # Zum schluss immer die LED ausschalten.
      setLED(GPIO.LOW)

if __name__ =='__main__':
    blinkloop()
    GPIO.cleanup(__PIN__)

Dieses Programm schaltet die LED ständig ein und aus mit einer Wartezeit von 0,5 Sekunden dazwischen. Es läuft solange, bis es mit CTRL-C abgebrochen wird. Eine Zeile will ich noch genauer erklären.

GPIO.setmode(GPIO.BCM)

Die GPIO Pins haben unterschiedliche Nummerierungen. In der ersten werden die Pins konsekutiv hintereinander von 1 bis 40 hochgezählt. Die andere wird vom SoC vorgegeben. Wir schalten hier die Nummerierung des Broadcom-SoC ein.

LED-Server

Die LED blinken zu lassen, ist maximal für 2 Minuten spannend.Jetzt will ich dir zeigen, wie du die LED über eine Browser URL schalten kannst.

Im Kapitel Netzwerk hab ich die Socketserver nicht angesprochen, da ich sie hier besser platziert sehe. Socketserver sind in erster Linie dazu da, TCP-Services wie bspw. HTTP oder FTP zu bedienen. Diesen können wir relativ einfach mit einem RequestHandler koppeln, um den übergebenen URL auszuwerten. Der RequestHandler stellt Methoden zur Verfügung, die bei den verschiedenen HTTP-Request GET,POST, DELETE aufgerufen werden. Dort implementieren wir dann unseren Code.

#! /usr/bin/python3
from http.server import SimpleHTTPRequestHandler
import socketserver
import logging
from led import setLED

responsehtml = '<html><body> <h3>LED-Server</h3><p> LED ist $ledstate_str</p></body></html>'
logging.basicConfig( format='%(asctime)-15s [%(levelname)s] %(funcName)s: %(message)s', level=logging.DEBUG)

# Da http ein stateless Protokoll ist, wird der Handler bei jedem Request neu
# aufgebaut! Deswegen benutzen wir hier setup() statt __init__()
class LEDHttpRequestHandler(SimpleHTTPRequestHandler):
    def setup(self):
        logging.debug('setting up Handler')
        self.ledstate = False
        super().setup()

    def do_GET(self):
        logging.debug(f'path= {self.path}')
        logging.debug('GET: empfangen')
        self.send_response(200)
        self.send_header('Content-Type:','text/html')
# Ende der Header markieren, dass ist wichtig, sonst kommt der Response nicht zurück!
        self.end_headers()

#Wenn im Requestpath 'led='on'enthalten ist, schalten wir die LED ein. Bei off aus
        if '?led=' in self.path:
          if 'on' in self.path:
            logging.debug('schalte LED ein')
            self.ledstate = True
            setLED(self.ledstate)
          elif 'off' in self.path:
            logging.debug('schalte LED aus')
            self.ledstate = False
            setLED(self.ledstate)

        logging.debug(f'ledstate={self.ledstate}')

        response = responsehtml.replace('$ledstate_str',('aus','an')[self.ledstate])

        self.wfile.write(response.encode())



class http_server:
    def __init__(self):
        def handler(*args):
            myHandler(*args)
        server = HTTPServer(('', 8080), handler)


if __name__ == '__main__':
    logging.debug('MAIN: start')
    setLED(False) # Beim Start LED ausschalten
#Request-Handler aufbauen
    handler = LEDHttpRequestHandler
    handler.ledstate = False
#Socketserver mit unserem Handler starten
    with socketserver.TCPServer(('',8080),handler) as httpd:
        logging.info('SERVER: start')
        try:
#Server läuft bis CTRL-C gedrückt wird.
          httpd.serve_forever()
        except KeyboardInterrupt:
          pass
        finally:
          setLED(False)

GPIO auslesen

Zu guter Letzt wollen wir noch den Zustand des Tasters am Pin 16 auslesen. Wenn Strom durch den gedrückten Taster geleitet wird, geht Pin 16 auf HIGH

#! /usr/bin/python3
import RPi.GPIO as GPIO
from time import sleep
import logging


__PIN__ = 16   # GPIO Pin, für den Taster
__WAIT__ = 0.5 # Warten für 0,5 Sekunden
logging.basicConfig( format='%(asctime)-15s [%(levelname)s] %(funcName)s: %(message)s', level=logging.DEBUG)

if __name__ =='__main__':
  GPIO.setwarnings(False)
# benutze Broadcom Pin Nummerierung
  GPIO.setmode(GPIO.BCM)

  logging.debug(f'konfiguriere Pin ${__PIN__} als Input.')
# Pin 16 als Input mit Pull-Up-Widerstand schalten.
  GPIO.setup(__PIN__, GPIO.IN, pull_up_down=GPIO.PUD_UP)
  pressed = False

  logging.debug('Start der Schleife.')
  try:
    while True:
      if not GPIO.input(__PIN__):
        if not pressed:
          logging.info('Button wurde gedrückt.')
          pressed = True
      else:
        logging.debug('Button nicht gedrückt.')
        pressed = False

      sleep(__WAIT__)
  except KeyboardInterrupt:
    logging.debug('Abbruch durch Benutzer.')
  finally:
    pass
Screenshot des Programmablaufs des Tasterprogramms.
Screenshot des Programmablaufs des Tasterprogramms.

Mir hat die Arbeit an diesem Kapitel viel Spaß gemacht. Im nächsten Teil kümmern wir uns um das wichtige Thema Testing.

Schreibe einen Kommentar

Cookie Consent Banner von Real Cookie Banner