Stromzähler Hutschiene mit Modbus TCP

Zuviel Werbung?
-> Hier kostenlos registrieren
Hast Du in der Instanz-Variable MB_Unit_ID die RS485 Bus-Adresse des Slave eingetragen?

PS: Bei "Gateway" brauchst Du nichts eintragen, kannst aber auch die selbe IP wie bei der S7-1200 eintragen.

Harald
Hallo Harald,

ja, in der Instanz-Variable MB_Unit_ID steht die Slave Adresse 16#01.

Ich habe das Projekt hochgeladen.

Werde mir gleich ein paar Dokus reinziehen, vielleicht finde ich was...

 

Anhänge

Bin nun einen kleinen Schritt weiter.

Habe in den Parametern die Hardwarekennung hin und her verstellt,
nun tut sich was an dem MB_Client Baustein.

Die Hardwarekennung ist 66 und entspricht dem Port, wo das ModbusGateway angeschlossen ist.

Der Status des MB_Client Bausteines wechstelt nun ständig zwischen 16#8200 und 16#7004.

Etwas scheint noch an der Verbindung zu fehlen.
 

Anhänge

  • 1.png
    1.png
    1,4 MB · Aufrufe: 25
Habe bis jetzt eine Einstellung gefunden, wo die Kommunikation scheinbar aufgebaut wird:

MB_MODE = 0
MB_DATA_ADDR = 1
MB_DATA_LEN_ 8

Bei diesen Einstellungen bekomme ich den stabilen Status 16#7006

Andere Register des Slave-Bauteiles kann ich nicht wählen, denn
da bekomme ich keine Verbindung aufgebaut.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Erstmal die grundlegenden Angaben:
- Welche MLFB-Nummer (6ES7...) und welche Firmwareversion hat Deine CPU 1215?
- Welches Modbus-Gerät willst Du auslesen? Was willst Du aus dem Gerät auslesen?
- Du verwendest TIA V16?

Vermutlich willst Du 8 Halteregister lesen (Modbus Funktion 03)?
Bei MB_MODE = 0 müsstest Du bei MB_DATA_ADDR die gewünschte erste Registernummer + 40001 angeben. Oder MB_MODE 103 verwenden.
Bei Dir MB_DATA_ADDR = 16#132F = 4911 ist nicht größer als 40001 - der MB_CLIENT versucht die Ausgangs-Bits 4910 bis 4917 zu lesen (Modbus Funktion 01).

An REQ darfst Du nicht einfach einen 1Hz-Takt anlegen, sondern mußt warten, bis ein vorhergehender Auftrag beendet ist, also der MB_CLIENT nicht mehr BUSY ist bzw. mit DONE oder ERROR das Auftrag-beendet signalisiert. Das kann bei einem Auftrags-Abbruch durch Timeout auch länger als eine halbe Sekunde dauern. Erst dann darfst Du einen neuen REQ triggern.

Harald
 
Zuletzt bearbeitet:
Erstmal die grundlegenden Angaben:
- Welche MLFB-Nummer (6ES7...) und welche Firmwareversion hat Deine CPU 1215?
- Welches Modbus-Gerät willst Du auslesen? Was willst Du aus dem Gerät auslesen?
- Du verwendest TIA V16?

Vermutlich willst Du 8 Halteregister lesen (Modbus Funktion 03)?
Bei MB_MODE = 0 müsstest Du bei MB_DATA_ADDR die gewünschte erste Registernummer + 40000 angeben. Oder MB_MODE 103 verwenden.
Bei Dir MB_DATA_ADDR = 16#132F = 4911 ist nicht größer als 40000 - der MB_CLIENT versucht die Ausgangs-Bits 4910 bis 4917 zu lesen (Modbus Funktion 01).

An REQ darfst Du nicht einfach einen 1Hz-Takt anlegen, sondern mußt warten, bis ein vorhergehender Auftrag beendet ist, also der MB_CLIENT nicht mehr BUSY ist bzw. mit DONE oder ERROR das Auftrag-beendet signalisiert. Das kann bei einem Auftrags-Abbruch durch Timeout auch länger als eine halbe Sekunde dauern. Erst dann darfst Du einen neuen REQ triggern.

Harald
Hallo Harald,

- Welche MLFB-Nummer (6ES7...) => 6ES7 215-1AG40-0XB0
und welche Firmwareversion hat Deine CPU 1215? => V4.4 im Projekt V4.5 die Hardware
- Welches Modbus-Gerät willst Du auslesen? => Das ist ein Durchflusszähler von Enderess Hauser Promag400
Was willst Du aus dem Gerät auslesen? => Zuerst nur ein Holding Register (Baudrate: mit der Adresse: 4912)
- Du verwendest TIA V16? => Ja

