Im zweiten Teil des Tutorials wird gezeigt, wie man mittels eines Skripts die GPIO Pins des I2C auslesen kann und Signale sendet. Außerdem wird ein Skript gezeigt, dass auf einfache User Interaktionen reagiert.
Python Skript zur Ein- und Ausgabe
Also erstellen wir ein Skript
sudo nano i2c_input_output.py
mit folgendem Inhalt:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
import smbus import time #bus = smbus.SMBus(0) # Rev 1 Pi bus = smbus.SMBus(1) # Rev 2 Pi DEVICE = 0x20 # Device Adresse (A0-A2) IODIRA = 0x00 # Pin Register fuer die Richtung IODIRB = 0x01 # Pin Register fuer die Richtung OLATB = 0x15 # Register fuer Ausgabe (GPB) GPIOA = 0x12 # Register fuer Eingabe (GPA) # Definiere GPA Pin 7 als Input (10000000 = 0x80) # Binaer: 0 bedeutet Output, 1 bedeutet Input bus.write_byte_data(DEVICE,IODIRA,0x80) # Definiere alle GPB Pins als Output (00000000 = 0x00) bus.write_byte_data(DEVICE,IODIRB,0x00) # Setze alle 7 Output bits auf 0 bus.write_byte_data(DEVICE,OLATB,0) #Funktion, die alle LEDs aufleuchten laesst. def aufleuchten(): for MyData in range(1,8): # Zaehle von 1 bis 8, was binaer # von 001 bis 111 ist. bus.write_byte_data(DEVICE,OLATB,MyData) print "Zahl:", MyData, "Binaer:", '{0:08b}'.format(MyData) time.sleep(1) # Setze wieder alle Pins auf 0 bus.write_byte_data(DEVICE,OLATB,0) #Endlosschleife, die auf Tastendruck wartet while True: # Status von GPIOA Register auslesen Taster = bus.read_byte_data(DEVICE,GPIOA) if Taster & 0b10000000 == 0b10000000: print "Taster gedrueckt" aufleuchten() |
Mit STRG + O und STRG + X speichern und beenden.
Um das Skript nun zu starten, geben wir
sudo python i2c_input_output.py
ein. Sobald du den Taster drückst fangen die LEDs an zu leuchten. Mit STRG + C kannst du das Skript abbrechen und zur Konsole zurückkehren.
Wie du siehst ist die Benutzung recht einfach und damit hat man sich weitere 16 GPIO Pins geschaffen.
22 Kommentare
Hallo Felix,
sehr gute Anleitung! Könntest du den Punkt mit dem Taster noch in die Anleitung mit aufnehmen (3,3V -> 10kOhm -> GPA7 <- Taster <-GND)? War zwar schnell gegoogelt aber der Vollständigkeit :)?
Hey,
das Tutorial ist nur ein Forsatz des ersten Teils, da ist der Aufbau angegeben 🙂
Hast du schon mal was mit dem Explorer700 von joy-it gemacht?
Hallo Felix,
danke für den Hinweis, habe das nicht im ersten Teil gefunden, daher die Anmerkung 🙂
Gibt es denn eine Möglichkeit den Status einer Reihe abzufragen?
Also den Hex Wert ob die Pins als Input oder Output definiert sind?
Ich versuche gerade ein paar Funktionen zu schreiben die mir das Umrechnen etc. erleichtern.
Kleine Anmerkung für nachfolgende Leser….
Der Taster zieht nicht die Spannung auf GND sondern gibt 3.3V auf den Eingangs-Pin.
Der Widerstand dient als Pull-Down nicht als Pull-Up!!!
Hat was damit zutun, dass der MCP23017 bei neustart und noch keiner Konfiguration die Pins als Ausgänge definiert. Hierbei wird auch die Ausgänge auf High gesetzt. Bei Tastern die auf GND ziehen würde hierbei ein Kurzschlusss geben und den Chip zerstören.
Bei 3.3V auf 3.3V passiert dabei nichts.
Moin moin,
ich habe in dem Script ein kleines Verständnisproblem. In Zeile 14 steht:
# Binaer: 0 bedeutet Output, 1 bedeutet Input
In Zeile 15 wird dann PIN 7 als Input definiert mit
bus.write_byte_data(DEVICE,IODIRA,0x80)
IODIRA hat den Wert 0x00 was ich denke auch Input aussagt.
Ist in der Erklärung dann nur ein kleiner Fehler und müsste heißen
# Binaer: 1 bedeutet Output, 0 bedeutet Input
oder versteh ich das vollkommen falsch und bin auf dem Holzweg?
Gruß
Holger
IODIRA und IODIRB haben jeweils 8 IO Pins. Bei IODIRB setzen wir alle als Output, sprich 00000000 (binär = 0x00). Bei IODIRA allerdings setzen wir einen Pin als Input und alle anderen als Output: 10000000 (binär = 0x80).
Nachdem ich mir jetzt noch mal das Datenblatt aus Teil 1 hinzugenommen habe, habe ich es endlich gerafft. 🙂 Danke
Sehr gut, kein Problem 🙂
Hallo, vorab erstmal ein Lob zu der guten Anleitung.
Allerdings habe ich immer Verständnisprobleme, wenn es um das Einlesen von Daten geht. Also die verwendung der Pins als Inputs. Ich lese ja immer ein Ganzes Byte ein. Besp.(00101010) wenn ich nun alle Pins als Eingang deklariert habe, wie kann ich nun differenzieren welches Bit auf „1“ ist? Ich möchte hinter jedes Bit eine Bedingung hängen. Also wenn Bit 2 „1“ ist machhe dies und wenn Bit 5 „1“ ist mache das.
Du hast hier diese Bedingung abgefragt: if Taster & 0b10000000 == 0b10000000
Wenn ich also alle Pins als Eingang dklariert habe,so ist die Abfrage so gut wie nie erfüllt. Wenn ich Beispielsweise Bit 7 & 8 auf „1“ habe, ist die Bedingung ja Falsch, aber mein Bit ist ja trotzdem „1“.
Ich hoffe man kann meine Verwirrung verstehen. Vielleicht drehe ich mich ja auch nur irgendwo im Kreis. Vielleicht könnt Ihr mir ja helfen
Hallo Christian,
mit dem & Operator verbindest du zwei Bits. D.h nur wenn beide Eins sind, kommt als Ergebnis eine 1. Bsp:
10000011 &
10001010
——–
10000010
Hallo!
Klasse Beitrag!
Wie schaut es aus, wenn man zwei oder mehr von den MCP23017 verwendet? Wie muss man die verdrahten? Alle parallel an den gleichen GPIO des RPi und dann nur über die Adresse ansprechen?
Ändert sich am Programmcode was, wenn ein Pi3B eingesetzt wird? Läuft der auch über SMBus(1)? Initialisierung, Programmmodule usw. – ändert sich da viel?
Laut Datenblatt verkraftet der MCP23017 125 mA Eingangsstrom/150 mA Ausgangsstrom. Wenn man 16 LEDs à 20 mA (=320 mA) an die Ausgänge schaltet, raucht der wohl ab… Selbst bei 10 mA low current LEDs wirds eng. Man könnte alle LEDs über Transistoren oder Optokoppler ansteuern. Oder gibt’s eine einfachere Lösung? Abgesehen davon gibt der Pi ja auch nicht beliebig viel her
Bei mehreren MCP23017 kommt man wohl um eine extra Stromversorgung nicht herum. 3,3 V Netzteile sind offenbar nicht verbreitet – bei 5 V schaltet aber der GPIO des Pi nicht mehr sicher, weil der MCP23017 80% seiner Versorgungsspannung braucht, um zu schalten (also 4 V) der Pi aber nur 3,3 V liefert. Wie löst man das am besten? Kann man einen 3,3 V / 800 mA Spannungsregler nehmen und dann direkt auf die Anschlüsse gehen?
Du musst darauf achten, dass alle eine andere ID bekommen. Daher können bis zu 8 (2^3) angeschlossen werden. Ich habe es zwar damals mit einem Pi1B getestet, aber daran sollte sich nichts geändert haben.
Um LEDs oder höheres zu schalten, würde ich generell immer Transistoren verwenden. Da reichen wenige mA und du kannst das Endgerät / LED auch extern mit Strom versorgen.
Falls du eine extere Versorgung nimmst, kannst du ein 5V Netzteil nehmen und dann einen 3.3V Konverter nutzen, wie ich es hier getan habe.
Hallo,
Super Tutorial. Bytes lesen und schreiben ist soweit klar… jetzt eine Frage eines Python Einsteigers: Kann ich mir das Byte was ich schreiben möchte auch irgendwie „zusammenbauen“? Was ich meine ist dass ich die einzelnen Bits aus jeweils einer Variablen auslesen möchte.
Beispiel: A1=1, A2=0, A3=0………A8=0 ==> Byte zum schreiben auf dem Ausgang: 10000000.
Das entspricht HEX 0x80… schon klar… aber wie baue ich mir das Byte zusammen?
Hat da jemand eine Idee wie das geht?
Ja, z.B. mit
0b0000001
Siehe: https://docs.python.org/3.1/library/stdtypes.html#additional-methods-on-integer-types
Hallo Felix,Danke für die Antwort.
Ich habe sehr wenig Ahnung von Python und sammle mir codeschnipsel zusammen und puzzle mir daraus ein script. Ich verstehe zwar das Prinzip wie das Byte zusammengebaut werden muss aber das in Python abzubilden ist sehr schwierig für mich.
Ich stelle mir das so vor:
byte = bin(int(0b A1 A2 A3 A4 A5 A6 A7 A8)).
Funzt so aber nicht. Wie schreibe ich diesen Befehl correct? geht das überhaupt so?
Nein, so geht das nicht. Du könntest einen String aus den Zahlen erstellen (bin_str = str(A1) + str(A2) + …) und den in eine Zahl konvertieren. Hier steht es für Hex Zahlen, aber geht equivalent: https://stackoverflow.com/questions/209513/convert-hex-string-to-int-in-python
Hallo Felix,
Das war ein Schubs in die richtige Richtung.
Meine Lösung sieht jetzt so aus:
myhex = hex(int(str(A0)+str(A1)+str(A2)+str(A3)+str(A4)+str(A5)+str(A6)+str(A7), 2))
…und das beste: es funktioniert!
Danke nochmal 🙂
Kein Problem 🙂
Hi Felix,
Sehr gutes Tutorial für den i2c bus mit python. Ich kann auch mit python umgehen, mag die Sprache aber nicht wirklich — u.a. wegen der aufgezwungenen Einrückung.
Könntest du so ein Tutorial auch noch mit node.js oder c machen?
Damit kann man meiner Ansicht nach mehr anfangen.
Liebe Grüße
Aus de palz ?
Hi Felix…
In Deinem Aufbau ist meiner Meinung nach ein kleiner, aber entscheidender Fehler..
Ich hab das mal so aufgebaut wie Du… Hatte dann das Problem, das der MCP23017 mal erkannt wurde, dann mal nicht, dan war er mal wieder da, dann wieder weg, etc… Sporadisch halt..
Ich habe dann herausgefunden, dass es an der direkten Versorgung des RESET Pins gelegen hat…
Habe dann dort einen kleinen Kondensator (220 µF) dazwischen geschaltet, der über einen Widerstand langsam geladen wird, der das RESET signal nur ein paar ms verzögert hat.. Und schon lief der Käse stabil…
Das ist besonders wichtig, wenn man mehrere MCP23017 im Bus hängen hat, sonst gibts Probleme das eben die MCP23017 mal da sind & mal nicht…
Leider gibts hier nicht die Funktion ein Bild hoch zu laden, sonst hätte ich Dir hierzu ein FRITZING Bild mit angehängt..
Servus Felix,
ich habe das Script auf meinen Raspberry pi 4 mit Phyton 3.7 eingegeben aber der Befehl in Zeile 28 bus.write_byte_data(DEVICE,OLATB,MyData) liefert keine Ausgabe ( verursacht aber auch keinen Fehler). Wenn ich anstelle von MyData z.B. 0x20 eingebe leuchtet folgerichtig die LED am Pin 5 des Port Expander. Dann geht’s aber nicht mit Schleifenzähler . Offensichtlich arbeitet der Befehl Bus.write…. nur mit Hex Zahlen, was MyData nicht ist (Integer). Der Befehl Hex () liefert aber nur einen Hex-String- geht auch nicht. Eine eigene Variable z.B. Zähler = 0x01 mit 2 multipliziert bei jeden Schleifendurchgang geht dann- ist aber nicht so elegant.
Liegt das Problem bei Pyton 3? Wie kann man einfach einen Integer in eine echte Hexadezimal Zahl umwandeln?
Danke