🧠 РАЗБОР КОДА
Исходный код:
Начальное значение:
Сигнал:
в течение 5 циклов ПЛК подряд.
❓ Что будет в iCounter после пятого цикла?
А)
Б)
В)
Г) Зависит от времени цикла
Сначала выберите вариант, потом откройте ответ 👇
🔎 Открыть правильный ответ
✅ Правильный ответ — Б: iCounter = 5.
Почему?
Условие xButton = TRUE выполняется во всех пяти циклах.
Поэтому команда:
iCounter := iCounter + 1;
тоже выполняется пять раз.
Получаем:
0 → 1 → 2 → 3 → 4 → 5
Время цикла здесь не влияет на результат, потому что в условии уже сказано: xButton оставался TRUE ровно 5 циклов.
💡 Главная мысль
Если действие нужно выполнить только один раз при переходе:
нужно использовать определение переднего фронта, например
💬 Получилось ответить правильно до открытия спойлера?
#CODESYS #ПЛК #StructuredText #ПрограммированиеПЛК
Исходный код:
IF xButton THEN
iCounter := iCounter + 1;
END_IF
Начальное значение:
iCounter = 0Сигнал:
xButton = TRUEв течение 5 циклов ПЛК подряд.
❓ Что будет в iCounter после пятого цикла?
А)
1Б)
5В)
0Г) Зависит от времени цикла
Сначала выберите вариант, потом откройте ответ 👇
🔎 Открыть правильный ответ
Почему?
Условие xButton = TRUE выполняется во всех пяти циклах.
Поэтому команда:
iCounter := iCounter + 1;
тоже выполняется пять раз.
Получаем:
0 → 1 → 2 → 3 → 4 → 5
Время цикла здесь не влияет на результат, потому что в условии уже сказано: xButton оставался TRUE ровно 5 циклов.
💡 Главная мысль
IF проверяет состояние сигнала в каждом цикле.Если действие нужно выполнить только один раз при переходе:
FALSE → TRUEнужно использовать определение переднего фронта, например
R_TRIG.💬 Получилось ответить правильно до открытия спойлера?
#CODESYS #ПЛК #StructuredText #ПрограммированиеПЛК
⏱ TON в CODESYS: как работает таймер задержки включения
Задержка включения двигателя, подтверждение аварии, фильтрация кратковременных сигналов, контроль превышения температуры — во всех этих задачах часто используется именно
Но иногда возникает ситуация:
«На входе уже был TRUE, а таймер почему-то не сработал».
Разберём, как
━━━━━━━━━━━━━━━━━━
🔹 Что делает TON?
Объявим экземпляр таймера:
Вызовем его:
Основные параметры:
В нашем примере:
Это означает, что
━━━━━━━━━━━━━━━━━━
🔄 Что происходит после IN = TRUE?
Пока:
таймер находится в сброшенном состоянии:
Как только:
начинается отсчёт времени.
Условно процесс выглядит так:
Пока:
выход:
Когда заданное время достигнуто:
получаем:
Если
━━━━━━━━━━━━━━━━━━
⚠️ Самая важная особенность TON
Теперь представим такую ситуацию:
До заданных 5 секунд не хватило всего 0.2 секунды.
Что произойдёт?
Как только:
обычный
Когда
Предыдущие 4.8 секунды таймер не запоминает.
━━━━━━━━━━━━━━━━━━
🧠 TON считает непрерывное время
Это ключевой момент.
«Сколько всего времени сигнал был TRUE?»
Он отвечает:
«Как долго сигнал непрерывно находится в TRUE?»
Например:
Суммарно сигнал был активен:
Но при:
выход
Потому что ни один непрерывный участок
━━━━━━━━━━━━━━━━━━
🏭 Практический пример: задержка аварии
Допустим, есть температура:
Нужно сформировать аварию только в том случае, если температура выше 90 °C непрерывно держится 5 секунд.
Сначала получаем условие превышения:
Затем запускаем таймер:
Что произойдёт?
Если температура кратковременно поднимется выше 90 °C, например на 300 мс:
таймер начнёт отсчёт.
Но как только температура снова опустится ниже 90 °C:
таймер сбросится.
Авария не появится.
Если же температура остаётся выше 90 °C непрерывно 5 секунд:
и сформируется аварийный сигнал.
Так
━━━━━━━━━━━━━━━━━━
⚠️ Частая ошибка: вызывать таймер только внутри IF
Иногда встречается такой код:
Проблема в том, что когда
Его входы и внутреннее состояние в этом цикле не обновляются обычным способом.
TON — один из самых используемых таймеров в программах ПЛК.Задержка включения двигателя, подтверждение аварии, фильтрация кратковременных сигналов, контроль превышения температуры — во всех этих задачах часто используется именно
TON.Но иногда возникает ситуация:
«На входе уже был TRUE, а таймер почему-то не сработал».
Разберём, как
TON работает на самом деле.━━━━━━━━━━━━━━━━━━
🔹 Что делает TON?
TON — это таймер задержки включения.Объявим экземпляр таймера:
VAR
fbTimer : TON;
xSignal : BOOL;
xAlarm : BOOL;
END_VAR
Вызовем его:
fbTimer(
IN := xSignal,
PT := T#5s
);
Основные параметры:
IN — вход запуска таймераPT — заданное время задержкиQ — выход таймераET — прошедшее времяВ нашем примере:
PT := T#5s
Это означает, что
IN должен непрерывно оставаться в состоянии TRUE в течение 5 секунд.━━━━━━━━━━━━━━━━━━
🔄 Что происходит после IN = TRUE?
Пока:
IN = FALSEтаймер находится в сброшенном состоянии:
Q = FALSE
ET = T#0s
Как только:
IN = TRUEначинается отсчёт времени.
Условно процесс выглядит так:
0 сек → ET = 0 сек
1 сек → ET = 1 сек
2 сек → ET = 2 сек
3 сек → ET = 3 сек
4 сек → ET = 4 сек
5 сек → ET = 5 сек
Пока:
ET < PT
выход:
Q = FALSE
Когда заданное время достигнуто:
ET ≥ PT
получаем:
Q = TRUE
Если
IN продолжает оставаться TRUE, выход Q тоже остаётся активным.━━━━━━━━━━━━━━━━━━
⚠️ Самая важная особенность TON
Теперь представим такую ситуацию:
xSignal = TRUE → 4.8 сек
xSignal = FALSE → 0.1 сек
xSignal = TRUE → снова
До заданных 5 секунд не хватило всего 0.2 секунды.
Что произойдёт?
Как только:
IN = FALSEобычный
TON сбрасывается:ET → T#0s
Q → FALSE
Когда
IN снова станет TRUE, отсчёт начнётся заново.Предыдущие 4.8 секунды таймер не запоминает.
━━━━━━━━━━━━━━━━━━
🧠 TON считает непрерывное время
Это ключевой момент.
TON не отвечает на вопрос:«Сколько всего времени сигнал был TRUE?»
Он отвечает:
«Как долго сигнал непрерывно находится в TRUE?»
Например:
TRUE → 3 сек
FALSE → 1 сек
TRUE → 3 сек
Суммарно сигнал был активен:
3 + 3 = 6 секунд
Но при:
PT := T#5s
выход
Q не станет TRUE.Потому что ни один непрерывный участок
TRUE не длился 5 секунд.━━━━━━━━━━━━━━━━━━
🏭 Практический пример: задержка аварии
Допустим, есть температура:
rTemperatureНужно сформировать аварию только в том случае, если температура выше 90 °C непрерывно держится 5 секунд.
Сначала получаем условие превышения:
xHighTemp := rTemperature > 90.0;
Затем запускаем таймер:
fbHighTemp(
IN := xHighTemp,
PT := T#5s
);
xAlarm := fbHighTemp.Q;
Что произойдёт?
Если температура кратковременно поднимется выше 90 °C, например на 300 мс:
xHighTemp = TRUE
таймер начнёт отсчёт.
Но как только температура снова опустится ниже 90 °C:
xHighTemp = FALSE
таймер сбросится.
Авария не появится.
Если же температура остаётся выше 90 °C непрерывно 5 секунд:
fbHighTemp.Q = TRUE
и сформируется аварийный сигнал.
Так
TON позволяет отфильтровать кратковременные выбросы.━━━━━━━━━━━━━━━━━━
⚠️ Частая ошибка: вызывать таймер только внутри IF
Иногда встречается такой код:
IF xSignal THEN
fbTimer(
IN := TRUE,
PT := T#5s
);
END_IF
Проблема в том, что когда
xSignal = FALSE, функциональный блок вообще не вызывается.Его входы и внутреннее состояние в этом цикле не обновляются обычным способом.
Гораздо понятнее и надёжнее вызывать экземпляр таймера каждый цикл:
А затем использовать его выход:
Так алгоритм легко читать:
━━━━━━━━━━━━━━━━━━
🔎 Для чего нужен ET?
Например:
может иметь значения:
Это удобно использовать для:
• диагностики программы
• отображения времени на HMI
• индикации процесса задержки
• анализа работы алгоритма
• отладки
Например, оператору можно показать:
«Авария будет подтверждена через 2.3 секунды».
Для основной логики обычно используют
━━━━━━━━━━━━━━━━━━
📌 Коротко: алгоритм TON
Если:
получаем:
Если:
начинается отсчёт.
Пока:
получаем:
Когда:
получаем:
Если после этого:
таймер снова сбрасывается.
━━━━━━━━━━━━━━━━━━
💡 Где TON используется на практике?
Очень часто:
• задержка формирования аварии
• фильтрация кратковременных сигналов
• задержка включения оборудования
• контроль устойчивого состояния датчика
• контроль длительного превышения параметра
• ожидание перед переходом на следующий шаг алгоритма
• антидребезг дискретных сигналов
• задержка разрешения операции
Главный вопрос при выборе
«Нужно ли мне убедиться, что условие непрерывно выполняется заданное время?»
Если да —
━━━━━━━━━━━━━━━━━━
🧠 Запомните
«подождать 5 секунд».
Это проверка:
«Оставался ли вход IN непрерывно в TRUE в течение заданного времени PT?»
Даже кратковременный переход
И именно поэтому таймер иногда кажется «неработающим», хотя на самом деле работает совершенно правильно.
━━━━━━━━━━━━━━━━━━
❓ Проверим себя
Пусть задано:
Сигнал ведёт себя так:
Станет ли
💬 Напишите свой ответ в комментариях 👇
#CODESYS #ПЛК #АСУТП #StructuredText #ST #ПрограммированиеПЛК #Автоматизация
fbTimer(
IN := xSignal,
PT := T#5s
);
А затем использовать его выход:
IF fbTimer.Q THEN
xAlarm := TRUE;
END_IF
Так алгоритм легко читать:
xSignal определяет состояние входа таймера на каждом цикле ПЛК.━━━━━━━━━━━━━━━━━━
🔎 Для чего нужен ET?
ET показывает текущее прошедшее время.Например:
fbTimer.ET
может иметь значения:
T#500ms
T#2s
T#4s
T#5s
Это удобно использовать для:
• диагностики программы
• отображения времени на HMI
• индикации процесса задержки
• анализа работы алгоритма
• отладки
Например, оператору можно показать:
«Авария будет подтверждена через 2.3 секунды».
Для основной логики обычно используют
Q, а ET — как дополнительную информацию.━━━━━━━━━━━━━━━━━━
📌 Коротко: алгоритм TON
Если:
IN = FALSEполучаем:
ET = T#0s
Q = FALSE
Если:
IN = TRUEначинается отсчёт.
Пока:
ET < PT
получаем:
Q = FALSEКогда:
ET ≥ PT
получаем:
Q = TRUEЕсли после этого:
IN = FALSEтаймер снова сбрасывается.
━━━━━━━━━━━━━━━━━━
💡 Где TON используется на практике?
Очень часто:
• задержка формирования аварии
• фильтрация кратковременных сигналов
• задержка включения оборудования
• контроль устойчивого состояния датчика
• контроль длительного превышения параметра
• ожидание перед переходом на следующий шаг алгоритма
• антидребезг дискретных сигналов
• задержка разрешения операции
Главный вопрос при выборе
TON:«Нужно ли мне убедиться, что условие непрерывно выполняется заданное время?»
Если да —
TON обычно подходит.━━━━━━━━━━━━━━━━━━
🧠 Запомните
TON — это не просто команда:«подождать 5 секунд».
Это проверка:
«Оставался ли вход IN непрерывно в TRUE в течение заданного времени PT?»
Даже кратковременный переход
IN в FALSE приводит к сбросу отсчёта.И именно поэтому таймер иногда кажется «неработающим», хотя на самом деле работает совершенно правильно.
━━━━━━━━━━━━━━━━━━
❓ Проверим себя
Пусть задано:
PT := T#5s
Сигнал ведёт себя так:
TRUE → 4.9 сек
FALSE → 0.1 сек
TRUE → 4.9 сек
Станет ли
Q = TRUE хотя бы на одном цикле?💬 Напишите свой ответ в комментариях 👇
#CODESYS #ПЛК #АСУТП #StructuredText #ST #ПрограммированиеПЛК #Автоматизация
🧠 РАЗБОР КОДА: TON
Сигнал
Таймер:
❓ Станет ли
Попробуйте ответить до того, как откроете разбор.
👇 Правильный ответ — в следующем посте.
#CODESYS #ПЛК #TON #StructuredText
Сигнал
xSignal был:TRUE → 4.9 сек
FALSE → 0.1 сек
TRUE → 4.9 сек
Таймер:
fbTimer(
IN := xSignal,
PT := T#5s
);
❓ Станет ли
Q = TRUE?Попробуйте ответить до того, как откроете разбор.
👇 Правильный ответ — в следующем посте.
#CODESYS #ПЛК #TON #StructuredText
🧠 РАЗБОР КОДА: TON
Разберём задачу.
Есть таймер:
Сигнал на входе меняется так:
Начальное состояние:
❓ Что произойдёт с выходом
А)
Б)
В)
Г)
Сначала выберите вариант, потом откройте ответ 👇
🔎 Открыть правильный ответ
✅ Правильный ответ — В.
Q ни разу не станет TRUE.
Почему?
В первом интервале:
xSignal = TRUE → 4.9 сек
До PT = 5 сек не хватает 0.1 секунды, поэтому Q остаётся FALSE.
Затем сигнал становится FALSE.
Для TON это означает сброс:
ET → T#0s
Q → FALSE
После этого, когда xSignal снова становится TRUE, таймер начинает отсчёт заново.
Во втором интервале сигнал снова активен только 4.9 секунды, а этого опять недостаточно.
Поэтому Q ни разу не станет TRUE.
💡 Главная мысль
Как только:
таймер сбрасывается.
💬 Получилось ответить правильно до открытия спойлера?
#CODESYS #ПЛК #TON #StructuredText #ПрограммированиеПЛК
Разберём задачу.
Есть таймер:
fbTimer(
IN := xSignal,
PT := T#5s
);
Сигнал на входе меняется так:
TRUE → 4.9 сек
FALSE → 0.1 сек
TRUE → 4.9 сек
Начальное состояние:
Q = FALSE
ET = T#0s
❓ Что произойдёт с выходом
Q?А)
Q станет TRUE, потому что суммарно сигнал был TRUE больше 5 секундБ)
Q станет TRUE во втором интервале TRUEВ)
Q ни разу не станет TRUEГ)
Q кратковременно станет TRUE в момент сбросаСначала выберите вариант, потом откройте ответ 👇
🔎 Открыть правильный ответ
Q ни разу не станет TRUE.
Почему?
В первом интервале:
xSignal = TRUE → 4.9 сек
До PT = 5 сек не хватает 0.1 секунды, поэтому Q остаётся FALSE.
Затем сигнал становится FALSE.
Для TON это означает сброс:
ET → T#0s
Q → FALSE
После этого, когда xSignal снова становится TRUE, таймер начинает отсчёт заново.
Во втором интервале сигнал снова активен только 4.9 секунды, а этого опять недостаточно.
Поэтому Q ни разу не станет TRUE.
💡 Главная мысль
TON считает не суммарное время активности сигнала, а время, в течение которого вход IN находится в TRUE непрерывно.Как только:
IN = FALSEтаймер сбрасывается.
💬 Получилось ответить правильно до открытия спойлера?
#CODESYS #ПЛК #TON #StructuredText #ПрограммированиеПЛК
👍3
⚡ R_TRIG и F_TRIG в CODESYS
Сигнал может оставаться
Но иногда нам нужен только один конкретный момент:
⬆️ сигнал появился
⬇️ сигнал исчез
Для этого в CODESYS используются
👇 В следующем посте подробно разберём, как они работают и где применяются.
#CODESYS #ПЛК #StructuredText #R_TRIG #F_TRIG
Сигнал может оставаться
TRUE или FALSE сотни циклов.Но иногда нам нужен только один конкретный момент:
⬆️ сигнал появился
⬇️ сигнал исчез
Для этого в CODESYS используются
R_TRIG и F_TRIG.👇 В следующем посте подробно разберём, как они работают и где применяются.
#CODESYS #ПЛК #StructuredText #R_TRIG #F_TRIG
⚡ R_TRIG и F_TRIG в CODESYS: как поймать момент изменения сигнала?
В программах ПЛК постоянно приходится работать с дискретными сигналами:
• кнопка нажата
• двигатель работает
• датчик сработал
• авария появилась
• команда исчезла
Но очень важно различать:
состояние сигнала
и
момент изменения сигнала.
Именно для второго случая в CODESYS используются функциональные блоки
━━━━━━━━━━━━━━━━━━
🔹 Состояние и событие — не одно и то же
Допустим:
Если написать:
команда будет выполняться каждый цикл ПЛК, пока кнопка остаётся нажатой.
Например, если цикл программы составляет 10 мс, а кнопку держат одну секунду, код может выполниться около 100 раз.
Но иногда нам нужно выполнить действие только один раз:
именно в момент нажатия.
Для этого необходимо определить переход:
Это называется передним фронтом.
━━━━━━━━━━━━━━━━━━
⬆️ R_TRIG — передний фронт
Объявим функциональный блок:
Вызываем его каждый цикл:
Когда
выход:
станет
После этого, даже если
до следующего нового фронта.
━━━━━━━━━━━━━━━━━━
🧠 Пример
Пусть сигнал выглядит так:
Выход
То есть импульс появляется только в момент изменения сигнала.
━━━━━━━━━━━━━━━━━━
✅ Практический пример с кнопкой
Нужно увеличивать счётчик один раз при каждом нажатии:
Теперь:
🔘 нажали →
⏳ держим → ничего
🔘 отпустили → ничего
🔘 нажали снова → ещё
━━━━━━━━━━━━━━━━━━
⬇️ А что делает F_TRIG?
Он определяет переход:
То есть задний фронт сигнала.
Объявление:
Вызов:
Когда сигнал изменится:
получим:
на один цикл ПЛК.
━━━━━━━━━━━━━━━━━━
🔄 R_TRIG и F_TRIG рядом
Для одного сигнала можно использовать оба блока:
Получаем:
Таким образом можно отдельно обработать появление и исчезновение одного и того же сигнала.
━━━━━━━━━━━━━━━━━━
🏭 Где применяется R_TRIG?
Передний фронт очень часто нужен для:
• обработки нажатия кнопки
• запуска последовательности
• подсчёта событий
• регистрации появления аварии
• формирования однократной команды
• переключения режима
• увеличения или уменьшения значения
• запуска операции с HMI
Например:
Переход выполняется один раз — именно при появлении команды.
━━━━━━━━━━━━━━━━━━
🏭 Где применяется F_TRIG?
Задний фронт полезен, когда действие должно происходить при исчезновении сигнала.
Например:
• оператор отпустил кнопку
• механизм остановился
• датчик перестал быть активным
• команда была снята
• аварийное условие исчезло
Пример:
Счётчик увеличится именно в момент перехода:
━━━━━━━━━━━━━━━━━━
⚠️ Важный момент
В программах ПЛК постоянно приходится работать с дискретными сигналами:
• кнопка нажата
• двигатель работает
• датчик сработал
• авария появилась
• команда исчезла
Но очень важно различать:
состояние сигнала
и
момент изменения сигнала.
Именно для второго случая в 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
━━━━━━━━━━━━━━━━━━
⚠️ Важный момент
R_TRIG и F_TRIG должны помнить состояние входа на предыдущем вызове.Поэтому экземпляр функционального блока нужно вызывать циклически.
Например:
fbRise(CLK := xSignal);
на каждом выполнении задачи.
Не стоит вызывать блок только изредка в случайной ветке программы, если вы хотите надёжно отслеживать каждый переход сигнала.
━━━━━━━━━━━━━━━━━━
⚠️ Ещё одна частая ошибка
Не нужно использовать один экземпляр
R_TRIG для нескольких независимых сигналов.Плохо:
fbTrig(CLK := xStart);
...
fbTrig(CLK := xReset);
У блока есть внутреннее состояние.
Для разных сигналов лучше создавать разные экземпляры:
fbStart : R_TRIG;
fbReset : R_TRIG;
и вызывать их отдельно:
fbStart(CLK := xStart);
fbReset(CLK := xReset);
Так программа будет понятнее и предсказуемее.
━━━━━━━━━━━━━━━━━━
💡 Главное различие
Обычный:
IF xSignal THEN
отвечает на вопрос:
«Сигнал сейчас TRUE?»
R_TRIG отвечает:«Сигнал только что изменился с FALSE на TRUE?»
А
F_TRIG:«Сигнал только что изменился с TRUE на FALSE?»
━━━━━━━━━━━━━━━━━━
📌 Запомните
⬆️
R_TRIGFALSE → TRUE
Передний фронт — сигнал появился.
⬇️
F_TRIGTRUE → FALSE
Задний фронт — сигнал исчез.
Выход
Q активируется только на один цикл программы при обнаружении соответствующего перехода.━━━━━━━━━━━━━━━━━━
❓ Проверим себя
Сигнал изменяется так:
FALSE
FALSE
TRUE
TRUE
FALSE
FALSE
TRUE
Сколько раз за это время сработает
R_TRIG, а сколько — F_TRIG?💬 Напишите ответ в комментариях, не подглядывая в документацию 👇
#CODESYS #ПЛК #АСУТП #StructuredText #ST #R_TRIG #F_TRIG #ПрограммированиеПЛК
🧠 РАЗБОР КОДА: R_TRIG и F_TRIG
Посмотрите на изменение сигнала по циклам ПЛК:
Для этого сигнала работают два блока:
где:
⬆️
⬇️
❓ Сколько раз за эти 7 циклов сработают R_TRIG и F_TRIG?
А) R_TRIG — 1, F_TRIG — 1
Б) R_TRIG — 2, F_TRIG — 1
В) R_TRIG — 2, F_TRIG — 2
Г) R_TRIG — 3, F_TRIG — 2
Выберите вариант до того, как посмотрите разбор 👇
Правильный ответ — в следующем посте.
#CODESYS #ПЛК #R_TRIG #F_TRIG #StructuredText
Посмотрите на изменение сигнала по циклам ПЛК:
Цикл: 1 2 3 4 5 6 7
Signal: FALSE FALSE TRUE TRUE FALSE FALSE TRUE
Для этого сигнала работают два блока:
fbRise(CLK := xSignal);
fbFall(CLK := xSignal);
где:
⬆️
fbRise — R_TRIG ⬇️
fbFall — F_TRIG❓ Сколько раз за эти 7 циклов сработают R_TRIG и F_TRIG?
А) R_TRIG — 1, F_TRIG — 1
Б) R_TRIG — 2, F_TRIG — 1
В) R_TRIG — 2, F_TRIG — 2
Г) R_TRIG — 3, F_TRIG — 2
Выберите вариант до того, как посмотрите разбор 👇
Правильный ответ — в следующем посте.
#CODESYS #ПЛК #R_TRIG #F_TRIG #StructuredText
✅ РАЗБОР ЗАДАЧИ: R_TRIG и F_TRIG
Исходный сигнал:
❓ Сколько раз сработают R_TRIG и F_TRIG?
А) R_TRIG — 1, F_TRIG — 1
Б) R_TRIG — 2, F_TRIG — 1
В) R_TRIG — 2, F_TRIG — 2
Г) R_TRIG — 3, F_TRIG — 2
Сначала выберите вариант, затем откройте разбор 👇
🔎 Открыть правильный ответ
✅ Правильный ответ — Б.
R_TRIG сработает 2 раза.
F_TRIG сработает 1 раз.
Разберём по шагам.
⬆️ Между циклами 2 и 3:
FALSE → TRUE
Это передний фронт.
Значит:
R_TRIG.Q = TRUE
только на один цикл.
На следующем цикле сигнал всё ещё TRUE, но нового фронта уже нет.
⬇️ Между циклами 4 и 5:
TRUE → FALSE
Это задний фронт.
Значит:
F_TRIG.Q = TRUE
только на один цикл.
⬆️ Между циклами 6 и 7 снова происходит:
FALSE → TRUE
Поэтому R_TRIG срабатывает второй раз.
Итого:
R_TRIG — 2 срабатывания
F_TRIG — 1 срабатывание
💡 Главная мысль
Само длительное состояние
💬 Получилось ответить правильно до открытия спойлера?
#CODESYS #ПЛК #R_TRIG #F_TRIG #StructuredText #ПрограммированиеПЛК
Исходный сигнал:
Цикл: 1 2 3 4 5 6 7
Signal: FALSE FALSE TRUE TRUE FALSE FALSE TRUE
❓ Сколько раз сработают R_TRIG и F_TRIG?
А) R_TRIG — 1, F_TRIG — 1
Б) R_TRIG — 2, F_TRIG — 1
В) R_TRIG — 2, F_TRIG — 2
Г) R_TRIG — 3, F_TRIG — 2
Сначала выберите вариант, затем откройте разбор 👇
🔎 Открыть правильный ответ
R_TRIG сработает 2 раза.
F_TRIG сработает 1 раз.
Разберём по шагам.
⬆️ Между циклами 2 и 3:
FALSE → TRUE
Это передний фронт.
Значит:
R_TRIG.Q = TRUE
только на один цикл.
На следующем цикле сигнал всё ещё TRUE, но нового фронта уже нет.
⬇️ Между циклами 4 и 5:
TRUE → FALSE
Это задний фронт.
Значит:
F_TRIG.Q = TRUE
только на один цикл.
⬆️ Между циклами 6 и 7 снова происходит:
FALSE → TRUE
Поэтому R_TRIG срабатывает второй раз.
Итого:
R_TRIG — 2 срабатывания
F_TRIG — 1 срабатывание
💡 Главная мысль
R_TRIG реагирует только на:FALSE → TRUEF_TRIG — только на:TRUE → FALSEСамо длительное состояние
TRUE или FALSE новых импульсов не создаёт.💬 Получилось ответить правильно до открытия спойлера?
#CODESYS #ПЛК #R_TRIG #F_TRIG #StructuredText #ПрограммированиеПЛК
📘 Новая книга по CODESYS 3.5
Подготовил практическую книгу по программированию ПЛК в CODESYS.
Внутри — понятные объяснения, примеры на Structured Text и разборы типовых задач.
📎 Книгу прикрепляю к этому посту.
Если материал окажется полезным — поделитесь постом с друзьями и коллегами, которым интересны ПЛК, CODESYS и промышленная автоматизация.
🔁 Репосты очень помогают развивать канал и делать больше полезных материалов.
#CODESYS #ПЛК #АСУТП #StructuredText #ПрограммированиеПЛК
Подготовил практическую книгу по программированию ПЛК в CODESYS.
Внутри — понятные объяснения, примеры на Structured Text и разборы типовых задач.
📎 Книгу прикрепляю к этому посту.
Если материал окажется полезным — поделитесь постом с друзьями и коллегами, которым интересны ПЛК, CODESYS и промышленная автоматизация.
🔁 Репосты очень помогают развивать канал и делать больше полезных материалов.
#CODESYS #ПЛК #АСУТП #StructuredText #ПрограммированиеПЛК
👍1🤝1
🔀 CASE в CODESYS: когда алгоритм начинает тонуть в IF
Небольшой проект легко написать на нескольких
Но когда появляются этапы запуска, ожидание датчиков, таймеры, остановка и аварии — код быстро превращается в запутанную цепочку условий.
Для последовательных алгоритмов часто удобнее связка:
Например:
Каждое состояние имеет свою логику, а переменная
👇 В следующем посте — подробный пример на Structured Text.
📤 Если тема актуальна — перешлите пост коллеге, который программирует ПЛК.
#CODESYS #ПЛК #StructuredText #CASE #ПрограммированиеПЛК
Небольшой проект легко написать на нескольких
IF.Но когда появляются этапы запуска, ожидание датчиков, таймеры, остановка и аварии — код быстро превращается в запутанную цепочку условий.
Для последовательных алгоритмов часто удобнее связка:
ENUM + CASEНапример:
IDLE → STARTING → WORKING → STOPPING → IDLE
Каждое состояние имеет свою логику, а переменная
eState всегда показывает, где сейчас находится алгоритм.👇 В следующем посте — подробный пример на Structured Text.
📤 Если тема актуальна — перешлите пост коллеге, который программирует ПЛК.
#CODESYS #ПЛК #StructuredText #CASE #ПрограммированиеПЛК
🔀 CASE в CODESYS: как строить понятные пошаговые алгоритмы
По мере роста программы ПЛК часто появляется что-то похожее:
Сначала всё выглядит нормально.
Но потом появляются:
• дополнительные условия
• блокировки
• таймеры
• аварийные переходы
• ручной режим
• повторный запуск
И через некоторое время становится трудно ответить на простой вопрос:
«На каком этапе сейчас находится алгоритм?»
Для последовательных процессов часто удобнее использовать
━━━━━━━━━━━━━━━━━━
🏭 Пример задачи
Пусть после команды «Пуск» механизм должен:
1️⃣ включить двигатель
2️⃣ дождаться срабатывания датчика
3️⃣ работать ещё 5 секунд
4️⃣ остановиться
У процесса можно выделить четыре состояния:
Создадим перечисление:
И переменную текущего состояния:
Теперь вместо нескольких BOOL-переменных вида:
мы имеем одну:
которая однозначно показывает текущий этап.
━━━━━━━━━━━━━━━━━━
⏱ Сначала подготовим таймер
Пусть в состоянии
Объявим:
Таймер удобно вызывать циклически:
Когда состояние становится
При выходе из этого состояния:
и
━━━━━━━━━━━━━━━━━━
🔧 Теперь сам CASE
Теперь структура алгоритма читается почти как описание технологического процесса.
━━━━━━━━━━━━━━━━━━
🔎 Разберём по шагам
1. IDLE
Механизм находится в ожидании:
При появлении команды:
выполняется:
━━━━━━━━━━━━━━━━━━
2. STARTING
Включаем двигатель:
И ждём подтверждающий сигнал от датчика:
Пока датчик не сработал, алгоритм остаётся в
━━━━━━━━━━━━━━━━━━
3. WORKING
Двигатель продолжает работать:
А таймер:
станет
После этого:
━━━━━━━━━━━━━━━━━━
4. STOPPING
Останавливаем двигатель:
и возвращаем автомат в исходное состояние:
Цикл завершён.
━━━━━━━━━━━━━━━━━━
🧠 Что здесь даёт CASE?
Представим:
Тогда выполняется только логика ветки:
Код
Поэтому состояния процесса хорошо отделены друг от друга.
━━━━━━━━━━━━━━━━━━
⚠️ Важная особенность переходов
Допустим, внутри
Это не означает, что ветка
Текущая ветка уже была выбрана.
По мере роста программы ПЛК часто появляется что-то похожее:
IF xStart AND NOT xStep1 THEN
...
END_IF;
IF xStep1 AND xSensor THEN
...
END_IF;
IF xStep2 AND fbTimer.Q THEN
...
END_IF;
Сначала всё выглядит нормально.
Но потом появляются:
• дополнительные условия
• блокировки
• таймеры
• аварийные переходы
• ручной режим
• повторный запуск
И через некоторое время становится трудно ответить на простой вопрос:
«На каком этапе сейчас находится алгоритм?»
Для последовательных процессов часто удобнее использовать
CASE и явно хранить текущее состояние.━━━━━━━━━━━━━━━━━━
🏭 Пример задачи
Пусть после команды «Пуск» механизм должен:
1️⃣ включить двигатель
2️⃣ дождаться срабатывания датчика
3️⃣ работать ещё 5 секунд
4️⃣ остановиться
У процесса можно выделить четыре состояния:
IDLE
STARTING
WORKING
STOPPING
Создадим перечисление:
TYPE E_State :
(
IDLE,
STARTING,
WORKING,
STOPPING
);
END_TYPE
И переменную текущего состояния:
VAR
eState : E_State := IDLE;
END_VAR
Теперь вместо нескольких BOOL-переменных вида:
xStep1
xStep2
xStep3
xStep4
мы имеем одну:
eStateкоторая однозначно показывает текущий этап.
━━━━━━━━━━━━━━━━━━
⏱ Сначала подготовим таймер
Пусть в состоянии
WORKING механизм должен работать 5 секунд.Объявим:
VAR
eState : E_State := IDLE;
fbWorkTimer : TON;
xStart : BOOL;
xSensor : BOOL;
xMotor : BOOL;
END_VAR
Таймер удобно вызывать циклически:
fbWorkTimer(
IN := eState = WORKING,
PT := T#5s
);
Когда состояние становится
WORKING, таймер начинает отсчёт.При выходе из этого состояния:
IN = FALSE
и
TON сбрасывается.━━━━━━━━━━━━━━━━━━
🔧 Теперь сам CASE
CASE eState OF
IDLE:
xMotor := FALSE;
IF xStart THEN
eState := STARTING;
END_IF;
STARTING:
xMotor := TRUE;
IF xSensor THEN
eState := WORKING;
END_IF;
WORKING:
xMotor := TRUE;
IF fbWorkTimer.Q THEN
eState := STOPPING;
END_IF;
STOPPING:
xMotor := FALSE;
eState := IDLE;
END_CASE
Теперь структура алгоритма читается почти как описание технологического процесса.
━━━━━━━━━━━━━━━━━━
🔎 Разберём по шагам
1. IDLE
Механизм находится в ожидании:
xMotor := FALSE;
При появлении команды:
xStart = TRUE
выполняется:
eState := STARTING;
━━━━━━━━━━━━━━━━━━
2. STARTING
Включаем двигатель:
xMotor := TRUE;
И ждём подтверждающий сигнал от датчика:
IF xSensor THEN
eState := WORKING;
END_IF;
Пока датчик не сработал, алгоритм остаётся в
STARTING.━━━━━━━━━━━━━━━━━━
3. WORKING
Двигатель продолжает работать:
xMotor := TRUE;
А таймер:
fbWorkTimer.Q
станет
TRUE после пяти секунд пребывания в состоянии WORKING.После этого:
eState := STOPPING;
━━━━━━━━━━━━━━━━━━
4. STOPPING
Останавливаем двигатель:
xMotor := FALSE;
и возвращаем автомат в исходное состояние:
eState := IDLE;
Цикл завершён.
━━━━━━━━━━━━━━━━━━
🧠 Что здесь даёт CASE?
Представим:
eState = STARTING
Тогда выполняется только логика ветки:
STARTING:
Код
IDLE, WORKING и STOPPING в этом выполнении CASE не выполняется.Поэтому состояния процесса хорошо отделены друг от друга.
━━━━━━━━━━━━━━━━━━
⚠️ Важная особенность переходов
Допустим, внутри
STARTING выполняется:eState := WORKING;
Это не означает, что ветка
WORKING немедленно начнёт выполняться ниже в том же CASE.Текущая ветка уже была выбрана.
При следующем выполнении этого
Для циклической программы ПЛК это обычно означает переход к новой логике на следующем цикле задачи.
━━━━━━━━━━━━━━━━━━
✅ Почему ENUM лучше набора чисел?
Можно было бы написать:
Но что означает:
Без дополнительного описания — непонятно.
А:
читается сразу.
Именно поэтому для состояний удобно использовать
━━━━━━━━━━━━━━━━━━
🔧 Диагностика тоже становится проще
Если механизм остановился и оператор сообщает:
«Почему он не продолжает работу?»
в онлайн-режиме можно посмотреть:
После этого понятно:
алгоритм ждёт условия перехода из
В нашем случае первым делом стоит проверить:
Это значительно удобнее, чем искать комбинацию из нескольких:
━━━━━━━━━━━━━━━━━━
🏗 Где такой подход особенно полезен?
• последовательностей запуска оборудования
• пошаговых технологических процессов
• дозирования
• промывки
• продувки
• перемещения механизмов
• автоматических циклов
• управления режимами
• конечных автоматов
• процедур запуска и останова
━━━━━━━━━━━━━━━━━━
⚠️ Но CASE — не замена каждому IF
Не нужно превращать вообще всю программу в одну гигантскую машину состояний.
Если необходимо просто проверить условие:
обычный
состояния → условия перехода → следующее состояние.
━━━━━━━━━━━━━━━━━━
💡 Главная мысль
«Выполняется ли условие?»
А связка:
помогает описать:
«В каком состоянии находится алгоритм и куда он должен перейти дальше?»
Для небольшого кода разница может быть незаметна.
Но в большом промышленном проекте понятная структура программы сильно упрощает:
• разработку
• ПНР
• диагностику
• сопровождение
• последующую доработку
Хороший код должен быть понятен не только ПЛК, но и инженеру, который откроет проект через год.
━━━━━━━━━━━━━━━━━━
💬 А как вы строите пошаговые алгоритмы?
Используете
📤 Если статья оказалась полезной — отправьте её другу или коллеге, который работает с CODESYS и ПЛК.
🔁 Можно также репостнуть материал в профильный чат или канал — так о наших технических разборах узнает больше инженеров.
#CODESYS #ПЛК #АСУТП #StructuredText #ST #CASE #ENUM #ПрограммированиеПЛК
CASE значение eState будет прочитано снова, и тогда будет выбрана ветка:WORKING:
Для циклической программы ПЛК это обычно означает переход к новой логике на следующем цикле задачи.
━━━━━━━━━━━━━━━━━━
✅ Почему ENUM лучше набора чисел?
Можно было бы написать:
iState := 0;
iState := 10;
iState := 20;
iState := 30;
Но что означает:
iState = 20?Без дополнительного описания — непонятно.
А:
eState = WORKING
читается сразу.
Именно поэтому для состояний удобно использовать
ENUM.━━━━━━━━━━━━━━━━━━
🔧 Диагностика тоже становится проще
Если механизм остановился и оператор сообщает:
«Почему он не продолжает работу?»
в онлайн-режиме можно посмотреть:
eState = STARTING
После этого понятно:
алгоритм ждёт условия перехода из
STARTING.В нашем случае первым делом стоит проверить:
xSensorЭто значительно удобнее, чем искать комбинацию из нескольких:
xStep1, xStep2, xStep3...━━━━━━━━━━━━━━━━━━
🏗 Где такой подход особенно полезен?
ENUM + CASE хорошо подходит для:• последовательностей запуска оборудования
• пошаговых технологических процессов
• дозирования
• промывки
• продувки
• перемещения механизмов
• автоматических циклов
• управления режимами
• конечных автоматов
• процедур запуска и останова
━━━━━━━━━━━━━━━━━━
⚠️ Но CASE — не замена каждому IF
Не нужно превращать вообще всю программу в одну гигантскую машину состояний.
Если необходимо просто проверить условие:
IF rTemperature > 90.0 THEN
xHighTemp := TRUE;
END_IF;
обычный
IF прекрасно подходит.CASE особенно полезен тогда, когда есть:состояния → условия перехода → следующее состояние.
━━━━━━━━━━━━━━━━━━
💡 Главная мысль
IF отвечает на вопрос:«Выполняется ли условие?»
А связка:
ENUM + CASE
помогает описать:
«В каком состоянии находится алгоритм и куда он должен перейти дальше?»
Для небольшого кода разница может быть незаметна.
Но в большом промышленном проекте понятная структура программы сильно упрощает:
• разработку
• ПНР
• диагностику
• сопровождение
• последующую доработку
Хороший код должен быть понятен не только ПЛК, но и инженеру, который откроет проект через год.
━━━━━━━━━━━━━━━━━━
💬 А как вы строите пошаговые алгоритмы?
Используете
CASE, отдельные BOOL для каждого шага или свой шаблон машины состояний?📤 Если статья оказалась полезной — отправьте её другу или коллеге, который работает с CODESYS и ПЛК.
🔁 Можно также репостнуть материал в профильный чат или канал — так о наших технических разборах узнает больше инженеров.
#CODESYS #ПЛК #АСУТП #StructuredText #ST #CASE #ENUM #ПрограммированиеПЛК
👍3