同步应用实例
在此示例应用程序中,应用程序控制冗余系统中的数据同步。该示例显示了如何通过库 POU 触发同步阶段以及如何评估冗余系统的状态数据。可视化显示这些状态并提供冗余命令。可视化是用户的界面。
冗余系统包括两个 REDU01 和 REDU01 CODESYS Control Win 控制器。可视化运行在 CODESYS TargetVisu.
配置
设备树中的对象 | 设置 |
|---|---|
顶层 |
![]() |
任务配置 | ![]() |
冗余配置 | |
可编程逻辑控制器 2 |
|
一般的 | ![]() |
冗余链路 | ![]() |
可视化 | ![]() |
在 注册区域 | ![]() |
全球数据
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_VAR用于控制同步的 POU
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();可视化







