Skip to main content

Anwendungsbeispiel für Synchronisieren

In diesem Anwendungsbeispiel steuert die Applikation das Synchronisieren der Daten im Redundanzsystem. Das Beispiel zeigt, wie mit Hilfe von Bibliotheksbausteinen die Synchronisierungsphasen angestoßen werden und die Zustandsdaten des Redundanzsystems ausgewertet werden. Eine Visualisierung stellt diese Zustände dar und stellt Redundanzbefehle zur Verfügung. Die Visualisierung ist Schnittstelle für einen Benutzer.

Das Redundanzsystem besteht aus den zwei CODESYS Control Win-Steuerungen REDU01 und REDU01. Die Visualisierung läuft auf einer CODESYS TargetVisu.

Konfiguration

Objekt im Gerätebaum

Einstellungen

Toplevel-Gerät Device

REDU01

rdncy_img_example_device_config.png

Taskkonfiguration

rdncy_img_example_task_config.png

Redundanzkonfiguration

SPS 2

REDU02

Allgemein

rdncy_img_example_general_config.png

Redundanzverbindung

rdncy_img_example_link_config.png

Visualisierung

rdncy_img_example_visu_link_config.png

In Registrierte Bereiche

rdncy_img_settings_registered_areas.png

Globale Daten

GVL

(* Variables synchronized at Redundancy synchronization. Synchronization happens
- on bootup of the second PLC
- on call to RedundancySynchronizeData
- in every task cycle if setting is active in cfg file of both PLCs:
[CmpRedundancy]
DataSyncAlways=1
*)

VAR_GLOBAL
    globalvar1: INT;
    arr1 : ARRAY [0..10000] OF DWORD;
    arr2 : ARRAY [0..10000] OF DWORD;
    arr3 : ARRAY [0..10000] OF DWORD;
    arr4 : ARRAY [0..10000] OF DWORD;
    bSyncDataResult: BOOL;
END_VAR

GVL_1

VAR_GLOBAL
    sReduState: RedundancyState;
    conni: REDUNDANCY_CONNECTION_INFO;
    sSyncInfo: SYNC_INFO;
    sPlcIdent: PLC_IDENT;
    bConnectionState: BOOL;

    tLast: TIME;
    nTimeWarp: INT;
    tDiff: TIME;
    nTimeRun: INT;
    tNow: TIME;
    sState: STRING;
    acopy: INT;
    MB2 AT %MX0.2: BOOL;
    tDiffMax: TIME;
    tNow2: TIME;
    tDiff2: TIME;
    nTimeWarp2: INT;
    tDiffMax2: TIME;
    tLast2: TIME;
    tNowDownloadDone: TIME;
    tNowCodeInitDone: TIME;
    nCycle: INT;
    atNow: ARRAY [0..9] OF TIME;
    nCycle2: INT;
    atNow2: ARRAY [0..9] OF TIME;
    bAreaRegisterDone: BOOL;
    pIB64: POINTER TO BYTE;
    bUpdateData: BOOL;
    bSwitchToStandby: BOOL;
    bSwitchToActive: BOOL;
    bSwitchToSimulation: BOOL;
    bSynchronize: BOOL;
    bSwitchToStandaloneResult: BOOL;
END_VAR

GVL_Synchro

(* Global variables, registered to be synchronized in every task cycle. *)
VAR_GLOBAL
    iSyncFirst: INT;
    iSyncCount: INT;
    iSyncLast: INT;
END_VAR

Programmierbausteine zum Steuern der Synchronisierung

PROGRAM PLC_PRG
VAR
    a: INT;
    bSyncCalled: BOOL;
    Timestamp1: systime.SYSTIME;
    firstcycle: BOOL := TRUE;
    Timestamp2: systime.SYSTIME;
    b: INT;
    sText: STRING;
    bCopy: BOOL;
    Blink: TON;
    bBlink: BOOL;
    bAutoSync: BOOL := TRUE; // Flag to enable autosync mechanism
    xResSync: BOOL;
