e! Cockpit RTU Master

Thorkel

Level-1
Beiträge
3
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Moin zusammen,

ich habe ein Problem mit ModBus Master.
Ich habe von Wago eine Anleitung für einen MoBus Master bekommen, der läuft sehr stabil und hat eine Error Meldung bei Ausfall des Gerätes.
Aber das schreiben auf einzelne Register ist sehr langsam.
Hat jemand Erfahrungen wie man eine Verbindung schnell und sicher hinbekommt?

Viele Grüße


Diese Programmieung funktioniert, aber ist sehr langsam.
Code:
-------------------------Master----------------------------
FUNCTION_BLOCK fbMaster
VAR_INPUT
    I_Port            : WagoTypesCom.I_WagoSysComBase;
    udiBaudrate        : UDINT := 19200;
    eParity            : eTTYParity := eTTYParity.Even;
    tScanRate        : TIME := T#200MS;
END_VAR
VAR_OUTPUT
    sError            : STRING := 'startup';
END_VAR
VAR_IN_OUT
    I_Master        : typMasterQuery;
END_VAR
VAR
    oMaster            : WagoAppPlcModbus.FbMbMasterSerial :=(
        xConnect    := TRUE,
        usiDataBits    := 8,
        eStopBits    := eTTYStopBits.One,
        eHandshake    := eTTYHandshake.None,
        ePhysical    := eTTYPhysicalLayer.RS485_HalfDuplex,
        tTimeOut    := T#1S,
        eFrameType    := eMbFrameType.RTU );
    wState            : WORD;
    xSendQuery        : BOOL;
    oDelay            : TON;
END_VAR



oMaster(
    I_Port            := I_Port,
    udiBaudrate        := udiBaudrate,
    eParity            := eParity,
    utQuery            := I_Master.oQuery,
    xTrigger        := xSendQuery,
    utResponse        := I_Master.oResponse );

CASE wState OF
0:
    IF oMaster.xIsConnected THEN
        I_Master.eState := eMasterState.FREE;
        wState := 10;
    END_IF
    oMaster.oStatus.ShowResult(
        sDescription => sError );
10:
    IF I_Master.eState = eMasterState.START THEN
        xSendQuery := TRUE;
        I_Master.eState := eMasterState.BUSY;
        wState := 20;
    END_IF
20:
    IF NOT xSendQuery THEN
        oMaster.oStatus.ShowResult(
            sDescription => sError );
        I_Master.sError := sError;
        I_Master.xError := oMaster.xError;
        I_Master.eState := eMasterState.DONE;
        wState := 30;
    END_IF
30:
    oDelay(
        IN := TRUE,
        PT := tScanRate );
    IF oDelay.Q THEN
        oDelay( IN := FALSE );
        wState := 10;
    END_IF
END_CASE




TYPE eMasterState :
(
    INIT        := 0,
    FREE        := 1,
    START        := 2,
    BUSY        := 3,
    DONE        := 4
);
END_TYPE


TYPE typMasterQuery :
STRUCT
    oQuery        : typMbQuery;
    oResponse    : typMbResponse;
    eState        : eMasterState;
    sError        : STRING;
    xError        : BOOL;
END_STRUCT
END_TYPE



-----------------Slave--------------------------

FUNCTION_BLOCK FbEAP_Neu_2
VAR_INPUT
    bSlaveAddress            : BYTE;
    wOutput: WORD;
    xOutPut0        :BOOL;
    xOutPut1        :BOOL;
END_VAR
VAR_OUTPUT   
    xError                    : BOOL;
    sError                    : STRING;
    wHand , wHand2: WORD;
END_VAR
VAR_IN_OUT
    I_Master                : typMasterQuery;
   
    Trigger1: BOOL;
    Trigger2: BOOL;
END_VAR
VAR
   
    wState                    : WORD;
    wIndex                    : WORD;
    aJobs                    : ARRAY [1..MAX_JOB_Modbus] OF typMbQuery :=[
        (bFunctionCode := 4, uiReadAddress := 1, uiReadQuantity := 1), //1
       
       
        //(bFunctionCode := 16, uiWriteAddress := 0, uiWriteQuantity := 1), //16
        (bFunctionCode := 5, uiWriteAddress := 0, uiWriteQuantity := 1), //16
        (bFunctionCode := 5, uiWriteAddress := 1, uiWriteQuantity := 1), //16
        (bFunctionCode := 4, uiReadAddress := 1, uiReadQuantity := 1) //1
                                                                             ];
