Raspberry Pi: GPIO – Ausgänge schalten, Eingänge lesen

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.

Raspberry Pi Modell B+

Raspberry Pi Modell B+

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.GPIOtime 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.

Raspberry Pi mit 2-Kanal-Relais-Modul am GPIO25

Raspberry Pi mit 2-Kanal-Relais-Modul

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:

Raspberry Pi mit 2-Kanal-Relais-Modul (Schema)

Raspberry Pi mit 2-Kanal-Relais-Modul (Schema)

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.

Raspberry Pi mit gebrücktem Eingang GPIO24

Raspberry Pi mit gebrücktem Eingang

Angeschlossen wird das in meinem Beispiel so:

Raspberry Pi mit gebrücktem Eingang (Schema)

Raspberry Pi mit gebrücktem Eingang (Schema)

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()
Sebastian

93 Comments

  1. Antworten Berti

    Hallo,
    ich benutze meinen Rpi um einen 3d Drucker zu steuern.
    Jetzt möchte ich gern.dass ein Eingang gelesen wird und sobald
    dort eine logisch eins ansteht soll ein Ausgang für z.B. 2min auf
    eins gesetzt werden.
    Dieses soll aber direkt ab dem booten des Pi´s abgefragt werden.
    Wie setzte ich das um, dass ein Script quasi ab dem Booten ausgeführt wird ?

  2. Antworten deReeschler

    Hi,
    du kannst mit sudo nano /etc/rc.local in der Datei Dein Skript eintragen, aber VOR dem Exit Befehl, sieht dann in etwa so aus:

    sudo python /home/pi/meinscript.py &
    exit 0
    

    Wichtig dabei, das Skript muss ausführbar sein und im Home-Verzeichnis liegen. Falls es woanders liegt, einfach den Pfad anpassen.
    Grüße
    deReeschler

  3. Antworten Holgy

    Hallo,
    Sehr gute Beschreibung.
    Ich habe die gleichen Relais wie in deiner Abbildung: SRD-05VDC-SL-C in einen Block CP0408B. Die Softwre sagt das sich die Schaltsignale ändern von 0 auf 1 und umgekehrt. Das Relay ändert den Schaltzustand aber nicht. Kann es sein das die 3,3V am GPIO zu gering sind , um das Relay umzusteuern?
    Oder wo kann der Fehler liegen?

    • Antworten Sebastian

      Hallo Holgy,
      die 3,3V Ausgangsspannung reichen auf alle Fälle, denn dafür ist das Relais ja ausgelegt.
      Auf Anhieb fällt mir folgendes dazu ein:
      – Spannungsversorgung der ganzen Platine muss 5V sein (nicht 3,3V)
      – Der Jumper muss zwischen JD-VCC und VCC gesteckt sein
      – Eventuell setzt dein Programm an anderer Stelle den Ausgang am RPi zurück
      – Das Relais könnte einfach kaputt sein (passiert laut Amazon-Bewertungen garnicht so selten)

  4. Antworten Gerd

    Schöne Erklärung und drei Fälle sind abgehandelt
    1. Ausgang setzen und schalten
    2. Eingang setzen
    3. Ausgang Staus lesen

    Nun mein Probem, wie kann ich einen Eingang „setzen“ ?
    Also Taster an GPIOx mit Pullup, bei Tasendruck wird ein Interrupt erzeugt
    Nun möchte ich per Software den Tastendruck simulieren, also den Interrupt erzeugen.
    Egal ob per Programm, Cronjob oder ..

    Gerd

    • Antworten Sebastian

      Hallo Gerd,

      ich nehme an, dass das nur für einen Test gedacht ist. Auf Anhieb fallen mir da drei Möglichkeiten ein:
      1. Einen zusätzlichen Ausgang verwenden, diesen mit einem Eingang verbinden und durch das Setzen des Ausgangs eine Zustandsänderung am Eingang hervorrufen. Wenn Du noch einen GPIO frei hast, dann ist das sicher die einfachste Variante.
      2. Du könntest innerhalb Deines Programmes ereignisabhängig zur Laufzeit den Pullup-Widerstand auf Pulldown umkonfigurieren.
      3. Du konfigurierst den Eingang als Ausgang. Setzt ihn irgendwo in Deinem Programm nach belieben. An der Stelle, die Du testen willst, fragst Du den Ausgang einfach wie einen Eingang ab.

      Was auch immer gut funktioniert ist das verwenden von Variablen. Die kannst Du zum Testen nach belieben innerhalb des Programmen verändern und wenn Du fertig bist, verbindest Du sie softwaremäßig mit den GPIO. Das ist zum Teil auch bei industrieller Automatisierung üblich.

  5. Antworten tiago

    Hallo Sebastian,
    Ich hätte da eine frage, ich habe mir ein tinxi 8kanal relais gekauft bin mir aber nicht so sicher wie ich es am raspi anschließen soll.
    Kann es sein das der raspi kaput geht wenn ich es einfach so schalte wie in deine zeichnung? Oder sollte ich wiederstände benutzen um ihm zu beschützen?

    • Antworten Sebastian

      Es kann natürlich immer etwas kaputt gehen, lässt sich manchmal kaum verhindern. Aber das Relais ist im Prinzip das gleiche wie ich es verwende, nur mit der doppelten Anzahl an Kanälen. Die Gefahr ist also recht gering.

    • Antworten Sebastian

      Das kommt ganz sicher auf Deine spezielle Anwendung an und unter bestimmten Umständen kann das durchaus notwendig, oder zumindest besser sein. In dem hier gezeigten Beispiel kann ich da jedoch keinen größeren Sinn erkennen. Die Relaisspulen des hier verwendeten Moduls hängen nicht direkt am GPIO, sondern werden über einen Optokoppler betrieben. Daher schaltet das Relais auch nicht bei high ein, sondern bei low.

      • Antworten Rico

        Hallo Sebastian.
        Um nochmal auf die Ansteuerung zu kommen: Ich versorge das Modul mit 5V. Die GPIOs vertragen aber doch nur 3,3V. Brate ich mir nicht die GPIOs wenn geschaltet wird?

        • Antworten Sebastian

          Hi Rico,
          du kannst das Relais-Modul ganz beruhigt so anschließen. Die 5V sind die Versorgungsspannung des Moduls. Die 3,3V, die aus den GPIO heraus kommen, werden dann zum Schalten der Relais genutzt. Die 5V werden also nicht wieder zurück auf die GPIO geleitet.

  6. Antworten Stefan

    GPIO.setmode(GPIO.BOARD) bringt bei mir einen Fehler. Das setmod ist nicht in der Bibliothek, was kann ich tun?

  7. Antworten Wilfried

    Hallo, bis jetzt die beste Erklärung 😊
    ich muss für ein Projekt 8 Schwimmerschalter überwachen. Wenn einer der Eingänge auf Lo geht muss eine Alarm eMail verschickt werden (z Bsp „Alarm Pumpe 1“).
    Als Erweiterung soll je Pumpe ein Weiterer Schwimmerschalter ausgewertet werden. Dieser soll aber nur auswerten und ein Diagramm darstellen dieses dann einmal die Woche per Mail als CSV Datei.
    Wichtig es muss jeden Tag eine Testmeldung versendet werden.

    Bis Dato habe ich nur mit Siemens S5+S7 und CoDeSys gearbeitet brauche da also Unterstützung 😢

    • Antworten Sebastian

      Das klingt nach einem etwas umfangreicheren Projekt. Aber ich kann Dich beruhigen. S7-Programmierung ist ein ziemlich guter Background. Den hab ich nämlich auch und das hat mir schon manchmal weitergeholfen. Erstaunlicherweise lassen sich derartige Programmierstrategien hier gut anwenden, auch wenn die Programmiersprachen sich stark unterscheiden.

      Hast Du denn schon einen Lösungsansatz oder stehst du noch ganz am Anfang?

  8. Antworten JimBeamer

    Hallo Sebastian, tolles Tutorial. Deine Beschreibung hat mich ein ganzes Stück weiter gebracht. Ich habe mir ein Internetradio gebastelt und benutze vier Knöpfe zum bedienen des Radios. Nun ist es so, dass mein Programm nach zweimaligem umschalten in verschiedene Menüs den Zugriff auf die Knöpfe verliert. Es kommt keine Fehlermeldung der Pi reagiert einfach nicht mehr auf die Knöpfe. Das Programm läuft aber noch weiter was ich an der Anzeige des 20×4 Zeichen Displays erkennen kann.

    • Antworten Sebastian

      Ohne weitere Informationen ist es natürlich schwer, hier etwas passendes dazu beizutragen.
      Vielleicht kannst Du mir mal Dein Programm zeigen? Wenn es zu lang ist, gern auch per Email, Dropbox, FTP-Download – was Dir am liebsten ist.

  9. Antworten Reinhold

    Sehr hilfreiche Beiträge für mich, danke!
    Habe mal wo? gelesen, das sich nicht bei allen GPIOs die Pull-Wiederstände schalten lassen würden. Ist da was zu beachten?

    • Antworten Sebastian

      Meines Wissens nach haben alle GPIO Pull-Up/Down-Widerstände, jedoch kann man die nicht bei allen GPIO verändern.
      Ich kann mich aber auch irren, weiß es also nicht genau.

  10. Pingback: GPIO Eingänge: Werte wechseln ständig zwischen 0 und 1 – Smarthome

  11. Antworten Andreas

    Hallo,
    leider funktioniert die Statusabfrage der Eingänge erst nach der ersten Statusänderung.
    Danach läuft es ohne Probleme. Aber ich will nach dem Programmstart den Zustand wissen.
    Was mache ich falsch?
    Danke und Gruß
    Andreas

      • Antworten Andreas

        Hallo Sebastian,
        ich habe als Vorlage dein Script „Status eines Ausgangs abfragen“ genommen.

        #!/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 Filter
        GPIO.setup(18, GPIO.IN, pull_up_down = GPIO.PUD_DOWN)
        
        # Pin 11 (GPIO 17) als Eingang festlegen Teich
        GPIO.setup(11, GPIO.IN, pull_up_down = GPIO.PUD_DOWN)
        
        # Schleifenzähler
        i = 0
        print "start1";
        
        # Ereignis-Funktion für Eingang Filter HIGH
        def doIfHigh1(channel):
        	# Zugriff auf Variable i
        	global i
        
        	if GPIO.input(channel) == GPIO.HIGH:
        		# Wenn Eingang HIGH ist, Ausgabe im Terminal erzeugen
        		print "Wasserstand Filter ok " + str(i)	
        	else:
        		# Wenn Eingang LOW ist, Ausgabe im Terminal erzeugen
        		print "Wassertand Filter zu niedrig " + str(i)
        	
        	# Schleifenzähler erhöhen
        	i = i + 1
        	
        	# Ereignis-Funktion für Eingang  HIGH
        def doIfHigh2(channel):
        	# Zugriff auf Variable i 
        	global i
        	
        	if GPIO.input(channel) == GPIO.HIGH:
        		# Wenn Eingang HIGH ist, Ausgabe im Terminal erzeugen
        		print "Wasserstand  ok " + str(i)
        	else:
        		# Wenn Eingang LOW ist, Ausgabe im Terminal erzeugen
        		print "Wassertand  zu niedrig " + str(i)
        
        	# Schleifenzähler erhöhen
        	i = i + 1
        	
        # Ereignis deklarieren
        GPIO.add_event_detect(18, GPIO.BOTH, callback = doIfHigh1, bouncetime = 200)
        GPIO.add_event_detect(11, GPIO.BOTH, callback = doIfHigh2, bouncetime = 200)
        
        # Eigentlicher Programmablauf
        while 1:
        	time.sleep(8.1)
        
        • Antworten Sebastian

          Hi Andreas,

          Du fragst in Deinem Script nirgendwo den Zustand der Eingänge ab, sondern wertest nur einen Flankenwechsel aus. Das ist hier der Grund.

          • Andreas

            Hallo Sebastian,
            da habe ich wohl was vergessen .
            Danke für deine Unterstützung.
            VG
            Andreas

  12. Antworten Jägerbgt153

    Moin,
    Habe alle Anweisungen befolgt. Die Shell gibt bei mir aus:
    Traceback (most recent call last):
    File „/home/pi/Desktop/n/fan_test.py“, line 2, in
    import RPi.GPIO as GPIO
    RuntimeError: This module can only be run on a Raspberry Pi!
    könnt ihr mir sagen was ich falsch gemacht habe?
    Ich benutze das Skript für einen Lüfter.

    • Antworten Sebastian

      Die Meldung weist dich darauf hin, dass RPI.GPIO nur auf einem Raspberry Pi verwendet werden kann. Führst Du das Script denn auf einem Raspberry Pi aus?

  13. Antworten Denis

    Moin,

    ich möchte drei Taster an die GPIO Pins anschliessen. Wenn ich Taster1 drücke, wird ein Schrittmotor „Schneller“, wenn ich Taster2 drücke, wird der <motor "langsamer" und wenn ich Taster3 drücke, hält der Motor an.
    Der Motor ist per USB an dem RPi angeschlossen und wird in der Konsole als "dev/ttyUSB0" erkannt. Ich kann ihn auch über die Konsole steuern, mit den integrierten Befehlen vom Hersteller. Jetzt benötige ich nur noch ein Programm für die Taster 🙁

    Kann ich dein Programmcode "Eingagng lesen" teilweise dafür verwenden? Oder hast du eine Idee?

    LG Denis

    • Antworten Sebastian

      Moin Denis,

      klar kannst Du das verwenden, oder Dich zumindest daran orientieren.
      Allerdings habe ich solch einen Schrittmotor nicht, sodass ich Dir bei diesem Teil nicht direkt weiterhelfen kann. Aber solange der sich in Python ansteuern lässt, könntest Du vielleicht etwas in diese Richtung bauen:

      ...
      while 1:
          # Eingang Taster 1
          if GPIO.input(18) == GPIO.HIGH:
              # Befehl für Motor SCHNELLER
          # Eingang Taster 2
          if GPIO.input(19) == GPIO.HIGH:
              # Befehl für Motor LANGSAMER
          # Eingang Taster 3
          if GPIO.input(20) == GPIO.HIGH:
              # Befehl für Motor ANHALTEN
      

      Falls es Sinn macht, kannst Du auch die Flanken abfragen. Den Schleifenzähler brauchst Du hier natürlich nicht, denn der ist im Beispiel nur zur besseren Visualisierung eingebaut.

      • Antworten Denis

        Moin Sebastian,

        danken für deine Antwort. Hab mich irgendwie selbst durch gewurschtelt.

        # Main Function
        def main():
         value = 0
         actspeed= 0
        
         while True:
        
           if not GPIO.input(Tasterup):
             #Geschwindigkeit HOCH'
             value +=speeddelta
        
           if not GPIO.input(Tasterdown):
             #Geschwindigkeit Runter'
             value -= speeddelta
           if not GPIO.input(Tasterstop):
             #'stop'
             value = 0
        
           if not (actspeed == value):
             speed='V'+str(value)
             ser.write(speed+'n')
             print speed
             actspeed = value 
        
           time.sleep(0.1)
        

        was auch funktioniert.

        Will jetzt noch Daten wie z.B Geschwindigkeit, auf einem Segment Display anzeigen lassen. Da würde ich deine Hilfe nochmal in Anspruch nehmen 🙂

        • Antworten Sebastian

          Hi Denis,
          sehr schöne Lösung, gefällt mir wirklich gut. Aber beim Display muss ich Dich leider wieder enttäuschen – auch dafür hatte ich bisher noch keine Verwendung, weshalb ich auch keins besitze.

  14. Antworten Christoph Thomas

    Hallo,

    vielen Dank für diesen super Artikel.
    Ich möchte mit dem RPI und FHEM den Druck einer Wasserleitung überwachen und bei Unterschreiten eines bestimmten Drucks eine Pumpe anschalten. Zur Drucküberwachung habe ich mir einen Sensor besorgt, der druckabhängig eine Spannung von 0-4,5 V liefert.
    Meine Idee ist es, ein Poti zwischen Sensor und GPIO zu schalten, um den Schaltpunkt „titrieren“ zu können. Kann das funktionieren? Ab welcher Eingangsspannung am GPIO wird „High“ ausgegeben?

    Danke
    Christoph

    • Antworten Sebastian

      Hi Christoph,
      Ich finde das ehrlich gesagt keine gute Lösung. Besser wäre es, wenn du einen passenden Schwellwertschalter dazwischen bauen würdest, oder vielleicht gleich einen einstellbaren Druckschalter verwendest.

  15. Antworten Christoph

    Hi,
    ich habe mal eine prinzipielle Frage bzgl den GPIOs:
    ich habe derzeit ein python script, um LEDs und Lampen zu steuern.
    Diese basieren auf der GPIO.BCM „zählweise“.

    Nun möchte ich mein Script so erweitern, dass das nun auch per website (also im WLAN) zu steuern geht.
    nun habe ich gelesen, dazu müsste ich wiringPI installieren.

    Wenn ich nun wiringPI installiere ist nun die zählweise der GPIOs anders.
    Muss ich dazu nun mein derzeit aktuelles script abändern?
    Oder kann ich das so lassen, da ich ja explizit die GPIO.BCM zählweise angegeben habe
    und dann ja nur die website diese zählweise nutzen würde?

  16. Antworten Fips

    Hi. genau das was ich gesucht habe. Leider Kriege ich das für mich nicht umgesetzt. Bin noch am lernen.
    Vielleicht hilft mir jemand mit einem Quelltext aus.

    Ich möchte eine Batterie an den Raspi bauen und eine Meldeeinrichtung bei Stromausfall. Dafür schließe ich einen USB Port an ein %V Relais. Dieses Schaltet, wenn der Strom abbricht.

    Jetzt möchte ich 1. Eine Email bekommen wenn das der Fall ist (Programm dafür ist geschieben, muss nur ausgeführt werden)
    2. Einen Terminal Eintrag mit datum und Uhrzeit
    3. dass sich der Raspi selbstständig runterfährt wenn der strom in 60 Min nicht wieder da ist.
    4. Sollte der Strom wieder da sein: Runterfahren abbrechen, Terminaleintrag und Email an mich.

    Wäre schön, wenn mir da jemand ein Programm zu schreiben kann, wenn möglich mit Kommentar, damit ich es verstehen kann.

    Danke, Gruß Fips

  17. Antworten Mr. F

    Hallo und vielen Dank für die gut lesbare Anleitung.
    Ich versuche mit dem Raspi eine Audiostation, die auf Knopfdruck eine MP3-Datei abspielt einzurichten.
    Durch dein Anleitung habe ich den Teil des Tasters nachvollzogen. Mir ist noch nicht klar wie ich damit ein Ereignis wie z.B. Audioplayer starten auslöse.
    Ich versuche hiermit für ein Museum die sonst sehr teuren Hörstationen für eine Ausstellung zu ersetzen.
    Vielen Dank schon einmal für Hinweise.
    Fred

  18. Antworten Lars

    Moin, habe da mal eine Anfängerfrage….
    Wozu dient das (channel) hinter dem doIfHigh?
    das dient doch normaler weise dazu Werte zu übergeben, oder liege ich da falsch?
    (Bisher nur in C geschnuppert, Python gerade erst angefangen).
    „doIfHigh“ wird mit callback aufgerufen, da wird aber nichts übergeben….

    Gruß, Lars

    • Antworten Sebastian

      Hi Lars,
      da hast Du natürlich recht. Das ist zwar eigentlich nur ein Relikt aus einem anderen Skript gewesen, aber ich hab das Beispiel mal entsprechend erweitert.

  19. Antworten Tobias

    Hallo Sebastian,
    vielen dank für diese Anleitung.

    Ich habe eine Frage. Wenn ich mein Script starte dann setzt er den Eingang des Relais direkt auf HIGH.
    Kannst du mir sagen woran das liegt ?

    #!/usr/bin/python
    #coding: utf8 
     
    import time
    import RPi.GPIO as GPIO
     
    # Zählweise der Pins festlegen
    GPIO.setmode(GPIO.BOARD)
     
    # Variablendeklaration
    
     
    # Pins Festlegen
    GPIO.setup(12, GPIO.OUT)	#light GPIO18
    GPIO.setup(16, GPIO.OUT) 	#printer GPIO23
    GPIO.setup(29, GPIO.IN, pull_up_down = GPIO.PUD_DOWN) 	#Pushbutton light GPIO5
    GPIO.setup(31, GPIO.IN, pull_up_down = GPIO.PUD_DOWN) 	#Pushbutton printer GPIO6
    
    def PushButtonLight(channel):
    
    	print "Pushbutton Licht wurde gedrückt"
    	if 	GPIO.input(12) == GPIO.HIGH:
    		GPIO.output(12,GPIO.LOW)
    		print "Licht wird ausgeschaltet"
    	else:
    		GPIO.output(12,GPIO.HIGH)
    		print "Licht wird eingeschaltet"
    
    
    def PushButtonPrinter(channel):
    	print "Pushbutton Printer wurde gedrückt"
    	if 	GPIO.input(16) == GPIO.HIGH:
    		GPIO.output(16,GPIO.LOW)
    		print "Printer wird ausgeschaltet"
    	else:
    		GPIO.output(16,GPIO.HIGH)
    		print "Printer wird eingeschaltet"
    
    		
    # Event Detection
    GPIO.add_event_detect(29, GPIO.RISING, callback = PushButtonLight, bouncetime = 200)
    GPIO.add_event_detect(31, GPIO.RISING, callback = PushButtonPrinter, bouncetime = 200)
    
    
    while True:
        time.sleep(0.1)
    
  20. Antworten Nils

    Hallo Sebastian,
    erstmal vielen Dank für die tolle Anleitung!
    Ich habe aber ein Problem und hoffe, du kannst mir helfen. Ich habe genau wie in deinem Beispiel ein Relais an meinem Pi angeschlossen (gleiche Pins, gleicher Code, gleiche Schaltung). Dieses lässt sich nach dem Anschalten durch „GPIO.output(22, GPIO.HIGH)“ nicht mehr mit „GPIO.output(22, GPIO.LOW)“ ausschalten.
    Erst wenn „GPIO.cleanup()“ ausgeführt wird, schließt das Relais wieder.
    Irgendeine Idee woran das liegen kann?
    Viele Grüße

      • Antworten Nils

        Hallo Sebastian,
        ich weiß nicht genau, wie du das meinst. Also das Relais schließt, wenn Spannung anliegt; sprich wenn der Ausgang auf High steht. Wenn ich daraufhin noch einmal GPIO.output(22, GPIO.HIGH) ausführe, bleibt das Relais auch geschlossen.
        (Sorry, ich sehe gerade in meiner ersten Nachricht war das letzte „schließen“ unglücklich formuliert – ich meinte, dass das Relais erst dann wieder den Stromfluss unterbricht)

        Ich möchte das Problem mal verdeutlichen:

        # Programmstart mit allem drum und dran
        
        print("startzustand")
        # relais ist offen, kein Stromfluss
        
        time.sleep(2)
        print("output high")
        GPIO.output(22, GPIO.HIGH)
        # jetzt ist das relais geschlossen, der Strom fließt
        
        time.sleep(2)
        print("output high erneut")
        GPIO.output(22, GPIO.HIGH)
        # das Relais bleibt geschlossen, Strom fließt weiter
        
        time.sleep(2)
        print("output low")
        GPIO.output(22, GPIO.LOW)
        # hier würde ich erwarten, dass das Relais sich öffnet und den Stromfluss unterbricht
        # tut es aber nicht - das Relais bleibt geschlossen und der Strom fließt weiter
        
        time.sleep(2)
        print("cleanup")
        GPIO.cleanup()
        # Relais öffnet sich und unterbricht den Stromfluss
        
        • Antworten Sebastian

          Im Moment fällt mir dazu nichts konkretes ein. Zeig doch mal das komplette Script, mit dem du da arbeitest.

  21. Antworten Nils

    Hallo Sebastian,
    bitte entschuldige meine späte Reaktion. Mein erster einfacher Code sieht folgendermaßen aus:

    #!/usr/bin/env python
    #coding: utf8
    
    import time
    import RPi.GPIO as GPIO
    
    # Zahlweise der Pins festlegen
    GPIO.setmode(GPIO.BOARD)
    
    # Pin 22 (GPIO 25) als Ausgang festlegen
    GPIO.setup(22, GPIO.OUT)
    
    # Ausgang einschalten
    print("Schalte Augang auf HIGH...")
    GPIO.output(22, GPIO.HIGH)
    print("Ausgang auf HIGH geschaltet")
    
    # zwei Sekunden warten
    time.sleep(2)
    
    # Ausgang ausschalten
    print("Schalte Augang auf LOW...")
    GPIO.output(22, GPIO.LOW)
    print("Augang auf LOW geschaltet")
    
    # zwei Sekunden warten
    time.sleep(2)
    
    # Ausgange wieder freigeben
    print("cleanup aufrufen...")
    GPIO.cleanup()
    print("cleanup fertig")
    

    Dieser Code führt zu meinem beschriebenen Fehler: das Relais öffnet sich erst wieder beim GPIO.cleanup() und nicht beim GPIO.output(22, GPIO.LOW).
    Es gibt jedoch einen Unterschied zu deinem Versuchsaufbau. Ich habe nicht nur das Relais am Ausgang, sondern noch ein weiteres Relais (als Schalter) am Eingang.

    Die Idee ist folgende:
    Ich möchte an meinen Fernseher ein Backlight mit Hyperion bauen. Die LEDs sollen nicht dauerhaft am Strom sein, aber ich möchte sie auch als „Mood-Light“ einschalten können, ohne dass der Fernseher an ist.
    Folglich habe ich ein Relais, welches ich mit dem Pi steuern möchte, das den Stromkreis der LEDs auf Wunsch unterbricht oder herstellt.
    Anders herum möchte ich jedoch, dass immer wenn der Fernseher eingeschaltet wird, automatisch die LEDs angehen. Dafür habe ich ein weiteres Relais an den USB-Port des Fernsehers geschlossen. Dieses Relais schließt, sobald der Fernseher angeht und dient somit als Eingang („Schalter“) für den Pi.

    Für den Anfang habe ich mir ein ganz rudimentäres Skript (das ebenso genau den obigen Fehler aufweist) zusammengebastelt:

    #!/usr/bin/env python
    #coding: utf8
    
    import time
    import RPi.GPIO as GPIO
    
    # Zahlweise 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)
    
    # Pin 22 (GPIO 25) als Ausgang festlegen
    GPIO.setup(22, GPIO.OUT)
    
    # Ereignis-Funktion für Flanken
    def flanke(channel):
    
        if GPIO.input(channel) == GPIO.LOW:
            # Wenn Eingang LOW ist, Ausgabe im Terminal erzeugen und Ausgang LOW setzen
            print "Fallende Flanke erkannt. Schalte ausgang LOW..."
            GPIO.output(22, GPIO.LOW)
            print "ausgang geschaltet"
        else:
            # Wenn Eingang HIGH ist, Ausgabe im Terminal erzeugen und Ausgang HIGH setzen
            print "Steigende Flanke erkannt. Schalte Ausgang HIGH..."
            GPIO.output(22, GPIO.HIGH)
            print "ausgang geschaltet"
    
    # Ereignis deklarieren
    GPIO.add_event_detect(18, GPIO.BOTH, callback = flanke)
    
    # Eigentlicher Programmablauf
    while 1:
        time.sleep(0.1)
    

    Auch hier, öffnet sich das Relais nicht wieder, nachdem es einmal geschlossen wurde.

    Bitte entschuldige den ewig langen Beitrag.
    Beste Grüße
    Nils

    • Antworten Sebastian

      Am Code kann ich keinen Fehler erkennen. Vielleicht liegt es an der elektrischen Verschaltung? Aus deiner Beschreibung „noch ein weiteres Relais (als Schalter) am Eingang“ kann ich mir kein Bild davon machen, was du da gebaut hast.

      • Antworten Nils

        Ok, vielen Dank, dass du es dir angeschaut hast!
        Ich habe jetzt das Ein- und Ausschalten in zwei Skripte ausgelagert, sodass ich sie unabhängig von dem Skript, dass den Eingang prüft, aufrufen kann. Im Ausschalten-Skript verwende ich jetzt einfach GPIO.cleanup() analog zum output(GPIO.LOW). Damit funktioniert es soweit (auch wenn es nicht ganz die feine englische Art ist), zumindest habe ich noch keine Issues dadurch erlebt.
        Die Schaltung mit dem anderen Relais versuche ich dir noch einmal zu verdeutlichen:

                        |---------------------------|
            5V-  ---|---| Rel. In     Rel. öffner   |
                    |   |                           |
        TV USB      |---| Rel. 5V-    Rel. Strom    |--- Pin 1
                        |                           |
            5V+  --- ---| Rel. 5V+    Rel. schließer|--- Pin 18
                        |---------------------------|
        

        Ich hoffe du weißt was ich meine. Wenn der TV angeht, bekommt der USB Port Strom und das Relais schließt. Der Pi verzeichnet dann die Flanke.

        Viele Grüße
        Nils

        • Antworten Nils

          Und das Relais am Ausgang sieht dann so aus:

                    |---------------------------|
          Pin 22 ---| Rel. In     Rel. öffner   |
                    |                           |
          Pin 20 ---| Rel. 5V-    Rel. Strom    |--- LED Strom + von Netzteil
                    |                           |
          Pin  2 ---| Rel. 5V+    Rel. schließer|--- LED Strom + zu LEDS
                    |---------------------------|
          
          • Nils

            Sorry, die Abbildung mit der Pipe zwischen den Relais-Inputs sollte er nicht absenden.
            Ich habe die Ausgänge auch schon alle durchgemessen und es gibt keinen Kurzschluss zwischen ihnen. Vielleicht habe ich auch nur einen Montags-Pi erwischt. Aber da es ja mit cleanup() funktioniert, passt es jetzt eigentlich für mich.
            Trotzdem noch einmal vielen Dank für deine Hilfe!
            Viele Grüße
            Nils

          • Sebastian

            Jetzt hab ich mir dein Script nochmal angeschaut. Wenn GPIO18 den Zustand ändert, rufst du die Funktion flanke als Event auf (Zeile 31). In dieser Funktion fragst du mit if/else den Zustand von GPIO(channel) ab, hast aber vergessen, den GPIO-Kanal mit zu übergeben. Da if niemals true sein kann wenn channel nicht definiert ist (Zeile 19) , folgt das Script immer dem else-Zweig, in dem das Relais dann eingeschaltet wird.

            Wenn du den Aufruf auf Zeile 31 nach
            GPIO.add_event_detect(18, GPIO.BOTH, callback = flanke(18))
            oder die Abfrage auf Zeile 19 nach
            if GPIO.input(18) == GPIO.LOW:
            änderst, sollte das Relais eigentlich richtig schalten.

  22. Antworten Sascha

    Halle Sebastian,
    ich habe Probleme mit der Shebang (glaube ich):
    #!/usr/bin/env python (Fall 1) existiert bei mir nicht, weswegen ich #!/usr/bin python ausprobiert habe. Ebenso habe ich Python 3.6.4 installiert und das Shebang auf python3.6 (Fall 2) gesetzt.
    Im Fall 1 sagt mir die Konsole verständlicherweise: sudo: unable to execute ./Lampe_x.py: No such file or directory
    Im Fall 2 sagt mir die Konsole selbst unter rootrechten (sudo und user root):
    sudo: unable to execute ./Lampe_x.py: Permission denied

    Warum besitze ich nicht das Verzeichnis ./env …? Und wie könnte ich den Fehler beheben?

    Ich habe einen Rasp 3 mit debian (full) drauf.

    Vielen Dank

    • Antworten Sebastian

      Hi Sascha,

      Du kannst im Terminal einfach den Befehl $ which python absetzen. Dann bekommst du angezeigt, was Du als Shebang nutzen kannst.

      • Antworten Sascha

        Hey Sebastian,
        das habe ich versucht. Ausgespuckt hat mir das Terminal „/usr/bin/python“, was ja heißt: #!/usr/bin/python

        Im Ordner Programme befindet sich auch mein Programm Lampe_x.py, welches auch ausführbar gemacht wurde (grün im Terminal)

        pi@raspberrypi:~/Programme $ ls
        Lampe_1.py Lampe_x.py

        Das Ding ist, ich bekomme dennoch den selben Ausführungsfehler.
        pi@raspberrypi:~/Programme $ sudo ./Lampe_x.py
        sudo: unable to execute ./Lampe_x.py: No such file or directory

        Irgendwo in englischen Foren wird etwas von $Path gesprochen, was ich jedoch inhaltlich nicht verstehe. Kann es irgendwie am Ort bzw. an irgendeiner symbolischen Verlinkung liegen?

        • Antworten Sebastian

          So einen Fall hatte ich bisher noch nie, aber ich würde nicht ausschließen, dass es an der Pfad-Variable liegt.

          Ich würde jetzt folgende Dinge probieren:
          Im Terminal einfach mal den Befehl $ python absetzen und schauen, was passiert.
          Wenn das funktioniert, würde ich mich nochmal eingehender mit dem Script auseinandersetzen. Wenn das nicht funktioniert, dann schauen, ob es an der Pfadvariable liegen könnte.

          Wenn das zuvor funktioniert hat, kannst Du auch die Shebang im Script entfernen und das Script mit dem Befehl $ python ./Lampe_x.py aufrufen.

          Zum Thema Pfadvariable kannst Du hier etwas auf Deutsch lesen:
          http://www.technik-tipps-und-tricks.de/raspberry-pi/raspberry-pi-sonstiges/

          • Sascha

            Danke Sebastian, tatsächlich liegt es an der Path Variable.
            100% sichererer Weg ist: sudo python /home/pi/Programme/PROGRAMMxyz.py

  23. Antworten tom

    Hallo Sebastian.
    ich habe dein script versucht zu verwenden aber ich bekomme immer folgende fehlermeldungen:

    GPIO.add_event_detect(18, GPIO.BOTH, callback=doIfHigh(18), bouncetime = 200)
    TypeError: Parameter must be callable

    was mache ich da falsch?

    danke tom

    • Antworten Sebastian

      Hi Tom,
      du machst garnichts falsch. Ich hatte kürzlich das diesen Beitrag überarbeitet und dabei hat sich dieser Fehler eingeschlichen. Probiere es mit dem aktuellen Code gern nocheinmal.

  24. Antworten Harry

    Hallo Sebastian,
    ich habe Deinen Artikel… Flanken eines Eingangs abfragen (Interrupt)… das Script mit einer steigenden Flanke umgesetzt. Ziel ist es Rauchmelder zu überwachen über ein NO (normal open) Kontakt. Der Kontakt des Rauchmelders ist auch geöffnet im Normalfall das habe ich mittels Messgerät überprüft.
    Leider erkennt das Raspberry trotzdem einen geschlossenen Kontakt und gibt einen Alarm aus.
    Was ich festgestellt habe, dass am Rauchmelder Kontakt eine sehr geringe Spannung anliegt.
    Vielleicht hat das Ansprechen des Scriptes damit etwas zu tun?
    Schließe ich die Kontakte via Steckbrücke und öffne sie wieder reagiert das Script wie von Dir beschrieben.
    Danke für Deine Einschätzung hierzu.
    Gruss Harry

    • Antworten Sebastian

      Hallo Harry,

      wenn du Flanken auswertest, dann reagiert das Script auch nur auf Flanken, die entsprechend eintreten müssen. Es kommt also im Detail darauf an, wie du dein Script geschrieben hast.
      Vermutung: Ist der Rauchmelder angeschlossen und du startest dein Script, dann muss er wahrscheinlich erstmal auslösen und wieder rückgesetzt werden, damit die negative Flanke auftritt und dein Script sich anschließend in der richtigen Stellung befindet. Dass es mit der Steckbrücke funktioniert ist ja ein Zeichen dafür, dass dein Script grundsätzlich in Ordnung zu sein scheint. Aber so eine Steckbrücke ist eben auch mal schnell geöffnet oder geschlossen, der Rauchmelderkontakt nicht. Kommt ganz darauf an, was du da programmiert hast.

      Sollte sich meine Vermutung bewahrheiten, dann müsstest du vielleicht noch eine Startup-Routine einbauen, die den statischen Zustand des Melders auswertet und das Script initialisiert.
      Wenn ich daneben liege wäre es vielleicht hilfreich, wenn du dein Script mal zeigst. Vielleicht kann ich dir dann besser weiterhelfen.

      Zur Spannung: So einen GPIO belegt man ja mit 3,3V, die du zwangsläufig über den Kontakt von deinem Rauchmelder ziehst. Insofern muss da bei geöffnetem Kontakt auch eine Spannung messbar sein. Wenn man auch bei nicht angeschlossenem Kontakt eine Spannung an den Anschlussklemmen messen kann, dann müsste man das mal genauer untersuchen und insbesondere sicherstellen, dass der Kontakt tatsächlich potenzialfrei ist.

  25. Antworten Harry

    Hallo Sebastian, gutes Neues Jahr wünsche ich Dir.

    mein Script sieht so aus… und muss sagen bin wirklicher Neuling.
    Habe noch eingebaut dass es mir bei Event ne email schicken soll.
    Problem ist das die email sobald ich den Melder anschließe immer kommt.
    Ich vermute doch einen Fehler im Script. 🙂

    #!/usr/bin/env python
    # coding: utf8
    
    from __future__ import absolute_import, division, print_function
    import time
    import smtplib
    from time import sleep
    from datetime import datetime as DateTime
    from email.mime.text import MIMEText
    import RPi.GPIO as GPIO
     
    FROM_EMAIL = 'xxxx.hm@gmail.com'
    TO_EMAIL = 'xxxx.hm@gmail.com'
    SMTP_SERVER = 'smtp.gmail.com'
    SMTP_USERNAME = FROM_EMAIL
    SMTP_PASSWORD = 'xxx'
    
    GPIO.setmode(GPIO.BOARD)
     
    # Pin 18 (GPIO 24) als Eingang festlegen
    GPIO.setup(18, GPIO.IN, pull_up_down = GPIO.PUD_DOWN)
     
    # Schleifenzaehler
    i = 0
    
    def doIfHigh(channel):
        # Zugriff auf Variable i ermoeglichen
        global i
        # Schleifenzaehler erhoehen
        i = i + 1
    
        now = DateTime.now()
        text  = 'Alarm Rauchmelder'  
        message = MIMEText(text)
        message['Subject'] = ('Alarm Rauchmelder'.format(now))
        message['From'] = FROM_EMAIL
        message['To'] = TO_EMAIL
        message['Date'] = format(now)
        smtp = smtplib.SMTP(SMTP_SERVER)
        smtp.starttls()
        smtp.login(SMTP_USERNAME, SMTP_PASSWORD)
        smtp.sendmail(message['From'], message['To'], message.as_string())
        smtp.quit()
        print('Email sent')
        sleep(2)
     
    # Ereignis deklarieren
    channel = 18
    GPIO.add_event_detect(channel, GPIO.RISING, callback = doIfHigh, bouncetime = 200)
     
    # Eigentlicher Programmablauf
    while 1:
        time.sleep(0.1)
    

    Danke für Deine Hilfe schon mal.

  26. Antworten Harry

    Habe jetzt das Script von Dir direkt verwendet für steigende Flanke und da spricht das Event auch dauerhaft an sobald ich den Melder anschließe.

  27. Antworten thomas

    Hallo,
    bin ich froh diese Beitraege gefunden zu haben.
    Bin verzeifelt am suchen welcher GPIO Eingang genommen werden muss wenn ich auf dem Piface den 1sten
    Taster ( Eingang 0) als GPIO programmieren moecht.
    Danke fuer euer Hilfe.
    gruss
    thomas

      • Antworten thomas

        Hallo,
        leider nein, aber ich suche weiter.
        Wuerde dieses script so funktionieren wenn (ev. nur noch Eingangs nummer falsch) um den
        subprocess.Popen(["/home/pi/th/aus"]) bei jedem flankenwechsel (falling od. rising edge) auszufuehren?

        #!/usr/bin/env python
        #coding: utf8
        
        import subprocess
        from subprocess import Popen
        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)
        
        # Ereignis-Funktion für Eingang HIGH
        def doIfHigh(channel):
        
            subprocess.Popen(["/home/pi/th/aus"])
        
        
        # Ereignis deklarieren
        channel = 18
        GPIO.add_event_detect(channel, GPIO.BOTH, callback = doIfHigh, bouncetime = 200)
        
        # Eigentlicher Programmablauf
        while 1:
            time.sleep(0.1)
        

        gruss
        thomas

        • Antworten thomas

          Natuerlich so mit richtiger Einrueckung:

          # Ereignis-Funktion für Eingang HIGH
          def doIfHigh(channel):
              subprocess.Popen(["/home/pi/th/aus"])
          

          gruss
          thomas

  28. Antworten thomas

    Hallo,
    so einfach wie ich mir das gedacht habe ist es jetzt leider doch nicht.
    Bräuchte da Mal bitte Hilfe.
    Mit Deinem Programm getestet:

    Wenn Eingang 18 0 ist, schreibt es mir, Low Low Low Low usw.
    Wenn Eingang 18 dann auf 1 wechselt, schreibt es mir, High und bleib da stehen.
    Wenn Eingang 18 wieder auf 0 wechselt, schreib es mir wieder, Low Low Low usw.

    Das Problem is nun dass subprocess.call("/home/pi/th/aus") bei Low, Low, Low den Befehl „aus“ (fuer Lampe) immer wieder sendet.
    Wenn das script „aus“ die Lampe steuert, geht Lampe zuerst an, ganz hell und dann aus. Deshalb muss beim Flankenwechel in beide Richtungen
    Low oder High, das Low oder High nur ein Mal kommen, naehmlich nur beim Wechseln der Flanke.
    wie kann man das machen??

    #!/usr/bin/env python
    #coding: utf8
    
    import time
    from time import sleep
    import RPi.GPIO as GPIO
    import subprocess
    
    # 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)
    
    
    channel = 18
    
    
    def doIfHigh(channel):
        if GPIO.input(channel):
            print "Rising edge detected on 18"
            subprocess.call("/home/pi/th/aus")
        else:
            print "Falling edge detected on 18"
            subprocess.call("/home/pi/th/aus")
    
    # Ereignis deklarieren
    channel = 18
    GPIO.add_event_detect(channel, GPIO.BOTH, callback = doIfHigh, bouncetime = 200)
    
    
    
    # Eigentlicher Programmablauf
    while 1:
        sleep(0.1)
    

    Wenn ich denn das Programm stoppe, kommt dieser Fehler.

    	^X^CTraceback (most recent call last):
      File "/home/pi/th/flanke.py", line 35, in 
        sleep(0.1)
    KeyboardInterrupt
    sys.excepthook is missing
    lost sys.stderr
    

    Waere echt froh wenn ihr mir hilft dises zum laufen zu bringen, habe seit 3 Tagen verschiedene scripts probiert, keines geht.

    gruss
    Thomas

  29. Antworten OlliPausW

    ich hätte da mal eine Frage:

    ich möchte wie im beitrag erklärt ein input am pi erkennen lassen (ich machs mit shell)

    jetzt wäre meine frage müssen die 3.3V die man auf den input pin gibt vom pi kommen oder können die auch von einer externen spannungsquelle kommen, die aber auch mit dem pi verbunden sind

    ich hab hier als netzteil für den pi ein altes pc netzteil, das sowohl 3.3 als auch 5 Volt versorgt und möchte dieses jetzt als spannungsquelle für den taster nutzen

    ich hab das ganze mal gezeichnet damit man sich in etwa vorstellen kann was ich versuche
    https://i.ibb.co/hMwXWGQ/Unbenannt.png

    ebenfalls frage ich mich was passieren würde wenn ich den pin aus versehen als output konfiguriere

    • Antworten Sebastian

      Kannst du machen. Wichtig ist nur, dass die 5V und 3,3V das gleiche Bezugspotenzial besitzen.

      • Antworten OlliPausW

        okay und was würde passieren wenn ich den pin ausversehen als output eingestellt hätte und dann taste?

        ich schalte ja dann die vom pi gebildeten 3.3V gegen die 3.3V vom netzteil kurz. Haben diese das selbe Potential, so dass da nichts passiert?

  30. Antworten Jochen

    Hallo

    ich hätte eine Frage.

    Ich würde gerne mit GPIO´s 2 Relay steuern.

    Mein Problem ist das er das eine Relais anschalten soll, und 2 Sekunden später das 2. Relay.
    Nacheinander klappt es wunderbar , ich bräuchte allerdings beide zusammen.
    Ist für einen automatischen Kameraauslöser an einem 3D-Scanner gedacht.
    Relay 1 soll also ca. 2 Sek die Kamera scharf stellen und Relay 2 den Auslöser betätigen, das klappt aber nur wenn Relay 1 noch betätigt ist.

    Ich verzweifel gerade

    Vg
    Jochen

  31. Antworten Karsten

    Hallo, ich bin zufällig auf deine Seite da gestoßen da ich für mein Programm die gpio Eingänge benutzen möchte. Ich suche eine Möglichkeit das mein Programm egal in welcher Funktion es zur Zeit steckt immer auf die gpio Eingänge reagiert. Ich habe dein Programm etwas verändert um dies zu verdeutlichen. Gibt es eine Möglichkeit das die gpio Eingänge auch in der Funktion weiter() ausgewertet werden ohne sie dort nochmal speziell abzufragen?

    #!/usr/bin/env python
    #coding: utf8
    import time
    import RPi.GPIO as GPIO

    # Zählweise der Pins festlegen
    GPIO.setmode(GPIO.BCM)
    # Pin 18 (GPIO 24) als Eingang festlegen
    GPIO.setup(19, GPIO.IN, pull_up_down = GPIO.PUD_DOWN)
    # Schleifenzähler
    i = 0
    # Ereignis-Funktion für Eingang HIGH

    def weiter():
    while True:
    print „zweite Schleife“
    print „jetzt muss das Programm auf den gleichen qpio Eingang reagieren…“
    time.sleep(1)

    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
    weiter()

    # Ereignis deklarieren
    channel = 19
    GPIO.add_event_detect(channel, GPIO.RISING, callback = doIfHigh, bouncetime = 200)
    # Eigentlicher Programmablauf

    while 1:
    time.sleep(0.1)

    • Antworten Sebastian

      Ein Event wird immer ausgelöst, also auch, wenn die Funktion „weiter“ ausgeführt wird. Einfach mal ausprobieren 😉

      • Antworten Karsten

        Danke für die schnelle Antwort. Bei mir kann ich nach dem ersten Betätigen des Eingangs 19 leider keine Änderung von i mehr feststellen.

        #!/usr/bin/env python
        #coding: utf8
        import time
        import RPi.GPIO as GPIO
        # Zählweise der Pins festlegen
        GPIO.setmode(GPIO.BCM)
        # Pin 18 (GPIO 24) als Eingang festlegen
        GPIO.setup(19, GPIO.IN, pull_up_down = GPIO.PUD_DOWN)
        # Schleifenzähler
        i = 0
        # Ereignis-Funktion für Eingang HIGH

        def weiter(i):
        print „Hallo“
        while True:
        print „zweite Schleife“
        #print i
        time.sleep(1)

        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
        weiter(i)

        # Ereignis deklarieren
        channel = 19
        GPIO.add_event_detect(channel, GPIO.RISING, callback = doIfHigh, bouncetime = 200)

        # Eigentlicher Programmablauf
        while 1:
        print i
        time.sleep(0.1)

        Nach dem betätigen des Eingangs erhalte ich folgende Ausgabe:
        Eingang 19 High 0
        Hallo
        zweite Schleife
        1
        1
        1
        1
        1
        zweite Schleife
        1
        1
        1
        1
        …. usw.
        Die Variable i wird nicht erhöht egal wie oft ich den Taster noch betätige. An was könnte das denn liegen?

        • Antworten Sebastian

          Das liegt daran, dass du die Funktion aufrufst und sie durch die darin enthaltene Endlosschleife nicht wieder verlässt. „While true“ darf nur im Hauptprogramm verwendet werden.

          • Karsten

            Alles klar. Dann kann ich das so nicht verwenden. Ich wollte in der Funktion weiter einen Lauftext an ein Display senden. Und dies sollte so lange laufen bis eine Taste gedrückt wird. Danke nochmal für die Antworten.

  32. Antworten Werner

    Hallo Sebastian, ich besitze einen Rpi3B+ und ein 16er Relais womit ich gerne vollautomatisch 3 LED-Licht-Stromkreise flexibel im Garten schalten möchte. Im Zeitfenster von 21:00 Uhr Abends bis morgens um 06:00 Uhr sollen am besten zu unterschiedlichen Zeiten Mo-So alle 3 Stromkreise für eine Dauer von ca. 30 Minuten pro Stunde an und aus gehen. Ich möchte gerne fortwährendes nächtliches Lichtspektakel um Tiere des Waldes vom Garten fernhalten zu können. Auch Einbrecher möchte ich so fernhalten. Hättest Du einen Code für mich, wenn ich Dir die 3 GPIO 16 (PIN 36), GPIO20 (PIN 38) und GPIO 21 (PIN40) mitteile. Beste Grüße vorab. Werner

  33. Antworten Achim

    Hallo Sebastian,
    in einigen Programmen ist die Zeile „Das Script läuft solange, bis es mit der Tastenkombination Strg+C abgebrochen wird.“ zu lesen. Könnte man dieses „Strg+C“ auch durch einen Taster über einen GPIO-Eingang auch ausführen?
    Viele Grüße
    Achim

    • Antworten Sebastian

      Hi Achim,
      Natürlich kannst du das Script auch mit einem Taster beenden. Du fragst einfach den Eingang ab und fügst dort als Reaktion sys.exit() ein.

  34. Antworten Thomas

    Hallo,
    wie kann ich GPIO. setup(27, GPIO.OUT)
    als FALLING Flanke von GPIO. input(27)== GPIO.LOW abfragen?

    Dieses script funktioniert so weit, aber das Licht ist immer aus da keine Flankenauswertung.
    #!/usr/bin/env python
    import time
    from time import sleep
    import RPi.GPIO as GPIO
    import subprocess

    GPIO.setwarnings(False)
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(27, GPIO.OUT)

    while True:
    sleep(0.1)
    if GPIO.input(27)== GPIO.LOW:
    subprocess.call(„/home/pi/th/licht_aus.py“)
    print(„Lampe aus“)

    GPIO.cleanup()

    Kannst Du mir da bitte auf die Spruenge helfen?
    Gruss
    Thomas

  35. Pingback: Drucker automatisch starten – MyBlog

  36. Antworten Hendrik 1994

    Hallo Sebastian

    ich möchte gerne mit einer Steuerung einen Reifendruck regeln.
    zum auslesen vom Luftdruck wird ein Sensor genommen der von 0,25-4,75 Volt schaltet.
    wenn ein Schalter gedrückt wird soll der Drück über ein vor eingestellten Wert sich anpassen, entweder aufpumpen oder ablassen.
    Kannst du mir dabei helfen?
    Danke schon mal im vorraus

    • Antworten Sebastian

      Tut mir leid, das gibt meine freie Zeit leider nicht her. Aber ich drücke dir die Daumen, dass sich vielleicht jemand anderes dazu bereit erklärt.

  37. Antworten SimpleIT

    Hallo, Danke für diesen sehr interessanten Artikel ich habe jetzt nur eine Frage. Und zwar versuche ich meinen Raspberry Pi4 mit einem HifiBerry AMP2 und einem Relais (dahinter ist noch ein Bewegungsmelder) so einzurichten bzw. über ein Skript zu ermöglichen, dass sobald an dem Pi oder HifiBerry ein Signal über einen GPIO PIN ausgehend von dem Bewegungsmelder kommt, Musik abgespielt wird.
    Sobald der Bewegungsmelder kein Signal mehr bringt soll die Musik stoppen.
    Über eine Hilfe wäre ich sehr dankbar. Ich habe zwar ein grundsätzliches Skript jedoch ist das vermutlich nicht ganz performant. Als weiteres Problem ist der Service und systemd. Der Dienst wird gestartet mit dem Skript jedoch beginnt sofort die Musik an zu spielen und das nicht so wie konfiguriert sonst kreuz und quer und in einer Lautstärke wo der Nachbar die Musik noch hört.

    Evtl kann mir ja jemand helfen.

    Vielen Dank
    Gruß Fabi

Hinterlasse eine Antwort

Deine E-Mail-Adresse wird nicht veröffentlicht.

WordPress Cookie Hinweis von Real Cookie Banner