Sensoren am Raspberry PI: Taster

taster3Über die GPIO-Pins lassen sich viele schöne Sachen mit dem Raspberry PI machen. In diesem Beispiel soll über einen Taster eine LED abwechselnd ein- und wieder ausgeschaltet werden. Dabei versuche ich die gängigsten Fallstricke zu umgehen, die Schaltung möglichst fehlertolerant zu bauen und den Programmcode möglichst effizient zu gestalten.


(Der Nachbau der Schaltung und des Programmes geschehen auf eigene Gefahr)

1) Der Schaltplan

In diesem Beispiel wird ein Taster und eine LED an den Raspberry PI angeschlossen. Durch Drücken des Tasters soll die LED abwechselnd aus- und wieder eingeschaltet werden.

Eine passende Schaltung dazu habe ich hier gefunden.

taster1Als Input wird der GPIO-PIN 23 verwendet. Über einen pull-up Widerstand von 10 kΩ wird der Input an 3.3V angeschlossen und damit auf HIGH gesetzt. Theoretisch kann man auf den pull-up-Widerstand auch verzichten, da der Raspberry PI an den GPIOS eingebaute pull-up-Widerstände hat, die man per Software dazuschalten kann. Das Wort „kann“ ist hier aber der Knackpunkt. Wird das vergessen, so ist der Zustand des Inputs undefiniert und das Verhalten der Software ist zufällig. Mal geht es, mal geht es nicht. Viel Spaß bei der Fehlersuche… Deshalb soll die Schaltung möglichst fehlertolerant sein, so dass ich lieber einen eigenen pull-up-Widerstand verwende. So hat man schon einen Punkt weniger, der bei der Programmierung schiefgehen kann.

taster2 Der Taster verbindet den Pin 23 mit Ground und schaltet ihn damit auf LOW. Und schon kommen wir zu einem weiteren Punkt, der schiefgehen kann (und nach Murphys Gesetzt schiefgehen wird): Konfiguriert man den Pin versehentlich als Output und drückt den Taster, so kann es zu einem Kurzschluss kommen, welcher den Rauchgenerator des Raspberry PI aktiviert. Und bekanntlich geht das nur einmal. Aus diesem Grund ist ein weiterer Widerstand (1kΩ) eingebaut, der den Strom in diesem Fall begrenzt. Die Schaltung ist nun einigermaßen sicher und verzeiht auch Software-Fehler.

An Pin 24 ist zusätzlich noch eine LED angeschlossen. Auch LEDs müssen zwingend über einen Vorwiderstand betrieben werden (Stichwort: Rauchgenerator). In diesem Fall kommt ein 470 Ω Widerstand zum Einsatz.

Damit ist der Hardware-Teil der Schaltung abgeschlossen.

Programmierung

Mit Hilfe eines Python-Programmes soll das oben beschriebene Verhalten umgesetzt werden: Wird der Taster gedrückt geht die LED abwechselnd an und aus. Oft liest man in Büchern und Anleitungen Code wie diesen:

while True:
  input = GPIO.input(17)
  ...
  sleep(100)

Oder auch:

while True:
    GPIO.wait_for_edge(23, GPIO.FALLING)
    ...

In beiden Fällen geschieht das Auslesen des Tasters in der Hauptschleife des Programms. Das hat diverse Nachteile. Zum Einen belastet es den Prozessor unnötig und zum anderen ist das Auslesen des Tasters entweder langsam (nur 10x / Sekunde bei Fall 1) oder man kann im Programm nichts anderes machen, solange man auf den Tastendruck wartet (Fall 2). Beides ist nicht wirklich schön und zum Glück kann man es mit Hilfe von Interrupts besser machen:

toggle_led.py

import RPi.GPIO as GPIO

BUTTON = 23
LED = 24

led_on = False

GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)

GPIO.setup(BUTTON, GPIO.IN)
GPIO.setup(LED, GPIO.OUT)

def toggle_led(channel):         
    global led_on
    led_on = not led_on
    GPIO.output(LED,GPIO.HIGH if led_on else GPIO.LOW)
    print "LED: ", led_on

GPIO.add_event_detect(BUTTON, GPIO.FALLING, callback=toggle_led, bouncetime=200)     

try:
    while True:
        pass

except KeyboardInterrupt:
    print "Ctrl-C - quit"

finally:
    GPIO.cleanup() 

Die Erklärung im Einzelnen:
Zunächst die GPIO-Library importieren:

import RPi.GPIO as GPIO

Nun werden die Pins für Button und LED in Konstanten gespeichert:

BUTTON = 23
LED = 24

In dieser Variablen wird der aktuelle Zustand der LED gespeichert:

led_on = False

Es gibt verschiedene Beschriftungen für die Pins. In diesem Fall wird die BCM-Beschriftung benutzt. Außerdem werden Warnungen unterdrückt, falls die GPIO-Schnittstelle zuvor nicht richtig beendet wurde:

GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)

Nun werden die GPIO-Pins auf Input (für den Taster) und Output (für die LED) gesetzt:

GPIO.setup(BUTTON, GPIO.IN)
GPIO.setup(LED, GPIO.OUT)

Hier wird die Callback-Funktion definiert, die durch den Interrupt gerufen werden soll. Diese greift auf die globale Variable „led_on“ zu. Bei jedem Aufruf wird der Zustand der LED negiert und entsprechend geschaltet. Außerdem erfolgt eine Ausgabe auf stdout

def toggle_led(channel):         
    global led_on
    led_on = not led_on
    GPIO.output(LED,GPIO.HIGH if led_on else GPIO.LOW)
    print "LED: ", led_on

Hier wird der Interrupt definiert und die Callback-Funktion gesetzt. Ein Bouncen des Tasters wird über „bounctime=200“ verhindert.

