Modbus "FbDigitalTwinMbSlaveDevice"

bbm1995

Level-2
Beiträge
54
Reaktionspunkte
5
Zuviel Werbung?
-> Hier kostenlos registrieren
Guten Tag miteinander!

Ich versuche derzeit meine Steuerung zu optimieren und würde gerne wissen ob es eine andere oder einfachere Möglichkeit gibt, die FbDigitalTwinMbSlaveDevice zu implementieren.
Ich habe in der ersten Version 172 Modbusanfragen die ~45sek brauchen bis alle Werte abgefragt werden.
Code:
FUNCTION_BLOCK FbQueryRead EXTENDS WagoAppPlcModbus.FbDigitalTwinMbSlaveDevice
VAR
    r_FbQuery:        ARRAY[1..172] OF FbQuery(THIS^) :=
                    [
                      (* Digital Variables (Coils) *)
                       (* Unit Status *)
                        ( _bFunctionCode := 2, _uiReadAddress := 001, _uiReadQuantity := 1),
                        ( _bFunctionCode := 2, _uiReadAddress := 002, _uiReadQuantity := 1),

                        etc...
Meine Idee wäre, die 172 Adressen mit "ReadQuantity" zusammenzufassen und zu gruppieren in einer separaten GVL, leider habe ich ein Verständnisproblem mit (THIS^) und allgemein finde ich keinen Lösungsweg für mein Ziel.
Der Grund ist, dass ich für die Visualisierung z.b. Temperaturanzeigen öfter abfrage als die Alarme von 2 Klimageräten.
Code:
    aQL_rStatus:    ARRAY[1..3] OF FbQuery() :=
                    [
                      (* Unit Status *)
                       // General Status
                        ( _bFunctionCode := 2, _uiReadAddress := 001, _uiReadQuantity := 11),    (* 001 - 011 *)
                       // AC Status
                        ( _bFunctionCode := 2, _uiReadAddress := 012, _uiReadQuantity := 6),    (* 012 - 017 *)
                       // Free cooler / Inverter Compressor
                        ( _bFunctionCode := 2, _uiReadAddress := 018, _uiReadQuantity := 2)        (* 018 - 019 *)
                    ];

    aQL_rAlarms:    ARRAY[1..1] OF FbQuery() :=
                    [
                      (* Alarms *)
                        ( _bFunctionCode := 2, _uiReadAddress := 030, _uiReadQuantity := 54)    (* 030 - 083 *)
                    ];

und so weiter...
Mit dieser Definition erhalte ich im Moment den Fehler vom GVL: "C0395: Die Anzahl von 'FB_Init'-Initialisierern (0) stimmt nicht mit der Anzahl der Arrayelemente (3) überein". und komme da nicht weiter.

Ziel wäre für mich, dass ich quasi eine einheitliche FbQuery habe, welche ich mit unterschiedlich grossen Modbusanfragen füttern kann und in einer separaten Funktionsblock die Werte dann aufbereite.

Gruss
BBM
 
Guten Tag miteinander!

Ich versuche derzeit meine Steuerung zu optimieren und würde gerne wissen ob es eine andere oder einfachere Möglichkeit gibt, die FbDigitalTwinMbSlaveDevice zu implementieren.
Ich habe in der ersten Version 172 Modbusanfragen die ~45sek brauchen bis alle Werte abgefragt werden.
Code:
FUNCTION_BLOCK FbQueryRead EXTENDS WagoAppPlcModbus.FbDigitalTwinMbSlaveDevice
VAR
    r_FbQuery:        ARRAY[1..172] OF FbQuery(THIS^) :=
                    [
                      (* Digital Variables (Coils) *)
                       (* Unit Status *)
                        ( _bFunctionCode := 2, _uiReadAddress := 001, _uiReadQuantity := 1),
                        ( _bFunctionCode := 2, _uiReadAddress := 002, _uiReadQuantity := 1),

                        etc...
Meine Idee wäre, die 172 Adressen mit "ReadQuantity" zusammenzufassen und zu gruppieren in einer separaten GVL, leider habe ich ein Verständnisproblem mit (THIS^) und allgemein finde ich keinen Lösungsweg für mein Ziel.
Der Grund ist, dass ich für die Visualisierung z.b. Temperaturanzeigen öfter abfrage als die Alarme von 2 Klimageräten.
Code:
    aQL_rStatus:    ARRAY[1..3] OF FbQuery() :=
                    [
                      (* Unit Status *)
                       // General Status
                        ( _bFunctionCode := 2, _uiReadAddress := 001, _uiReadQuantity := 11),    (* 001 - 011 *)
                       // AC Status
                        ( _bFunctionCode := 2, _uiReadAddress := 012, _uiReadQuantity := 6),    (* 012 - 017 *)
                       // Free cooler / Inverter Compressor
                        ( _bFunctionCode := 2, _uiReadAddress := 018, _uiReadQuantity := 2)        (* 018 - 019 *)
                    ];

    aQL_rAlarms:    ARRAY[1..1] OF FbQuery() :=
                    [
                      (* Alarms *)
                        ( _bFunctionCode := 2, _uiReadAddress := 030, _uiReadQuantity := 54)    (* 030 - 083 *)
                    ];

und so weiter...
Mit dieser Definition erhalte ich im Moment den Fehler vom GVL: "C0395: Die Anzahl von 'FB_Init'-Initialisierern (0) stimmt nicht mit der Anzahl der Arrayelemente (3) überein". und komme da nicht weiter.
Naja, dein FbQueryRead erweitert den FB WagoAppPlcModbus.FbDigitalTwinMbSlaveDevice und hat damit auch alle Methoden von diesem. Der FB hat die Methode FB_init implementiert die bestimmte Variablen bei der Instantiierung benötigt und die hast Du nicht angegeben, darum meckert der Compiler.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich konnte einen relativ sinnvollen Lösungsansatz anwenden, im Grunde genommen die Aufträge mit der "typMbQuery" Struktur abspeichern und in der Query Funktion vor der Abfrage zur "FbQuery(THIS^)" umwandeln.
Im Anhang ein Codesys V3 Export für diejenigen die ein bisschen mehr Hilfe benötigen, welche aber an sich nicht lauffähig ist.

Code:
FUNCTION_BLOCK FbQ EXTENDS WagoAppPlcModbus.FbDigitalTwinMbSlaveDevice
VAR_IN_OUT
    xTrig:                BOOL;                        // Auftragstrigger
END_VAR
VAR_INPUT
    bUnitAddr:            BYTE;                        // Geräteadresse
    tQL:                typMbQuery;                    // Auftragsliste
    xRead:                BOOL;                        // Lesemodus
    xWrite:                BOOL;                        // Schreibmodus
END_VAR
VAR_OUTPUT
    toStatus:            WagoSysErrorBase.FbResult;    // Rückmeldestatus
    xError:                BOOL;                        // Fehler
    udiErrorCounter:    UDINT;                        // Fehlerzähler
    udiResponseCounter:    UDINT;                        // Rückmeldezähler

   // Rückmeldung
    atResponse:            typMbResponse;
END_VAR
VAR
    xAllJobsDone:        BOOL;                        // Aufträge erledigt
    uiActiveJobs:        UINT;                        // Aktive Aufträge
    diCurrJobIndex:        DINT;                        // Aktueller Auftragszähler
    diAttaJobIndex:        DINT;                        // Anzuhängender Auftragszähler

   // Interne Auftragsliste
    F_QL:                FbQuery(THIS^);
END_VAR

(* ============================================================== *)

(* Wenn keine Aufträge anstehen *)
IF xAllJobsDone THEN
    xTrig            := FALSE;    // Trigger freigeben
    xAllJobsDone    := FALSE;    // Auftragsstatus zurücksetzen
END_IF


(* Wenn Baustein aufgerufen wird *)
IF xTrig AND (uiActiveJobs = 0) THEN
    (* Aktuellen Auftrag in die Auftragsliste schreiben *)
        F_QL.bUnitId                :=    bUnitAddr;                // Geräteadresse
        F_QL.bFunctionCode            :=    tQL.bFunctionCode;        // Funktionscode

    (* Wenn gelesen werden soll *)
    IF xRead THEN
            F_QL.uiReadAddress        :=    tQL.uiReadAddress;        // Leseregister
            F_QL.uiReadQuantity        :=    tQL.uiReadQuantity;        // Lesemenge
    (* Wenn geschrieben werden soll *)
    ELSIF xWrite THEN
            F_QL.uiWriteAddress        :=    tQL.uiWriteAddress;        // Schreibregister
            F_QL.uiWriteQuantity    :=    tQL.uiWriteQuantity;    // Schreibmenge
            F_QL.awWriteData        :=    tQL.awWriteData;        // Schreibdaten
    END_IF

    (* Auftragsliste anhängen *)
        uiActiveJobs            :=    uiActiveJobs + protAttachMbQuery(F_QL);

END_IF
 

Anhänge

I was able to use a relatively sensitive solution, basically saving the orders with the "typMbQuery" structure and converting them to "FbQuery(THIS^)" in the query function before the query.
Attached is a Codesys V3 export for those who need a little more help, but which is not actually executable.

Code:
FUNCTION_BLOCK FbQ EXTENDS WagoAppPlcModbus.FbDigitalTwinMbSlaveDevice
VAR_IN_OUT
    xTrig: BOOL; // order trigger
END_VAR
VAR_INPUT
    bUnitAddr: BYTE; // device address
    tQL: typeMbQuery; // order list
    xRead: BOOL; // read mode
    xWrite: BOOL; // write mode
END_VAR
VAR_OUTPUT
    toStatus: WagoSysErrorBase.FbResult; // feedback status
    xError: BOOL; // Mistake
    udiErrorCounter: UDINT; // error counter
    udiResponseCounter: UDINT; // feedback counter

   // Return message
    atResponse: typeMbResponse;
END_VAR
VAR
    xAllJobsDone: BOOL; // Jobs done
    uiActiveJobs: UINT; // Active orders
    diCurrJobIndex: DINT; // Current job counter
    diAttaJobIndex: DINT; // Job counter to append

   // Internal order list
    F_QL: FbQuery(THIS^);
END_VAR

(* ================================================ ============== *)

(* If there are no orders *)
IF xAllJobsDone THEN
    xTrig := FALSE; // release triggers
    xAllJobsDone := FALSE; // Reset order status
END_IF


(* if block is called *)
IF xTrig AND (uiActiveJobs = 0) THEN
    (* Write current order to the order list *)
        F_QL.bUnitId := bUnitAddr; // device address
        F_QL.bFunctionCode := tQL.bFunctionCode; // function code

    (* if to read *)
    IF xRead THEN
            F_QL.uiReadAddress := tQL.uiReadAddress; // read register
            F_QL.uiReadQuantity := tQL.uiReadQuantity; // read amount
    (* if you want to write *)
    ELSIF xWrite THEN
            F_QL.uiWriteAddress := tQL.uiWriteAddress; // write registers
            F_QL.uiWriteQuantity := tQL.uiWriteQuantity; // amount of writing
            F_QL.awWriteData := tQL.awWriteData; // write data
    END_IF

    (* attach order list *)
        uiActiveJobs := uiActiveJobs + protAttachMbQuery(F_QL);

END_IF
Hi mate, I need some help using that library, I am using wago plc and I need to use this library because I am reading some energy meters which have many modbus registers. one requirement is that they want to change the parameters like unitid, baud rate and the ones in the query, I haven't been able to make working this library for RTU, I need to ready many array of queries But i really haven't been able, is there any chance you can help me how to do it?
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hello,

the digital twin does not necessarily have to be used if several slaves are to be addressed.
See also the example from the other post:
https://www.sps-forum.de/threads/serial-interface-750-562-modbus.112182/post-885015


I have attached an example of the digital twin.
What I would like to do is the same as what is done in the network but using the library. I need to have all those connected in RTU or tcp, the idea of using the library is that I can modify the parameters and configurations of the slaves dynamically and not with hard code, such as the ip, unitid, port, baud rate, and others ... no I have been able to make a program because there is almost no information about the library, obviously I have tried to do the examples but they do not work for me, it is something more complex than that. I show more or less a photo with what I have and I would like to pass it all to the library. At least each slave has the wants that I show in the other photo. I would like to do it in a simple and orderly way where I could change the ecockpit network as well as help, for example, place the data type, map it etc...1690935522267.png

1690935311313.png
 
Zurück
Oben