В программах ПЛК постоянно приходится работать с дискретными сигналами:
• кнопка нажата
• двигатель работает
• датчик сработал
• авария появилась
• команда исчезла
Но очень важно различать:
состояние сигнала
и
момент изменения сигнала.
Именно для второго случая в CODESYS используются функциональные блоки
R_TRIG и F_TRIG.━━━━━━━━━━━━━━━━━━
🔹 Состояние и событие — не одно и то же
Допустим:
xButton = TRUE
Если написать:
IF xButton THEN
iCounter := iCounter + 1;
END_IF
команда будет выполняться каждый цикл ПЛК, пока кнопка остаётся нажатой.
Например, если цикл программы составляет 10 мс, а кнопку держат одну секунду, код может выполниться около 100 раз.
Но иногда нам нужно выполнить действие только один раз:
именно в момент нажатия.
Для этого необходимо определить переход:
FALSE → TRUE
Это называется передним фронтом.
━━━━━━━━━━━━━━━━━━
⬆️ R_TRIG — передний фронт
R_TRIG отслеживает переход:FALSE → TRUE
Объявим функциональный блок:
VAR
xButton : BOOL;
fbRise : R_TRIG;
END_VAR
Вызываем его каждый цикл:
fbRise(CLK := xButton);
Когда
xButton изменится:FALSE → TRUE
выход:
fbRise.Q
станет
TRUE только на один цикл программы.После этого, даже если
xButton продолжает оставаться TRUE:fbRise.Q = FALSE
до следующего нового фронта.
━━━━━━━━━━━━━━━━━━
🧠 Пример
Пусть сигнал выглядит так:
цикл 1 → FALSE
цикл 2 → FALSE
цикл 3 → TRUE
цикл 4 → TRUE
цикл 5 → TRUE
Выход
R_TRIG:цикл 1 → FALSE
цикл 2 → FALSE
цикл 3 → TRUE
цикл 4 → FALSE
цикл 5 → FALSE
То есть импульс появляется только в момент изменения сигнала.
━━━━━━━━━━━━━━━━━━
✅ Практический пример с кнопкой
Нужно увеличивать счётчик один раз при каждом нажатии:
VAR
xButton : BOOL;
fbButton : R_TRIG;
iCounter : INT;
END_VAR
fbButton(CLK := xButton);
IF fbButton.Q THEN
iCounter := iCounter + 1;
END_IF
Теперь:
🔘 нажали →
+1⏳ держим → ничего
🔘 отпустили → ничего
🔘 нажали снова → ещё
+1━━━━━━━━━━━━━━━━━━
⬇️ А что делает F_TRIG?
F_TRIG работает наоборот.Он определяет переход:
TRUE → FALSE
То есть задний фронт сигнала.
Объявление:
VAR
xSignal : BOOL;
fbFall : F_TRIG;
END_VAR
Вызов:
fbFall(CLK := xSignal);
Когда сигнал изменится:
TRUE → FALSE
получим:
fbFall.Q = TRUE
на один цикл ПЛК.
━━━━━━━━━━━━━━━━━━
🔄 R_TRIG и F_TRIG рядом
Для одного сигнала можно использовать оба блока:
fbRise(CLK := xSignal);
fbFall(CLK := xSignal);
Получаем:
FALSE → TRUE
↑
R_TRIG.Q
TRUE → FALSE
↓
F_TRIG.Q
Таким образом можно отдельно обработать появление и исчезновение одного и того же сигнала.
━━━━━━━━━━━━━━━━━━
🏭 Где применяется R_TRIG?
Передний фронт очень часто нужен для:
• обработки нажатия кнопки
• запуска последовательности
• подсчёта событий
• регистрации появления аварии
• формирования однократной команды
• переключения режима
• увеличения или уменьшения значения
• запуска операции с HMI
Например:
IF fbStart.Q THEN
eState := STATE_STARTING;
END_IF
Переход выполняется один раз — именно при появлении команды.
━━━━━━━━━━━━━━━━━━
🏭 Где применяется F_TRIG?
Задний фронт полезен, когда действие должно происходить при исчезновении сигнала.
Например:
• оператор отпустил кнопку
• механизм остановился
• датчик перестал быть активным
• команда была снята
• аварийное условие исчезло
Пример:
fbFall(CLK := xMotorRun);
IF fbFall.Q THEN
iStopCounter := iStopCounter + 1;
END_IF
Счётчик увеличится именно в момент перехода:
TRUE → FALSE
━━━━━━━━━━━━━━━━━━
⚠️ Важный момент