GPIO.add_event_detect(BUTTON, GPIO.FALLING, callback=toggle_led, bouncetime=200)     

In der Hauptschleife passiert in diesem Fall gar nichts („pass“). Hier wäre Platz für jeden beliebigen Code. Die Abfrage der Taste erfolgt unabhängig davon und wird durch den Interrupt sofort ausgelöst. Um die GPIO-Schnittstelle vernünftig zu beenden, wird „Ctrl-C“ hier gefangen und auf jeden Fall vor Beendigung des Programmes ein GPIO.cleanup() ausgeführt.

try:
    while True:
        pass

except KeyboardInterrupt:
    print "Ctrl-C - quit"

finally:
    GPIO.cleanup() 

Das ganze nun starten mit:

sudo python toggle_led.py

Und schon sollte beim Drücken des Tasters die LED an- und ausgehen. Außerdem sollte in der Konsole so etwas zu sehen sein:

pi@raspberry ~/toggle_led $ sudo python toggle_led.py 
LED:  True
LED:  False
LED:  True
LED:  False
LED:  True
Ctrl-C - quit

13 Gedanken zu „Sensoren am Raspberry PI: Taster

  1. Tom

    Tolles Tutorial, das habe ich so nachgebaut als Einstieg in kleinere Schaltungen mit dem Raspi.
    Vielen Dank dafür.

    Antworten
    1. martin Beitragsautor

      Auf dem Schaltplan ist sie richtig. Eigentlich müsste sie dann auf dem Bild auch richtig herum sein, sonst hat(te) Fritzing nen Bug, als ich den Beitrag erstellt habe.

      Antworten
  2. samke

    Hi, tolles TuT :-).
    Eine Frage dazu, ich möchte mittels Taster kein Gpio steuern, ich möchte ein Udp Paket senden (Taster „ein“ soll per Udp „Taster=1“ senden).
    Wo, bzw. wie müsste ich das Script abändern? Danke für einen Tipp!

    Antworten
    1. martin Beitragsautor

      Moin,

      klar geht das.

      Einfach die Callback-Funktion von toggle_led auf send_udp ändern:
      aus
      GPIO.add_event_detect(BUTTON, GPIO.FALLING, callback=toggle_led, bouncetime=200)
      wird
      GPIO.add_event_detect(BUTTON, GPIO.FALLING, callback=send_udp, bouncetime=200)

      Und dann eine Funktion send_udp schreiben:

      def send_udp(channel):         
          UDP_IP = "192.168.xxx.xxx"
          UDP_PORT = 7777
          MESSAGE = "Taster=1"
          sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 
          sock.sendto(MESSAGE, (UDP_IP, UDP_PORT))
      

      Das Paket socket muss importiert werden. Hier ist ein Beispiel:
      https://wiki.python.org/moin/UdpCommunication
      (ich hab das selbst nicht getestet, sieht aber gut aus)

      Antworten
  3. samke

    Super, Danke für die Info – klappt 1a.
    Jetzt muss ich die ganze Funktion nur noch irgendwie in den Autostart bekommen.

    Antworten
  4. Tato

    Hi, schön erklärt, Eine frage zu dem Thema, ist es auch möglich eine LED folgendermaßen zusteuern? – Taster S1 schaltet die LED an
    – Taster S2 schaltet die LED aus

    Antworten
    1. martin Beitragsautor

      Moin Tato,

      klar ist das möglich. Der Status der LED wird ja in der variablen led_on gespeichert. Anstatt der Funktion toggle_led kann man natürlich auch je auch eine Funktion switch_led(on) schreiben und dann kannst Du mit switch_led(True) oder (False) die LED an- oder ausschalten. Entweder durch einen 2. Taster, oder irgendeinen Sensor oder wie auch immer Du möchtest. Der Phantasie sind da keine Grenzen gesetzt.

      Antworten
  5. Jürgen Gugu

    Hallo,

    es funktioniert echt gut, solange ich nur einen Taster und eine Led habe. Wenn ich mehrere nach dem gleichen System anschließe, dann wird ganz wirr geschalten. Woran kann das liegen. Wäre wirklich dankbar für Hilfe.

    Gruß
    Jürgen

    Antworten
    1. martin Beitragsautor

      Ohne den Code zu kennen und den Aufbau der Schaltung zu sehen, ist die Frage ziemlich schwer zu beantworten. Poste doch mal ein paar Details und dann guck ich mal, ob mir was auffällt.

      Antworten
      1. Jürgen Gugu

        Ich habe den Code von dir aus der Anleitung verwendet. Nur habe ich anstatt einer LED 6 Relais dran hängen. Für jedes Relais habe ich dann mit den passenden werten ein Interrupt Abfrage gemacht. Bei meiner Schaltung ist es so, daß die Taster Grundstellung geschlossen ist und somit der Grundzustand immer von GPIO auf GND geschaltet ist. Bei Betätigung öffnet der Taster und Gibt den GPIO über eine 4,7 kohm Widerstand an 3.3V ab. Hast du eine Idee woran es liegen kann?

        Antworten
        1. martin Beitragsautor

          Hallo Jürgen,

          das kann viele Ursachen haben. Sowohl beim Aufbau der Hardware als auch beim Schreiben der Software. Ich würde das auf jeden Fall Schritt für Schritt angehen. Erstmal ein Relais, dann 2, dann 3. Manchmal verwechselt man nur 2 Pins, verwendet die falsche Pin-Nummer usw.

          Ohne den Aufbau, die Software und einer Beschreibung des Ziels Deines Projektes zu kennen, kann ich leider nicht viel zur Problemlösung beitragen.

          Antworten

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.