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 |
![]() |
Taskkonfiguration | ![]() |
Redundanzkonfiguration | |
SPS 2 |
|
Allgemein | ![]() |
Redundanzverbindung | ![]() |
Visualisierung | ![]() |
In Registrierte Bereiche | ![]() |
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_VARGVL_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_VARGVL_Synchro
(* Global variables, registered to be synchronized in every task cycle. *)
VAR_GLOBAL
iSyncFirst: INT;
iSyncCount: INT;
iSyncLast: INT;
END_VARProgrammierbausteine 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