Das mit der Modbusfunktion und dem Request schaue ich mir gleich mal an!
 
Harald, Danke für Deine Hilfe!
Jetzt scheint alles zu funktionieren,
ich bekomme Daten in die Steuerung! :)

Den MB-Modus habe ich, wie du es empfohlen hast, auf 103 gestellt
und den Request-Eingang entsprechend verschaltet!

Werde mich nun ein wenig mit den Daten auseinandersetzen.
 

Anhänge

  • 2.png
    2.png
    1,3 MB · Aufrufe: 19
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich würde zum ersten Test die Busadresse Register 4910 lesen, da weiß man welcher Wert kommen muß und sieht wie die Bytereihenfolge eingestellt ist.
Zum Lesen des Registers 4910 verwende diese Eingangsparameter:
MB_MODE = 0
MB_DATA_ADDR = 44911
MB_DATA_LEN = 1 (oder mehr)

oder
MB_MODE = 103
MB_DATA_ADDR = 4910
MB_DATA_LEN = 1 (oder mehr)


Harald
 
Hallo Harald,

ich bin auf ein Problem gestoßen:

Die Daten des Modbus-Slaves sind von den Adressen her sehr verstreut.
Der rahmen, in dem die benötigeten Daten liegen umfasst eine Größe von ca. 1000Worten.

Es ist ja klar, dass man keine 1000Worte aus dem Gerät lesen soll.

Die Frage ist, wie gehe ich mit dem MB_Client Baustein um, damit ich jeweils die benötigten Daten bekomme.

Mein Ansatz wäre:
Den selben "MB_Client Baustein"-Bautein in einem Programm
immer wieder aufzurufen und die
Übergabe-parameter: MB_DATA_ADDR , MB_DATA_LEN und MB_DATA_PTR
je nach Parameter anzupassen.

Gibt es da vielleicht eine elegentere Methode?

Eine Frage am Rande:
Kann man ein Modbus-Slave-Gerät nicht über den Eingangs- und Ausgangs-Adressbereich lesen?
Also ein Modbus-TCP-Gerät in der Hardware-Konfig anlegen?
Das wäre doch am Einfachsten oder?
 
Mein Ansatz wäre:
Den selben "MB_Client Baustein"-Bautein in einem Programm
immer wieder aufzurufen und die
Übergabe-parameter: MB_DATA_ADDR , MB_DATA_LEN und MB_DATA_PTR
je nach Parameter anzupassen.
Ja, Schrittkette und nacheinander die verschiedenen Parameter abfragen. Dazu jeweils die Modbus-Adressparameter je Leseauftrag anpassen. Ich würde immer die selbe MB_CLIENT-Instanz verwenden.

Kann man ein Modbus-Slave-Gerät nicht über den Eingangs- und Ausgangs-Adressbereich lesen?
Also ein Modbus-TCP-Gerät in der Hardware-Konfig anlegen?
Nein, geht nicht. In HW Konfig kann man nur Geräte mit Profinet-IO- oder Profibus-DP-Schnittstellen an E/A-Adressen anbinden. Oder Du bräuchtest ein konfigurierbares Gateway/Koppler Modbus zu Profinet oder Profibus.

Harald
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich komme nicht wirklich beim Lesen verschiedener Adressen durch den BM_Client voran.

Vorallem glaube ich, dass mein Problem an dem richtigen Schalten des Request-Einganges liegt.

Kann mir Jemand sagen, wie Ihr den Request-Eingang richtig schaltet?


Hier ist mein Programm:

Von dem Schritt 300 bis 305 wird die Kommunikation aufgebaut.

Ab den Schritt 310 werden die Register gelesen:
Zuerst wird ein Register Adressiert und ein Request gestartet.