END_VARIF a = 0 THEN
    Blink(PT := T#1S, IN := TRUE);
END_IF
a := a + 6;
globalvar1 := globalvar1 + 1;

(* Call functions of redundancy library *)
GetRedundancyState(ADR(sReduState));
bConnectionState := GetConnectionState();
sPlcIdent := GetPlcIdent();

(* Call functions of redundancy connection library *)
GetConnectionInfo(ADR(conni));

GetSyncInformation(ADR(sSyncInfo));

// Flag to enable autosync mechanism
IF bAutoSync THEN
    IF sReduState.eRedundancyState = RDCY.STATE.RS_CYCLE_STANDALONE AND bConnectionState AND xResSync = FALSE AND sPlcIdent = RDCY.PLC_IDENT.PLC_ID_2 THEN
            // Call of Synchronize from redundant application. Note, actual synchronisation is executed from background loop with some delay
            xResSync := RDCY.Synchronize();
    END_IF
END_IF

// Recover from error state
(*IF sReduState.eRedundancyState = RDCY.STATE.RS_SYNCHRO_ERROR THEN
    bSwitchToStandaloneResult := SwitchToStandalone();
END_IF

IF sReduState.eRedundancyState = RDCY.STATE.RS_CYCLE_ACTIVE THEN
    bSyncDataResult := RedundancySynchronizeData();
END_IF
*)

IF bUpdateData THEN
    bUpdateData := FALSE;
    RedundancySynchronizeData();
END_IF

IF bSwitchToStandby THEN
    bSwitchToStandby := FALSE;
    SwitchToStandby();
END_IF

IF bSwitchToActive THEN
    bSwitchToActive := FALSE;
    SwitchToActive();
END_IF

IF bSwitchToSimulation THEN
    bSwitchToSimulation := FALSE;
    SwitchToSimulation();
END_IF

IF bSynchronize THEN
    bSynchronize := FALSE;
    Synchronize();
END_IF

Blink();
IF Blink.Q THEN
    Blink.IN := FALSE;
    Blink();
    Blink.IN := TRUE;
    bBlink := NOT bBlink;
END_IF
%IB64;

IF bCopy THEN
    bCopy := FALSE;
    acopy := a;
END_IF

arr2 := arr1;

IF sReduState.eRedundancyState = RDCY.STATE.RS_CYCLE_ACTIVE THEN
    sState := 'Active';
    b := b + 1;
    pIB64 := ADR(%IB64);
    pIB64^ := pIB64^ + 1;
ELSIF sReduState.eRedundancyState = RDCY.STATE.RS_CYCLE_STANDBY THEN
    sState := 'Passive';
ELSIF sReduState.eRedundancyState = RDCY.STATE.RS_CYCLE_STANDALONE THEN
    sState := 'Standalone';
ELSIF sReduState.eRedundancyState = RDCY.STATE.RS_SIMULATION THEN
    sState := 'Simulation';
ELSIF sReduState.eRedundancyState = RDCY.STATE.RS_SYNCHRO THEN
    sState := 'Synchro';
ELSIF sReduState.eRedundancyState = RDCY.STATE.RS_SYNCHRO_ERROR THEN
    sState := 'SYNCHRO_ERROR';
ELSIF sReduState.eRedundancyState = RDCY.STATE.RS_NO_LICENSE THEN
    sState := 'LICENCE EXPIRED';
ELSIF sReduState.eRedundancyState = RDCY.STATE.RS_START THEN
    sState := 'START';
ELSE
    sState := 'Other';
END_IF

nCycle := nCycle + 1;
PROGRAM POU
VAR
END_VAR

tNow2 := TIME();
tDiff2 := tNow - tLast;
IF tDiff2 > T#1D THEN
     nTimeWarp2 := nTimeWarp2 + 1;
     LogAdd(STD_LOGGER, 'IEC', 0, 0, 0, 'Time Warp');
END_IF
IF tDiff2 > tDiffMax2 THEN
     tDiffMax2 := tDiff2;
END_IF
tLast2 := TIME();

IF nCycle2 < 10 THEN
    atNow2[nCycle2] := tNow2;
END_IF

nCycle2 := nCycle2 + 1;
FUNCTION cdCodeInit : DWORD
VAR_IN_OUT
    EventPrm: CmpApp.EVTPARAM_CmpApp;
END_VAR
VAR
END_VAR
tNowCodeInitDone := TIME();
FUNCTION cbDownloadDone : DWORD
VAR_IN_OUT
    EventPrm: CmpApp.EVTPARAM_CmpApp;
END_VAR
VAR
END_VAR
(* Register GVL_Synchro to be synchronized in every task cycle *)
bAreaRegisterDone := AreaRegister(ADR(iSyncFirst), ADR(iSyncLast) - ADR(iSyncFirst) + sizeof(iSyncLast), AREA_TYPE.AREA_SYNCHRO);
tNowDownloadDone := TIME();

Visualisierung

rdncy_img_example_visu.png