END_VAR
VAR CONSTANT
    MAX_JOB_Modbus            : WORD := 4;
END_VAR




CASE wState OF
0:
    IF I_Master.eState = eMasterState.FREE THEN
        wIndex := ( wIndex MOD MAX_JOB_Modbus) + 1;
       
                //aJobs[wIndex].awWriteData[0] := TO_WORD(xOutPut0);
        IF wIndex = 2 THEN
            IF Trigger1 THEN
                Trigger1 := FALSE;
                aJobs[wIndex].awWriteData[0] := TO_WORD(xOutPut0);
            ELSE
                wIndex := ( wIndex MOD MAX_JOB_Modbus) + 1;
            END_IF
        END_IF
        IF wIndex = 3 THEN
            IF Trigger2 THEN
                Trigger2 := FALSE;
                aJobs[wIndex].awWriteData[0] := TO_WORD(xOutPut1);
            ELSE
                wIndex := ( wIndex MOD MAX_JOB_Modbus) + 1;
            END_IF   
           
        END_IF
   
        I_Master.oQuery := aJobs[wIndex];
        I_Master.oQuery.bUnitId := bSlaveAddress;
        I_Master.eState := eMasterState.START;
        wState := 10;
    END_IF
   
10:
       
    IF I_Master.eState = eMasterState.DONE THEN
        sError := I_Master.sError;
        xError := I_Master.xError;
       
        IF NOT xError THEN
            CASE wIndex OF
            1:
                wHand := I_Master.oResponse.awData[0] ;
           
           
            4:
                wHand2 := I_Master.oResponse.awData[0] ;
               
           
            END_CASE
        END_IF
        I_Master.eState := eMasterState.FREE;
        wState := 0;
    END_IF
END_CASE
 
Zuletzt bearbeitet:
Definiere doch mal schnell!
Außerdem welche RS485. Intern wie bei einem 8212 oder Zusatzkarte(welche).

PS. Der Code wird lesbarer in einem Code Tag
 
Zuviel Werbung?
-> Hier kostenlos registrieren
In dem Fall ist es ein EAP DO Modul mit 10 digitalen Ausgängen.

Wenn ich alle mehrere DO’s schalten will, wo jeder DO eine Modbus Funktion bekommt, schaltet jeder DO, gefühlt im Sekundentakt ein obwohl alle gleichzeitig kommen sollten.

Ich muss noch ein Raumbediengerät programmieren, das hat diverse Register zu schreiben.

Wenn ich dran denke, wenn 4 Register schon 4 s benötigen, was machen denn erst 20 Register zu schreiben. Das macht mir den Bus tot für andere Sensoren oder Aktoren.

Nur lesen klappt super schnell, wenn in einem Block lese, aber schreiben.



Es ist die OnBoard Schnittstelle COM1
 
So wie ich das sehe lassen sich die Module als fortlaufende Register ansprechen. Somit hättest du nur einen Aufruf.
Wenn der Kabelausbau dies zulässt wäre auch eine Erhöhung der Baudrate möglich.
Bei deinem Raumbediengerät und den anderen Aktoren / Sensoren müsste man schauen welche Register zyklisch aufgefrischt werden müssen und welche nicht.
 
Hallo,

wie schon geschrieben solltest Du Lese- und Schreibvorgänge zusammenfassen und jeweils mehrere Register gleichzeitig übertragen. Dann hast Du auch Datenkonsistenz. Immer vorausgesetzt, daß Deine Anwendung zyklische Datenübertragung verträgt. Bei Ein- und Ausgängen sollte es aber der Fall sein.

Bei Deinem Code oben hast Du zunächst einmal zwischen zwei Jobs der Jobliste (aJobs) eine Wartezeit von 200 ms (tScanRate).

Dann kommt noch die Verarbeitungszeit der State-Machines dazu. Ich bin der Meinung, daß pro Zyklus nur ein Case Zweig verarbeitet wird: z.B. wState ist gleich 10, es wird der entsprechende Case Zweig verarbeitet, am Ende des Zweig wird wState auf 20 gesetzt, dann wird nicht unmittelbar mit dem Case Zweig weitergemacht sondern an das Ende der Case Anweisung gesprungen, so daß erst im nächsten Zyklus mit dem Case Zweig für wState = 30 weitergemacht wird. So kommen dann noch diverse Zykluszeiten zwischen zwei Jobs dazu.

Gruß
 
Zurück
Oben