// Область переменных
PROGRAM PLC_PRG
VAR
iStep: INT := 0; // Шаг автомата
// По переднему фронту инициируется синхронизация времени
xStartSync: BYTE;
wYear: WORD;
wMonth: WORD;
wDay: WORD;
wHour: WORD;
wMinute: WORD;
wSecond: WORD;
// Опрос Modbus slave
fbModbusChannel: IoDrvModbusTCP.ModbusChannel;
xTrigger: BOOL;
xExecute: BOOL;
fbTimeSyncTimer: TON;
iChannelIndex: INT;
fbStartDelay: TON;
xFirstCycle: BOOL := TRUE;
END_VAR
VAR CONSTANT
i_Channel_0: INT := 0;
i_Channel_1: INT := 1;
// Период синхронизации времени
tTimeSyncPeriod: TIME := T#1H;
END_VAR
//-----------------------------------------------------------------------------
// Область кода
fbTimeSyncTimer(
IN := (iStep = 0),
PT := tTimeSyncPeriod
);
// НОВЫЙ ТАЙМЕР: Задержка 2 секунды после включения ПЛК для инициализации сети
fbStartDelay(
IN := TRUE,
PT := T#2S
);
// 2. Вызов функционального блока Modbus ВСЕГДА на каждом цикле
fbModbusChannel(
slave := Modbus_TCP_Slave,
xExecute := xExecute,
iChannelIndex := iChannelIndex
);
// 3. Пошаговый автомат синхронизации
CASE iStep OF
0: // Ожидание срабатывания таймера ИЛИ первого старта
xExecute := FALSE;
IF fbTimeSyncTimer.Q OR (xFirstCycle AND fbStartDelay.Q) THEN
IF xFirstCycle THEN
xFirstCycle := FALSE;
END_IF
// Получение текущего времени из контроллера
wYear := TargetVars.stRtc.uiGetYear MOD 100;
wMonth := TargetVars.stRtc.usiGetMonth;
wDay := TargetVars.stRtc.usiGetDay;
wHour := TargetVars.stRtc.usiGetHour;
wMinute := TargetVars.stRtc.usiGetMinute;
wSecond := TargetVars.stRtc.usiGetSecond;
iStep := 10;
END_IF
10: // ШАГ 1: Запись значений времени (Channel 1)
iChannelIndex := i_Channel_1;
xExecute := TRUE; // Даем команду на отправку
// Ждем завершения операции
IF fbModbusChannel.xDone THEN
xExecute := FALSE; // Сбрасываем execute перед следующим шагом
xStartSync := 1; // Выставляем флаг синхронизации для панели
iStep := 20;
ELSIF fbModbusChannel.xError THEN
xExecute := FALSE;
iStep := 999; // Обработка ошибки
END_IF
20: // Пауза в 1 цикл для сброса фронта xExecute у ФБ
xExecute := FALSE;
iStep := 30;
30: // ШАГ 2: Отправка команды "Применить время" (Channel 0)
iChannelIndex := i_Channel_0;
xExecute := TRUE;
IF fbModbusChannel.xDone THEN
xExecute := FALSE;
xStartSync := 0; // Сбрасываем флаг синхронизации
iStep := 0; // Возврат в начало, таймер fbTimeSyncTimer начнет отсчет заново
ELSIF fbModbusChannel.xError THEN
xExecute := FALSE;
iStep := 999;
END_IF
999: // Ошибка обмена (например, панель еще не загрузилась)
xExecute := FALSE;
xStartSync := 0;
// Если при первом старте произошла ошибка связи, мы НЕ сбрасываем xFirstCycle.
// Автомат попробует снова синхронизироваться на следующем цикле (через шаг 0),
// не дожидаясь tTimeSyncPeriod, пока связь наконец-то не установится успешно.
xFirstCycle := TRUE;
iStep := 0; // Возврат в начало
END_CASE