[MCP23017] Register und Python

Heute ist Stammtischzeit:
Jeden Donnerstag 20:30 Uhr hier im Chat.
Wer Lust hat, kann sich gerne beteiligen. ;)
  • Guten Abend liebe Raspberry Pi Freunde,

    an dieser Stelle nutze ich in meinem 1. Beitrag kurz die Möglichkeit mich vorzustellen: Ich bin als Elektroniker für Betriebstechnik in der Photovoltaikbranche tätig und bilde mich im Rahmen des Teilzeit Elektrotechnikers FR Datenverarbeitung derzeit am DAA-Technikum fort (3. Semester Grundstudium). :sleepy:
    Ich hoffe in diesem Forum Hilfe bei Problemchen in Sachen Pythonprogrammierung zu finden. An dieser Stelle gleich mal zu meiner derzeitigen Frage:

    Es geht um den Portexpander MCP23017:

    Schreibe ich hex 0x00 (00010000) ins OLAT Register setze ich durch die 8bits jeden Wert der 8GPIO von Bank A auf LOW. Nehmen wir an, dass nun lediglich GPA4 auf HIGH gesetzt wird, schreibe ich 0x10 (00010000) ins OLAT Register. Soweit so gut...
    Angenommen GPA4 ändert zeitversetzt seinen Wert von LOW auf HIGH (LED blinken) und ich möchte währenddessen GPA5 durch 0x20 (00100000) auf HIGH setzen, so weiß ich den derzeitigen Wert von GPA4 nicht und würde diesen mit 0x20 (00100000) auf LOW schreiben.

    An dieser Stelle bräuchte ich etwas Starthilfe was den Python Code angeht. Wie realisiert man evlt. eine Abfrage der gesamten Bank A? oder wie löst ihr sowas um den derzeitigen Zustand der restlichen GPIO nicht zu verändern? :helpnew:

    Würde mich freuen wenn jemand ein paar Zeilen Beispielcode posten könnte woran ich aufbauen kann.

    Ich danke euch :danke_ATDE:

    Gruß
    opc

  • Hallo.


    Es geht um den Portexpander MCP23017:

    Schreibe ich hex 0x00 (00010000) ins OLAT Register setze ich durch die 8bits jeden Wert der 8GPIO von Bank A auf LOW. Nehmen wir an, dass nun lediglich GPA4 auf HIGH gesetzt wird, schreibe ich 0x10 (00010000) ins OLAT Register. Soweit so gut...
    Angenommen GPA4 ändert zeitversetzt seinen Wert von LOW auf HIGH (LED blinken) und ich möchte währenddessen GPA5 durch 0x20 (00100000) auf HIGH setzen, so weiß ich den derzeitigen Wert von GPA4 nicht und würde diesen mit 0x20 (00100000) auf LOW schreiben.


    hm... ganz verstanden hab ich das nicht, aber ich denke mit Bank A meinst den MCP.
    Aber wenn du was tust, und bekommst eine GPAx Änderung angeblich nicht mit, geht das sehr wohl.
    Les dir mal diese pigpio Library durch.
    Da gibt es unter anderem die Funktion:

    Code
    gpioSetAlertFuncEx	Request a gpio change callback, extended


    Also Flankengesteuerter Interrupt, der dir das Problemchen abnimmt.
    Mal in Ruhe durchlesen.
    Der MCP kann ja so eingestellt werden, bei Signalwechseln nen Int auszulösen.

    Weiterhin gibt es die Möglichkeit mit dieser Lib auch mit Bank's zu arbeiten.
    Erspart z.B bei ner 8Bit Ausgabe an die GPIO's lästiges shiften.

    Code
    gpioRead_Bits_0_31	Read all gpios in bank 1
    gpioRead_Bits_32_53	Read all gpios in bank 2
    
    gpioWrite_Bits_0_31_Clear	Clear selected gpios in bank 1
    gpioWrite_Bits_32_53_Clear	Clear selected gpios in bank 2
    
    gpioWrite_Bits_0_31_Set	Set selected gpios in bank 1
    gpioWrite_Bits_32_53_Set

    Python hab ich abgelegt, also mit Code Beispielen in Python muss ich da passen, in C ja.
    Diese Lib ist auch für Python.
    vlt. hilft es dir weiter.

    gruß root

  • Zitat


    Les dir mal diese pigpio Library durch.
    Da gibt es unter anderem die Funktion:

    Code
    gpioSetAlertFuncEx	Request a gpio change callback, extended


    Also Flankengesteuerter Interrupt, der dir das Problemchen abnimmt.
    Mal in Ruhe durchlesen.
    Der MCP kann ja so eingestellt werden, bei Signalwechseln nen Int auszulösen.


    Hallo root,

    da liegst du bei meiner Frage schon richtig, das habe ich gemeint. Die Lösung der Pinabfrage bevor weitere Werte ins Register geschrieben werden.
    Mir ist ansonsten keine Lösung bekannt nur einzelne Pins zu beschreiben ohne eine Abhängigkeit anderer zu haben.
    In diesem Sinne werde ich mir diese pigpio library mal zu Gemüte führen... :danke_ATDE:


    Zitat


    Weiterhin gibt es die Möglichkeit mit dieser Lib auch mit Bank's zu arbeiten.
    Erspart z.B bei ner 8Bit Ausgabe an die GPIO's lästiges shiften.

    So kann nur die ganze Bank abgefragt werden und an der Stelle geht es mir darum nach dem Auslesen aller Werte, einzelne zu ändern und die restlichen in ihrem Wert zu belassen. Dafür brauch ich eben nur noch den Code :thumbs1:

    Einmal editiert, zuletzt von opc241 (28. Dezember 2014 um 12:09)

  • Hallo.


    [quote]
    ...und an der Stelle geht es mir darum nach dem Auslesen aller Werte, einzelne zu ändern und die restlichen in ihrem Wert zu belassen.

    Genau das ist doch damit möglich.
    Also:
    mit

    Code
    uint32_t gpioRead_Bits_0_31(void)
    Returns the current level of gpios 0-31


    Liest du ne komplette GPIO Bank, bzw die Bit's die du brauchst.
    Dann änderst du Bits nach deinem Gutdünken und schreibst wieder zurück mit:

    Code
    int gpioWrite_Bits_0_31_Set(uint32_t bits)
    
    
    Sets gpios 0-31 if the corresponding bit in bits is set. 
    
    
    bits: a bit mask of gpios to set


    und somit sofort an die GPIO's.
    wichtig ist der Satz:

    Code
    Sets gpios 0-31 if the corresponding bit in bits is set.


    d.h. Werte die du belassen willst, müssen negiert werden.
    Die korrespondierenden Bit's sind dann 0, und der Wert wird belassen.

    Hoffe ich habe mich verständlich ausgedrückt.
    gruß root

    Einmal editiert, zuletzt von root (28. Dezember 2014 um 15:54)

  • In diesem Fall muss ich gestehen, dass ich etwas überfordert bin mit der Zusammensetzung des Codes. Am liebsten wär mir ein Beispielcode in Sachen Interruptabfrage am MCP. Vlt. hat sich schonmal jemand damit auseinandergesetzt und würde mir seinen Code zur Verfügung stellen? :thumbs1:

    Sämtliche zusammengeschnipselten Versuche gingen leider schief, da ich es gewöhnt bin mit Python nur die GPIO´s am Pi zu bearbeiten -ohne den MCP.. Expander.

    Würde mich über weitere Hilfe freuen :danke_ATDE:

    Gruß
    opc

    Einmal editiert, zuletzt von opc241 (29. Dezember 2014 um 22:50)

  • Hallo.


    In diesem Fall muss ich gestehen, dass ich etwas überfordert bin mit der Zusammensetzung des Codes. Am liebsten wär mir ein Beispielcode in Sachen Interruptabfrage am MCP.


    Sorry, ich glaube da haben wir kräftig aneinander vorbeigeredet.
    Das bezog sich auf die interne GPIO Banks, und nicht die des MCP's.
    Interrupts vom MCP mit Python ist sicher möglich.

    Wie gesagt, hab ich mit Python nix mehr am Hut.(das Ding hat in meine Augen furchtbare Macken... meine Meinung)
    Aber da wird sich sicher einer melden. :thumbs1:

    Nix für ungut, und weiterhin gutes gelingen
    gruß root

    Einmal editiert, zuletzt von root (29. Dezember 2014 um 23:48)

  • Zitat


    Sorry, ich glaube da haben wir kräftig aneinander vorbeigeredet.

    Kein Problem, somit ist mein Problem jetzt auch jedem klar geworden denk ich mal :thumbs1:

    Ich möchte schlichtweg mit Pyhton eine Interrupabfrage vom MCP realisieren, geknüpft mit einer Pinabfrage um nach dem setzen der Bits nicht jeden Ausgang im Wert zu verändern, sondern auf HIGH gesetzte auch auf HIGH belassen zu können.

    Einmal editiert, zuletzt von opc241 (30. Dezember 2014 um 13:30)

  • Ich habe ein erstes Skript auf die Beine gestellt, welches mich viel Zeit und Blätter im Datenblatt gekostet hat und leider so noch nicht funktioniert :(

    Aufgabenstellung ist weiterhin, es soll auf einen Interrupt reagiert werden und in der while Schleife einen Text ausgeben. Starte ich das Skript, fragt er durch "read" zwar die Bits von Bank A ab und setzt je nach Stand der Werte auch die If-Bedingung, allerdings nur 1x. Ändere ich mein Inputsignal muss ich mein Skript neustarten um den veränderten Wert abzufragen- und verändern zu können. Ich dachte durch "pass" kann ich die while Schleife verlassen und von vorne beginnen mit der Abfrage.

    Hier der Code: (achtet nicht zu sehr auf den Text hinter den Hashtags, die Werte hab ich testweise geändert, den Text nicht... stimmt also evlt. nicht mehr überein) :stumm:

    Einmal editiert, zuletzt von opc241 (31. Dezember 2014 um 12:56)

  • ``pass`` macht einfach gar nichts. Also ein Platzhalter für Nichts. Das Problem bei dir ist, dass du mit ``read = bus.read_byte_data(mcp,gpioa)`` nur 1x den Wert der Variable ``read`` zuweist. Du möchtest aber, dass ``read`` immer wieder mit neuen Werten bekommt.

    Ich würde mich nun in den kommenden Tagen mit Funktionen auseinender setzen und den Code aufräumen um Wiederholungen zu vermeiden.

  • Zitat


    Du möchtest aber, dass ``read`` immer wieder mit neuen Werten bekommt.

    Richtig :bravo2:

    Zitat


    Ich würde mich nun in den kommenden Tagen mit Funktionen auseinender setzen und den Code aufräumen um Wiederholungen zu vermeiden.

    Ich gehe davon aus, dass der Teil meines Codes oberhalb der while-Schleife passt, also werde ich deinem Tipp bezüglich der Funktionen nachgehen danke dir :danke_ATDE:

  • Ein Hallo zu später Stunde :sleepy:

    bootsmann: Bin deinem Tipp mit den Funktionen nachgegangen und habe den Chip nun endlich zufriedenstellend zum Laufen bekommen, ein danke an dich an der Stelle :danke_ATDE:

    Der Code ist zwar nun funktionstüchtig, jedoch bin ich mir sicher es geht noch besser in Sachen Komprimierung. Meine Lösung ist derzeit in etlichen If-Bedingungen geschrieben wobei sich mir diesbezüglich die Frage stellt, wie man diesen "elif-Haufen" etwas aufräumen kann...
    Wie lassen sich die auszulesenden mit den zu schreibenden Werten einfacher zuordnen, falls noch ein paar mehr In- und Outputs dazukommen könnte es so schnell unübersichtlich werden....? ggf. in Listen oder wie ist hier das Stichwort? :shy:

    Hier mein derzeitiger Code ohne die obigen Zuweisen aus meinem vorherigen Skript.
    Hier die Aktualisierung:

    (der Übersicht-wegen hab ich für mich z.T. binärzahlen geschrieben, also nicht wundern warum mal hex und mal binär... X1 und X2 stellen testweise zwei LED´s dar...)

    Einmal editiert, zuletzt von opc241 (2. Januar 2015 um 03:35)

  • Hi,

    Ein paar Ideen hätte ich da schon...

    Als erstes würde ich die ganzen überflüssigen pinread() Aufrufe die direkt unter bus.write_byte_date() gemacht werden entfernen. Die sind nämlich für die Katz.
    Was wolltest du damit bezwecken?

    Dann würde ich die Funktion pinread() nicht mit jedem if Test ausführen sondern nur einmal am Anfang der Schleife und den Wert in einer Variable zwischenspeichern. Die Variable kann man dann für alle Tests verwenden.

    Und dann könntest du noch die ersten beiden Bedingungen mit einem ODER verknüpfen. Dabei bin ich mir aber nicht sicher ob noch Klammern gesetzt werden müssen.

    (Ich habe auch den Namen der Funktion die den Port A des MCP ausliest umbenannt. pinread() trifft es wie ich finde nicht so gut wie readPortA(). Port = Bank). Dabei habe ich auch gleich noch die zwei Zeilen der Funktion in einer einzelnen zusammengefasst.
    Hier das Schnipsel mit den Änderungen:

    Grüße,
    Joh

    DON'T PANIC!

  • Also ich hab mit der RPi.GPIO Bibliothek noch nicht viel gemacht, habe da eher mit WiringPi rum gespielt, aber dort gibt es eine Funktion, um Schieberegister oder Port-Expander so einzurichten, das man denen z.B. Pin Nummer 100 bis 107 (für 8bit) zuweisen kann. Wenn man dann einfach z.B. Pin 103 auf HIGH setzt erledigt die Bibliothek das ganze Bitschieben für einen, und beachtet dabei auch welche Werte der Register aktuell hat.

    Klar kann man das alles auch von Hand machen, aber warum immer das Rad neu erfinden? Schau mal ob es in der Bibliothek auch so eine Funktion gibt. Würde das ganze dann ja stark vereinfachen.

  • joh.raspi: Danke für die Tipps, hab diese direkt angewendet. Ein Setzen von Klammern in der ODER-Verknüpfung war nicht mehr nötig. mit der Bezeichnung pinread() komm ich bestens klar :thumbs1:

    RyuKajiya: mit wiringPi hab ich noch nicht gearbeitet. Diese von dir genannte Möglichkeit Ports und Register zu bearbeiten hört sich zwar einfacher an als meine "manuelle" Vorgehensweise... an der Stelle mach ichs aber lieber kompliziert, erhöht erstmal den Lerneffekt und hält die Hirse fit :bravo2:

    Wenn noch jemand eine Lösung zur Vereinfachung der Zuweisungen hat, ich bin dankbar für jeden Tipp :thumbs1:

    In diesem Sinne, danke für eure Tipps und Unterstützung -> alle Fragen beantwortet vorerst :danke_ATDE::bravo2:

    Einmal editiert, zuletzt von opc241 (2. Januar 2015 um 17:56)

  • Dieser Thread ist schon etwas aelter, aber hier dennoch mein Loesungsansatz :D :

    Um Bits innerhalb eines Bytes zu manipulieren ist "bitwise" Manipulation mit log. Operatoren und Bit-Masken sinnvoll.
    Die fokussierten Register des MCP23017 muessen also bei jedem i2c-write komplett gesetzt werden. Dabei sind die vorherigen Zustaende der nicht betrachteten Bits, zusammen mit den gaenderten Bits als ein neues Byte in das betroffene Register zu schreiben.

    Beispiele zum Testen in Python:


    1.) Ausgabe von dez 228 im Binaerformat

    Code
    >>> print('{:08b}'.format(228))
    11100100


    2.) Bit1 auf 1 setzen, ohne die restlichen Bits im Ausgangswert zu aendern

    • Ausgangszustand: der dezimale Wert 228, entspricht binaer 11100100 und ist gegeben
    • Absicht: Bit1 auf 1 setzen ohne Bit0 sowie Bit2-Bit7 zu aendern
    • Lösung: gegebenen Wert binaer ueber "log. ODER" mit der Bit-Maske der zu setzenden Bits verknuepfen
    • Vorgehen: Bit-Maske efinieren ... fuer Bit1 = 1 ergibt sich Bit-Maske 00000010 = dezimal 2
    • 11100100 ODER 00000010 = 11100110; Python-Operator fuer "log. ODER" = "|"
    Code
    >>> print('{:08b}'.format(228 | 2))            
    11100110

    3.) Bit1 auf 0 setzen, ohne die restlichen Bits im Ausgangszustand zu aendern

    • Ausgangszustand: der dezimale Wert 230, entspricht binaer 11100110 und ist gegeben
    • Absicht: Bit1 auf 0 setzen ohne Bit0 sowie Bit2-Bit7 zu aendern
    • Lösung: gegebenen Wert binaer ueber "log. UND" mit der negierten Bit-Maske der zu setzenden Bits verknuepfen
    • Vorgehen: Bit-Maske definieren ... fuer Bit1 = 1 ergibt sich Bit-Maske 00000010 = dezimal 2
    • 11100110 UND (NICHT(00000010)) = 11100100; Python-Operator fuer "log. UND" = "&", fuer "NICHT" = "~"
    Code
    >>> print('{:08b}'.format(230 & ~2))            
    11100100

    4.) Multiple Bits in einem Durchgang aendern ...

    Code
    >>> print('{:08b}'.format(228 | 3))  # gegeben: dez 228; bin 11100100; Bit0 und Bit1 setzen; Bit-Maske 00000011 entspricht dez 3
    11100111
    >>> print('{:08b}'.format(231 & ~3)) # gegeben: dez 231; bin 11100111; Bit0 und Bit1 löschen; Bit-Maske 00000011 entspricht dez 3 
    11100100


    Skript-Beispiel (unter Verwendung des SMBUS-I2C-Moduls):

    SMBUS kommt mit Hex-Werten im Format 0x00 und Dez-Werten im Integerformat, auch gemischt, zurecht.
    Das Integerformat funktioniert in diesem Zusammenhang, bis jetzt, sehr gut.
    Die Bit-Masken lassen sich recht gut und schnell mit Integer-Werten festlegen.
    TIP: Etwas Ordnung bei der Zuweisung / Verschaltung der General Purpose Pins am MCP23017 erspart heftigste Kopfschmerzen :D

    Ein Problem, mit dem ich in diesem Zusammenhang, noch kaempfe:
    Jeder Veränderung der MCP23017-Register-Bits muss ein Auslesen des betroffenen Registers vorweg gehen, um eine Ausgangsbasis zur Bit-Manipulation zu schaffen.
    Unnötige I2C-Transfer (z.B.: Register auslesen) ist aber unschoen, besonders wenn rel. viele Daten transferriert werden muessen.
    Ich ueberlege daher, die Register-Werte nicht immer aus dem MCP23017 auszulesen, sondern groesstenteils innerhalb des Programms in Variablen zu fuehren bzw. zu aendern. Wenn die Variablen aber nicht mehr die aktuellen Werten habe, wird ggf. das ganze Programm inkonsistent. Eine gute Mischung zwischen Auslesen und in Fuehren in separaten Variablen muss gefunden werden ... :s

Jetzt mitmachen!

Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!