MCP23017 als Ausgang konfigurieren

JJoe
2019-02-17
2023-01-13
  • JJoe - 2019-02-17

    In einem Lehrertrainingsprojekt der deutschen Entwicklungszusammenarbeit wird der Raspberry PI 2 B mit Codesys V3.5 Sp14 eingesetzt. Neben einem Horter&Kalb digitalem Eingangsmodul wird auch ein MCP23017 verwendet. Der Baustein soll die benötigten digitalen Ausgänge zur Verfügung stellen. Das kleine Testprogramm (Bild 1) funktioniert nur, wenn ich vorher ein i2cdump dausgeführt habe und auch nur solange ich in Codesys das Programm nicht gestoppt habe. Nach dem erneuten Start muss ich wieder ein i2cdump durchführen, bevor er Ausgang reagiert.
    Die Testprogramme, die ich im Forum gefunden habe funktionieren bei mir auch nicht.

    P.S. Ein Testprogramm in Phyton funktioniert problemlos, so dass ich davon ausgehe, dass kein Hardwarefehler vorliegt. Der Raspberry ist auch komplett aktualisiert.

    Ich hoffe, dass jemand im Forum eine Lösung meines Problems hat und bedanke mich schon einmal im Voraus.

    IMG: 2.jpg

    IMG: 1.jpg

     
  • Anonymous - 2019-02-17

    Originally created by: *michi

    Hallo JJoe,

    so wie ich das verstehe, schreibst du in jedem Zyklus die Konfiguration an MCP raus. Ich vermute IO_B ist bei der Register 01.
    Die Konfiguration reicht, wenn diese einmalig gesetzt wird. Des weiteren empfiehlt es sich (wer mag) den geschriebenen Befehl erneut einzulesen, um sicher zu stellen, dass hier der korrekte Initialisierungswert übertragen wurde. By the Way... du mappst den Eingang direkt auf den Ausgang. Versuche erstmals dies mit einer Boolschen Variable. Um einzugrenzen ob dein Eingang nicht übertragen wird oder der Ausgang ein Problem hat.

    Gruß

     
  • JJoe - 2019-02-18

    Hallo Michi,
    vielen Dank für deine schnelle Antwort.
    Das Codesys Programm funktioniert so wie es programmiert ist. Aber nur dann, nachdem ich in einem Raspberry Terminal den Befehl i2cdump -y 1 0x24 durchgeführt habe. Und nur solange, bis ich das Codesys Programm stoppe.
    Viele Grüße
    JJoe

     
  • Anonymous - 2019-02-24

    Originally created by: *michi

    Hallo,

    hört sich unterm Strich so an, als würde Codesys deinen I2C nicht korrekt initialisieren, bzw. funktioniert nur der erste Teilnehmer nicht, oder beide, oder nur der zweite als Ausgang?!
    Mit dem I2cdump machst du unterm Strich nichts anderes, als ein Register lesen vom MCP23007. Es wäre wesentlich einfacher, wenn der Quellcode von deinem MCP23007 hier abgebildet wäre. Ich vermute, dass hier deine Ansteuerung in der Lib nicht korrekt ist. Was ich mir vorstellen könnte, das mit dem i2cdump die Adresse "irgendwie" gesetzt wird und du darüber Zugriff hast. Bei Stop, bzw. Reset ist diese natürlich dann 0. Das Codeschnippsl von dir ist an der Stelle nicht aussagekräftig...

     
  • laruso - 2023-01-10

    Hallo ,

    ich habe leider das gleiche Problem wenn ich das Gerät "MCP23017 IO Expansion Board" an einem BeagleBone Black betreiben möchte. Die Eingänge werden in CODESYS sofort erkannt. Die Ausgänge schalten nachdem sie in CODESYS geändert werden erst dann, wenn per linux shell einmal "i2cdump -y 2 0x27" ausgeführt wurde (die Adresse meines Boards ist ohne Veränderung 0x27 und nicht 0x20). Danach schalten sie bei jeder Änderung in CODESYS.

    Benutzt habe ich die Gerätebeschreibungsdatei und die Bibliothek von eschwellinger.
    Quelle: https://forge.codesys.com/forge/talk/Runtime/thread/8981ce928a/?page=1&limit=25#1cc1

    Im Programm verwende ich den Code von elconfa:~~~
    MCP23017_1.IO_A := 16#FF; //Input
    MCP23017_1.IO_B := 16#00; //Output

    Button_1 := MCP23017_1.IN_A.0;
    Button_2 := MCP23017_1.IN_A.1;
    Button_3 := MCP23017_1.IN_A.2;
    Button_4 := MCP23017_1.IN_A.3;
    Button_5 := MCP23017_1.IN_A.4;
    Button_6 := MCP23017_1.IN_A.5;
    Button_7 := MCP23017_1.IN_A.6;
    Button_8 := MCP23017_1.IN_A.7;

    MCP23017_1.OUT_B.0 := Rele_1;
    MCP23017_1.OUT_B.1 := Rele_2;
    MCP23017_1.OUT_B.2 := Rele_3;
    MCP23017_1.OUT_B.3 := Rele_4;
    MCP23017_1.OUT_B.4 := Rele_5;
    MCP23017_1.OUT_B.5 := Rele_6;
    MCP23017_1.OUT_B.6 := Rele_7;
    MCP23017_1.OUT_B.7 := Rele_8;
    ~~~
    Quelle: https://forge.codesys.com/forge/talk/Runtime/thread/d10648ca06/#1323

    Eine Lösung scheint hierfür leider noch nicht beschrieben zu sein.

     
  • laruso - 2023-01-13

    Ich habe eine Lösung für das Problem "die Ausgänge werden nicht gesetzt, bevor nicht ein Dump über die Linux Shell ausgeführt wurde":

    • Schnell und einfach: Ändere die vorkonfigurierten Werte der Bibliothek nach den Bedürfnissen ab. Benutze 16#FF ffür Eingänge und 16#00 für Ausgänge:
    IO_A : BYTE := 16#FF;
    IO_B : BYTE := 16#FF;
    

    • Etwas gebräuchlicher: Reinitialisiere die Port Konfiguration auf Anfrage. Füge diesen Code in der Bibliothek der Case Struktur des FB hinzu:
    10:
        IF REINIT THEN
            _iState := 0;
        END_IF
    

    Zusätzlich muss die Reinitialisierung der Port Konfiguration angefragt/angestoßen werden, nachdem das Gerät betriebsbereit (operational) ist. Und wenn man möchte kann man die Polarität der Eingänge und ob Port A/B mit Eingängen oder Ausgängen konfiguriert werden soll, zur Laufzeit ändern. Füge diesen Code oder Teile davon zu deinem Projekt hinzu:
    Deklaration:

    RTRIG_operational: R_TRIG;
    xInitialized: BOOL;
    xReinitialze: BOOL;
    xSwitchIO: BOOL;
    xSwitchIO_old: BOOL;
    xInputPolarity: BOOL;
    xInputPolarity_old: BOOL;
    
    Button_1: BOOL;
    Button_2: BOOL;
    Button_3: BOOL;
    Button_4: BOOL;
    Button_5: BOOL;
    Button_6: BOOL;
    Button_7: BOOL;
    Button_8: BOOL;
    
    Rele_1: BOOL;
    Rele_2: BOOL;
    Rele_3: BOOL;
    Rele_4: BOOL;
    Rele_5: BOOL;
    Rele_6: BOOL;
    Rele_7: BOOL;
    Rele_8: BOOL;
    

    Code:

    RTRIG_operational(CLK:=MCP23017.Operational);
    
    IF NOT xInitialized AND RTRIG_operational.Q THEN
        xReinitialze := TRUE;
        xInitialized := TRUE;
    END_IF
    
    IF xSwitchIO <> xSwitchIO_old THEN
        xReinitialze := TRUE;
        xSwitchIO_old := xSwitchIO;
    END_IF
    
    IF xInputPolarity <> xInputPolarity_old THEN
        xReinitialze := TRUE;
        xInputPolarity_old := xInputPolarity;
    END_IF
    
    IF xReinitialze THEN
        IF NOT xSwitchIO THEN
            MCP23017.IO_A := 16#FF; // Input
            MCP23017.IO_B := 16#00; // Output
        ELSE
            MCP23017.IO_A := 16#00; // Output
            MCP23017.IO_B := 16#FF; // Input
        END_IF
        IF NOT xInputPolarity THEN
            MCP23017.IPOL_A := 16#00;   // Same
            MCP23017.IPOL_B := 16#00;   // Same
        ELSE
            MCP23017.IPOL_A := 16#FF;   // Opposite
            MCP23017.IPOL_B := 16#FF;   // Opposite
        END_IF
        MCP23017.REINIT := TRUE;
        xReinitialze := FALSE;
    END_IF
    
    IF NOT MCP23017.REINIT THEN
        IF NOT xSwitchIO THEN
            Button_1 := MCP23017.IN_A.0;
            Button_2 := MCP23017.IN_A.1;
            Button_3 := MCP23017.IN_A.2;
            Button_4 := MCP23017.IN_A.3;
            Button_5 := MCP23017.IN_A.4;
            Button_6 := MCP23017.IN_A.5;
            Button_7 := MCP23017.IN_A.6;
            Button_8 := MCP23017.IN_A.7;
    
            MCP23017.OUT_B.0 := Rele_1;
            MCP23017.OUT_B.1 := Rele_2;
            MCP23017.OUT_B.2 := Rele_3;
            MCP23017.OUT_B.3 := Rele_4;
            MCP23017.OUT_B.4 := Rele_5;
            MCP23017.OUT_B.5 := Rele_6;
            MCP23017.OUT_B.6 := Rele_7;
            MCP23017.OUT_B.7 := Rele_8;
        ELSE
            MCP23017.OUT_A.0 := Rele_1;
            MCP23017.OUT_A.1 := Rele_2;
            MCP23017.OUT_A.2 := Rele_3;
            MCP23017.OUT_A.3 := Rele_4;
            MCP23017.OUT_A.4 := Rele_5;
            MCP23017.OUT_A.5 := Rele_6;
            MCP23017.OUT_A.6 := Rele_7;
            MCP23017.OUT_A.7 := Rele_8;
    
            Button_1 := MCP23017.IN_B.0;
            Button_2 := MCP23017.IN_B.1;
            Button_3 := MCP23017.IN_B.2;
            Button_4 := MCP23017.IN_B.3;
            Button_5 := MCP23017.IN_B.4;
            Button_6 := MCP23017.IN_B.5;
            Button_7 := MCP23017.IN_B.6;
            Button_8 := MCP23017.IN_B.7;
        END_IF
    END_IF
    

    Ich habe das positiv getestet mit der alten Bibliothek (gepostet von eschwellinger am 2021-11-27 https://forge.codesys.com/forge/talk/Runtime/thread/8981ce928a/?page=1&limit=25#1cc1) und mit der neuen Bibliothek (gepostet von elconfa at 2019-01-10 https://forge.codesys.com/forge/talk/Runtime/thread/a2dd4dd45f/#774c). Letztlich habe ich die neue Biliothek so erweitert, dass die Umschaltung der Polarität der Eingänge mit einer Variablen gesteuert wird:
    Deklaration:

    IPOL_A: BYTE := 16#00;  // Port A configuration: 0=same/1=opposite (INPUT POLARITY PORT REGISTER)
    IPOL_B: BYTE := 16#00;  // Port B configuration: 0=same/1=opposite (INPUT POLARITY PORT REGISTER)
    

    Code:

    STATE := STATE AND write8(16#02,IPOL_A);    //  IPOL: INPUT POLARITY PORT REGISTER
                            //      1=GPIO register bit reflects the opposite logic state of the input pin.
                            //      0=GPIO register bit reflects the same logic state of the input pin.
    STATE := STATE AND write8(16#03,IPOL_B);    //  IPOL: INPUT POLARITY PORT REGISTER
                            //      1=GPIO register bit reflects the opposite logic state of the input pin.
                            //      0=GPIO register bit reflects the same logic state of the input pin.
    
     

Log in to post a comment.