同步应用实例
在此示例应用程序中,应用程序控制冗余系统中的数据同步。该示例显示了如何通过库 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_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
用于控制同步的 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();
可视化