Sobald die Rückmeldug
(#x_Client_Busy = false AND #x_Client_Done) OR (#x_Client_Error AND "Clock_10Hz")
erfüllt wird, weden die gelieferten Werte verarbeitet und anschließend ein anderes Register gelesen.

Leider habe ich mit der Rückmeldung nicht das gewünschte Ergebnis,
machmal liefert der Baustein die Daten und manchmal auch nicht.
Es kommt es vor, dass Busy und Done gleichzeitig FALSE sind.
Auch Error ist machmal FLASE, sodass die Schrittkette hängen bleibt.

Ich bekomme auch manchemal den Status: 8200:
Parameter STATUS (S7-1200, S7-1500)
  • Eine andere Modbus-Anfrage wird zur Zeit über den Port verarbeitet.
  • Eine weitere Instanz von MB_CLIENT mit den gleichen Verbindungsparametern bearbeitet eine bereits bestehende Modbus-Anfrage.

Ich frage mich ob ich durch das Rumprobieren irgendetwas eingefügt habe, was jetzt stört.


Code:
IF #x_Start AND #i_state < 300 AND #x_Stop = false
THEN
    #i_state := 300;
END_IF;

IF #x_Stop THEN
    #i_state := 0;
END_IF;

(*
IF #x_Client_Error THEN
    #i_state := 300;
END_IF;
*)

CASE #i_state OF
      
    0:
      
        #x_Clienr_Request       := false;
        #x_Client_Disconnect    := false;
      
      
      
      
    //Start 
    300:
      
        #x_Clienr_Request := true;
        #x_Client_Disconnect := true;
      
      
      
        IF #w_Client_Status = 16#7000 THEN
            #i_state := 305;
        END_IF;
      
        IF #x_Client_Done THEN
            #i_state := 301;
        END_IF;
      
        IF #x_Client_Busy THEN
            #i_state := 302;
        END_IF;
      
    305:
        #x_Client_Disconnect := false;
        #x_Clienr_Request := false;
      
        IF #w_Client_Status = 16#7004 THEN
            #i_state := 310;
        END_IF;
      
      
    //Connection established 

  
    //Read Register
    310:
        #udi_Client_Register := 4909; //Bussadresse
        #x_Clienr_Request := true;
        IF (#x_Client_Busy = false AND #x_Client_Done) OR (#x_Client_Error AND "Clock_10Hz")
        THEN
            #i_state := 315;
        END_IF;
    315:
        #x_Clienr_Request := false;
        #dData.iBussadresse := WORD_TO_INT(#w_Client_Data[0]);
        IF #w_Client_Status = 16#7004 THEN
            #i_state := 320;
        END_IF;
      
    320:
        #udi_Client_Register := 4911; //Baudrate
        #x_Clienr_Request := true;
        IF (#x_Client_Busy = false AND #x_Client_Done) OR (#x_Client_Error AND "Clock_10Hz")
        THEN
            #i_state := 325;
        END_IF;
    325:
        #x_Clienr_Request := false;
        #dData.iBaudrate := WORD_TO_INT(#w_Client_Data[0]);
      
        IF #w_Client_Status = 16#7004 THEN
            #i_state := 330;
        END_IF;
      
    //Read Register 
    330:
        #udi_Client_Register := 4912; //Modbusdatenübertr
        #x_Clienr_Request := true;
      
        IF (#x_Client_Busy = false AND #x_Client_Done) OR (#x_Client_Error AND "Clock_10Hz")
        THEN
            #i_state := 335;
        END_IF;
    335:
        #x_Clienr_Request := false;
        #dData.iModBusDatenuebertr := WORD_TO_INT(#w_Client_Data[0]);
        #i_state := 345;
      
    //Read Register     
    345:
        #udi_Client_Register := 4913; //Parität
        #x_Clienr_Request := true;
      
        IF (#x_Client_Busy = false AND #x_Client_Done) OR (#x_Client_Error AND "Clock_10Hz")
        THEN
            #i_state := 350;
        END_IF;
    350:
        #x_Clienr_Request := false;
        #dData.iParitaet := WORD_TO_INT(#w_Client_Data[0]);
        #i_state := 355;
      
      
    //Read Register     
    355:
        #udi_Client_Register := 2259;//3873; //Volumenfluss
        #x_Clienr_Request := true;
      
        IF (#x_Client_Busy = false AND #x_Client_Done) OR (#x_Client_Error AND "Clock_10Hz")
        THEN
            #i_state := 360;
        END_IF;
    360:
        #x_Clienr_Request := false;


        #Byte0 := #w_Client_Data[0].%B0;
        #Byte1 := #w_Client_Data[0].%B1;
        #Byte2 := #w_Client_Data[1].%B0;
        #Byte3 := #w_Client_Data[1].%B1;
      
      
        #tempWord0 := (SHL(IN := BYTE_TO_WORD(#Byte1), N := 8)) OR #Byte0;
      
        #tempWord1 := (SHL(IN := BYTE_TO_WORD(#Byte3), N := 8)) OR #Byte2;
      
      
        #dData.rVolumenfluss := DWORD_TO_REAL(SHL( IN:= WORD_TO_DWORD(#tempWord0), N:= 16) OR WORD_TO_DWORD(#tempWord1));

        #i_state := 365;
      
    365:
        IF (#x_Client_Busy = false AND #x_Client_Done) OR (#x_Client_Error AND "Clock_10Hz") OR "Clock_0.5Hz"
        THEN
            #i_state := 310;
        END_IF;
END_CASE;
 

Anhänge

Habe mein Programm überarbeitet, das Problem war die falsche Ansteuerung des Request-Einganges an dem Baustein.

Werde mich gleich mit dem Schreiben der Modbus-Register beschäftigen.

Code:
//Read Modbus TCP-Data
//The Stucture sData contains the Arrays for the Registers to be read.
//The user has to tyte-in the Adress into the RagAdr fields,
//The corresponding data will be filled-in the Array by reading the device

IF #x_Start AND #i_state < 300 AND #x_Stop = false
THEN
    #i_state := 300;
END_IF;

IF #x_Stop THEN
    #i_state := 0;
END_IF;

CASE #i_state OF
    //Stop  
    0:
        #x_Client_Request := false;
        #x_Client_Disconnect := true;
       
    //Start  
    300:
       
        #x_Client_Request := true;
        #x_Client_Disconnect := false;
       
        #retTime := RD_SYS_T(#t1);
       
       
        IF #w_Client_Status = 16#7000 OR #w_Client_Status = 16#7006 THEN
            #i_state := 305;
        END_IF;
       
    305:
        #retTime := RD_SYS_T(#t2);
        #difTime := TIME_TO_UDINT(T_DIFF(IN1 := #t2, IN2 := #t1));
       
        #x_Client_Request := false;
       
        IF #w_Client_Status = 16#7004
            OR #difTime > #udi_JitterMax
        THEN
            #retTime := RD_SYS_T(#t1);
            #i_state := 310;
        END_IF;
       
    //Connection established    
    310:
       
        CASE #i_stateRead OF
            0:
                #i := 0;
                #i_stateRead := 2;
               
            2:
                IF #i <= 19 THEN
                    #i_stateRead := 3;
                ELSE
                    #i := 0;
                    #i_state := 300;
                END_IF;
           
            3:
                //Select the Adrress to be read
                #udi_Client_Register := #sData[#i].RegAdr;
               
                IF #x_Client_Busy = false THEN
                    #retTime := RD_SYS_T(#t1);
                    #x_Client_Request := true;
                    #i_stateRead := 5;
                END_IF;
               
            5:
                #retTime := RD_SYS_T(#t2);
                #difTime := TIME_TO_UDINT(T_DIFF(IN1 := #t2, IN2 := #t1));
               
                IF #x_Client_Busy THEN
                    #x_Client_Request := FALSE;
                END_IF;
               
                IF ((#x_Client_Busy = false AND #x_Client_Done)
                    OR (#x_Client_Error AND "Clock_10Hz"))
                    OR (#difTime > #udi_JitterMax)
                THEN
                    #retTime := RD_SYS_T(#t1);
                    #i_stateRead := 10;
                END_IF;
               
            10:
                #retTime := RD_SYS_T(#t2);
                #difTime := TIME_TO_UDINT(T_DIFF(IN1 := #t2, IN2 := #t1));
               
                #sData[#i].Word0 := (#w_Client_Data[0]);
               
                IF #w_Client_Status = 16#7004 OR #difTime > #udi_JitterMax
                THEN
                    #retTime := RD_SYS_T(#t1);
                    #i_stateRead := 30;
                END_IF;
               
            30:
                #i := #i + 1;
                #i_stateRead := 2;
        END_CASE;
END_CASE;
 

Anhänge

Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Nun versuche ich händisch ein Register in dem Modbus-Gerät über den Baustein MB_CLient zu schreiben.
Dies hat paar mal funktioniert und jetzt nicht mehr 🥴
Oh man....

Habe als MB_MODE 105 genommen und schreibe 1 Wort auf ein Register.

Vielleicht muss ich noch eine Nacht drüber schlafen.
 
Habe mitlerweile auch das Schreiben hinbekommen.

Hier ist mein Projekt:

Es wird ein Stromzähler: HAGER ECA380D, welcher eine Modbus RTU Schnittstelle hat über das Gateway (Modbus TCP) USR-DR302
angesteuert.
Es werden Parameter gelesen und geschrieben.

Später mache ich noch die VISU dazu.

Harald, vielen Dank für deine Unterstützung!
 

Anhänge

Zurück
Oben