🧠 РАЗБОР КОДА: 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 #ПрограммированиеПЛК
👍5
⚠️ Один экземпляр ФБ — два вызова. Что может пойти не так?
В CODESYS функциональные блоки хранят внутреннее состояние между вызовами.
Но что произойдёт, если один экземпляр вызвать дважды за один цикл ПЛК? 🤔
Например:
Оказывается, повторный вызов может привести к неожиданному поведению программы.
Особенно это важно для
🔍 Почему так происходит и как избежать ошибок?
👇 Подробный разбор с примерами — в следующем посте.
#CODESYS #ПЛК #StructuredText #ПрограммированиеПЛК
В CODESYS функциональные блоки хранят внутреннее состояние между вызовами.
Но что произойдёт, если один экземпляр вызвать дважды за один цикл ПЛК? 🤔
Например:
fbCounter(xEnable := TRUE);
fbCounter(xEnable := TRUE);
Оказывается, повторный вызов может привести к неожиданному поведению программы.
Особенно это важно для
TON, R_TRIG, счётчиков и собственных функциональных блоков.🔍 Почему так происходит и как избежать ошибок?
👇 Подробный разбор с примерами — в следующем посте.
#CODESYS #ПЛК #StructuredText #ПрограммированиеПЛК
⚙️ FUNCTION_BLOCK в CODESYS: почему повторный вызов может изменить результат?
📘 Часть 1/2. Внутренняя память и повторные вызовы
Функциональные блоки — основа многих программ ПЛК.
Таймеры, счётчики, триггеры, управление оборудованием, обмен по Modbus — всё это часто реализуется через
Но есть важная особенность:
Функциональный блок сохраняет своё внутреннее состояние между вызовами.
Если один экземпляр вызвать несколько раз за цикл программы, его код выполнится несколько раз.
Разберём, почему это важно.
━━━━━━━━━━━━━━━━━━
🔹 FUNCTION и FUNCTION_BLOCK — в чём разница?
В Structured Text используются разные типы программных единиц.
FUNCTION — функция.
Обычно применяется для вычислений и преобразований данных.
Например:
FUNCTION_BLOCK — функциональный блок.
В отличие от обычной функции, экземпляр ФБ может сохранять значения внутренних переменных между вызовами.
Например:
Каждый экземпляр имеет собственную память.
Именно поэтому
━━━━━━━━━━━━━━━━━━
🔄 Что происходит при вызове ФБ?
Создадим простой функциональный блок:
В программе объявим экземпляр:
И вызовем:
При каждом вызове выполняется тело функционального блока.
Значение
Если вызывать блок один раз за цикл, счётчик будет увеличиваться на единицу за цикл.
━━━━━━━━━━━━━━━━━━
⚠️ Что произойдёт при двух вызовах?
Теперь напишем:
Оба вызова обращаются к одному и тому же экземпляру.
Предположим, начальное значение:
После первого вызова:
После второго:
Получается, что за один цикл ПЛК счётчик увеличился сразу на две единицы.
Если продолжить выполнение:
Причина проста: каждый вызов повторно выполняет код ФБ.
━━━━━━━━━━━━━━━━━━
🧠 Почему это важно?
Функциональный блок — не просто набор инструкций.
Его экземпляр хранит собственные данные.
При повторном вызове используется та же память, а не создаётся новый независимый объект.
Это особенно важно для блоков, работа которых зависит от предыдущих состояний.
Например:
•
•
•
• Собственные ФБ могут хранить этапы алгоритма.
Повторный вызов может изменить результат работы всей программы.
━━━━━━━━━━━━━━━━━━
📌 Вывод первой части
Два вызова одного экземпляра ФБ — это не два независимых функциональных блока.
Это повторное выполнение одного объекта с общей внутренней памятью.
➡️ В части 2 рассмотрим более интересную ситуацию: как два вызова одного
#CODESYS #ПЛК #StructuredText #FUNCTION_BLOCK
📘 Часть 1/2. Внутренняя память и повторные вызовы
Функциональные блоки — основа многих программ ПЛК.
Таймеры, счётчики, триггеры, управление оборудованием, обмен по Modbus — всё это часто реализуется через
FUNCTION_BLOCK.Но есть важная особенность:
Функциональный блок сохраняет своё внутреннее состояние между вызовами.
Если один экземпляр вызвать несколько раз за цикл программы, его код выполнится несколько раз.
Разберём, почему это важно.
━━━━━━━━━━━━━━━━━━
🔹 FUNCTION и FUNCTION_BLOCK — в чём разница?
В Structured Text используются разные типы программных единиц.
FUNCTION — функция.
Обычно применяется для вычислений и преобразований данных.
Например:
rResult := ABS(rValue);
FUNCTION_BLOCK — функциональный блок.
В отличие от обычной функции, экземпляр ФБ может сохранять значения внутренних переменных между вызовами.
Например:
fbTimer : TON;
fbTrig : R_TRIG;
Каждый экземпляр имеет собственную память.
Именно поэтому
TON отсчитывает время, а R_TRIG способен обнаруживать фронт сигнала.━━━━━━━━━━━━━━━━━━
🔄 Что происходит при вызове ФБ?
Создадим простой функциональный блок:
FUNCTION_BLOCK FB_Counter
VAR_INPUT
xEnable : BOOL;
END_VAR
VAR_OUTPUT
iCount : INT;
END_VAR
IF xEnable THEN
iCount := iCount + 1;
END_IF;
В программе объявим экземпляр:
VAR
fbCounter : FB_Counter;
END_VAR
И вызовем:
fbCounter(xEnable := TRUE);
При каждом вызове выполняется тело функционального блока.
Значение
iCount при этом сохраняется внутри экземпляра.Если вызывать блок один раз за цикл, счётчик будет увеличиваться на единицу за цикл.
━━━━━━━━━━━━━━━━━━
⚠️ Что произойдёт при двух вызовах?
Теперь напишем:
fbCounter(xEnable := TRUE);
fbCounter(xEnable := TRUE);
Оба вызова обращаются к одному и тому же экземпляру.
Предположим, начальное значение:
iCount = 0
После первого вызова:
iCount = 1
После второго:
iCount = 2
Получается, что за один цикл ПЛК счётчик увеличился сразу на две единицы.
Если продолжить выполнение:
Цикл 1 → 2
Цикл 2 → 4
Цикл 3 → 6
Цикл 4 → 8
Причина проста: каждый вызов повторно выполняет код ФБ.
━━━━━━━━━━━━━━━━━━
🧠 Почему это важно?
Функциональный блок — не просто набор инструкций.
Его экземпляр хранит собственные данные.
При повторном вызове используется та же память, а не создаётся новый независимый объект.
Это особенно важно для блоков, работа которых зависит от предыдущих состояний.
Например:
•
R_TRIG запоминает предыдущее состояние сигнала.•
TON хранит состояние таймера.•
CTU хранит значение счётчика.• Собственные ФБ могут хранить этапы алгоритма.
Повторный вызов может изменить результат работы всей программы.
━━━━━━━━━━━━━━━━━━
📌 Вывод первой части
Два вызова одного экземпляра ФБ — это не два независимых функциональных блока.
Это повторное выполнение одного объекта с общей внутренней памятью.
➡️ В части 2 рассмотрим более интересную ситуацию: как два вызова одного
R_TRIG могут создавать ложные импульсы даже при неизменном входном сигнале.#CODESYS #ПЛК #StructuredText #FUNCTION_BLOCK
⚙️ FUNCTION_BLOCK в CODESYS
📘 Часть 2/3. Почему R_TRIG может выдавать ложные импульсы?
В первой части мы выяснили, что повторные вызовы одного экземпляра ФБ используют общую внутреннюю память.
Теперь рассмотрим ошибку, которую бывает непросто обнаружить при отладке.
━━━━━━━━━━━━━━━━━━
🧠 Один R_TRIG для двух сигналов
Объявим:
И вызовем один экземпляр для двух сигналов:
На первый взгляд кажется, что мы просто проверяем два сигнала.
Но
Поэтому второй вызов использует память, которая уже изменилась после первого.
━━━━━━━━━━━━━━━━━━
🔍 Что произойдёт?
Пусть:
Перед первым вызовом внутренняя память триггера содержит
Первый вызов:
Обнаруживается переход:
Поэтому:
Но затем выполняется второй вызов:
Теперь вход равен
После этого:
Если проверить выход после обоих вызовов:
условие не выполнится.
Импульс, сформированный первым вызовом, уже исчез!
━━━━━━━━━━━━━━━━━━
⚠️ А теперь самое интересное
Предположим, сигналы не меняются:
В каждом цикле выполняются два вызова.
1️⃣ Первый получает TRUE после предыдущего FALSE и формирует импульс.
2️⃣ Второй получает FALSE и обновляет внутреннюю память.
На следующем цикле ситуация повторяется.
В результате
Это серьёзная логическая ошибка!
━━━━━━━━━━━━━━━━━━
📌 Вывод
Один экземпляр
Каждый вызов изменяет его внутреннее состояние.
➡️ В следующей части: как правильно обрабатывать независимые сигналы и какие правила стоит соблюдать при работе с ФБ.
#CODESYS #ПЛК #StructuredText #R_TRIG
📘 Часть 2/3. Почему R_TRIG может выдавать ложные импульсы?
В первой части мы выяснили, что повторные вызовы одного экземпляра ФБ используют общую внутреннюю память.
Теперь рассмотрим ошибку, которую бывает непросто обнаружить при отладке.
━━━━━━━━━━━━━━━━━━
🧠 Один R_TRIG для двух сигналов
Объявим:
VAR
fbTrig : R_TRIG;
xA : BOOL;
xB : BOOL;
END_VAR
И вызовем один экземпляр для двух сигналов:
fbTrig(CLK := xA);
fbTrig(CLK := xB);
На первый взгляд кажется, что мы просто проверяем два сигнала.
Но
R_TRIG хранит предыдущее состояние входа CLK.Поэтому второй вызов использует память, которая уже изменилась после первого.
━━━━━━━━━━━━━━━━━━
🔍 Что произойдёт?
Пусть:
xA = TRUE
xB = FALSE
Перед первым вызовом внутренняя память триггера содержит
FALSE.Первый вызов:
fbTrig(CLK := xA);
Обнаруживается переход:
FALSE → TRUE
Поэтому:
fbTrig.Q = TRUE
Но затем выполняется второй вызов:
fbTrig(CLK := xB);
Теперь вход равен
FALSE.После этого:
fbTrig.Q = FALSE
Если проверить выход после обоих вызовов:
IF fbTrig.Q THEN
// Обработка события
END_IF;
условие не выполнится.
Импульс, сформированный первым вызовом, уже исчез!
━━━━━━━━━━━━━━━━━━
⚠️ А теперь самое интересное
Предположим, сигналы не меняются:
xA = TRUE
xB = FALSE
В каждом цикле выполняются два вызова.
1️⃣ Первый получает TRUE после предыдущего FALSE и формирует импульс.
2️⃣ Второй получает FALSE и обновляет внутреннюю память.
На следующем цикле ситуация повторяется.
В результате
R_TRIG формирует импульс при каждом первом вызове, хотя xA всё время остаётся TRUE.Это серьёзная логическая ошибка!
━━━━━━━━━━━━━━━━━━
📌 Вывод
Один экземпляр
R_TRIG нельзя использовать как два независимых триггера.Каждый вызов изменяет его внутреннее состояние.
➡️ В следующей части: как правильно обрабатывать независимые сигналы и какие правила стоит соблюдать при работе с ФБ.
#CODESYS #ПЛК #StructuredText #R_TRIG
⚙️ FUNCTION_BLOCK в CODESYS
📘 Часть 3/3. Как избежать ошибок повторного вызова ФБ?
В предыдущей части мы рассмотрели, как один экземпляр
Теперь разберём правильное решение.
━━━━━━━━━━━━━━━━━━
✅ Отдельный экземпляр для каждого сигнала
Если необходимо обнаруживать передний фронт двух независимых сигналов, создаём два экземпляра:
Вызываем их отдельно:
Теперь каждый экземпляр хранит собственное предыдущее состояние входа.
Сигналы не влияют друг на друга через внутреннюю память триггера.
━━━━━━━━━━━━━━━━━━
🏭 Где это особенно важно?
Повторные вызовы могут создавать проблемы при использовании:
• таймеров
• триггеров
• счётчиков
• автоматов состояний
• блоков управления оборудованием
• блоков обмена по Modbus
• собственных ФБ с внутренней памятью
Особенно внимательно нужно относиться к экземплярам, используемым в нескольких частях программы.
━━━━━━━━━━━━━━━━━━
🔧 Можно ли вызывать один ФБ несколько раз?
Да, можно!
Сам по себе повторный вызов не запрещён.
Иногда такое поведение используется намеренно.
Но важно понимать:
Каждый вызов выполняет код того же экземпляра и может изменить его состояние.
Поэтому нельзя считать несколько вызовов одного экземпляра независимыми.
━━━━━━━━━━━━━━━━━━
💡 Практическая рекомендация
Для обычных циклических ФБ полезно придерживаться правила:
Один экземпляр — один вызов за цикл задачи.
Это не обязательное требование языка, а рекомендация по организации программы.
Так проще:
• контролировать последовательность выполнения
• диагностировать ошибки
• анализировать внутреннее состояние
• сопровождать программу
• изменять алгоритм
Если один алгоритм нужен нескольким независимым объектам, создавайте отдельные экземпляры ФБ.
━━━━━━━━━━━━━━━━━━
📌 Главное
Повторный вызов экземпляра может изменить его внутреннее состояние.
Два вызова одного ФБ ≠ два независимых ФБ.
Понимание этой особенности помогает избежать ошибок, которые сложно обнаружить при наладке оборудования.
━━━━━━━━━━━━━━━━━━
💬 Вопрос к инженерам
Сталкивались ли вы с ситуациями, когда один экземпляр ФБ вызывался из нескольких мест программы?
Какие ошибки это вызывало?
Поделитесь опытом в комментариях 👇
━━━━━━━━━━━━━━━━━━
📤 Поделитесь статьёй!
Если материал оказался полезным, перешлите все три части друзьям и коллегам, которые программируют ПЛК.
🔁 Репостните материал в профильный чат или канал — возможно, он поможет другим инженерам избежать ошибок.
📚 Больше материалов по CODESYS:
https://t.me/codesys4
#CODESYS #ПЛК #АСУТП #StructuredText #FUNCTION_BLOCK
📘 Часть 3/3. Как избежать ошибок повторного вызова ФБ?
В предыдущей части мы рассмотрели, как один экземпляр
R_TRIG может создавать ложные импульсы при обработке двух независимых сигналов.Теперь разберём правильное решение.
━━━━━━━━━━━━━━━━━━
✅ Отдельный экземпляр для каждого сигнала
Если необходимо обнаруживать передний фронт двух независимых сигналов, создаём два экземпляра:
VAR
fbTrigA : R_TRIG;
fbTrigB : R_TRIG;
xA : BOOL;
xB : BOOL;
END_VAR
Вызываем их отдельно:
fbTrigA(CLK := xA);
fbTrigB(CLK := xB);
Теперь каждый экземпляр хранит собственное предыдущее состояние входа.
fbTrigA отслеживает xA.fbTrigB отслеживает xB.Сигналы не влияют друг на друга через внутреннюю память триггера.
━━━━━━━━━━━━━━━━━━
🏭 Где это особенно важно?
Повторные вызовы могут создавать проблемы при использовании:
• таймеров
TON, TOF, TP• триггеров
R_TRIG, F_TRIG• счётчиков
CTU, CTD• автоматов состояний
• блоков управления оборудованием
• блоков обмена по Modbus
• собственных ФБ с внутренней памятью
Особенно внимательно нужно относиться к экземплярам, используемым в нескольких частях программы.
━━━━━━━━━━━━━━━━━━
🔧 Можно ли вызывать один ФБ несколько раз?
Да, можно!
Сам по себе повторный вызов не запрещён.
Иногда такое поведение используется намеренно.
Но важно понимать:
Каждый вызов выполняет код того же экземпляра и может изменить его состояние.
Поэтому нельзя считать несколько вызовов одного экземпляра независимыми.
━━━━━━━━━━━━━━━━━━
💡 Практическая рекомендация
Для обычных циклических ФБ полезно придерживаться правила:
Один экземпляр — один вызов за цикл задачи.
Это не обязательное требование языка, а рекомендация по организации программы.
Так проще:
• контролировать последовательность выполнения
• диагностировать ошибки
• анализировать внутреннее состояние
• сопровождать программу
• изменять алгоритм
Если один алгоритм нужен нескольким независимым объектам, создавайте отдельные экземпляры ФБ.
━━━━━━━━━━━━━━━━━━
📌 Главное
FUNCTION_BLOCK — программный объект с собственной памятью.Повторный вызов экземпляра может изменить его внутреннее состояние.
Два вызова одного ФБ ≠ два независимых ФБ.
Понимание этой особенности помогает избежать ошибок, которые сложно обнаружить при наладке оборудования.
━━━━━━━━━━━━━━━━━━
💬 Вопрос к инженерам
Сталкивались ли вы с ситуациями, когда один экземпляр ФБ вызывался из нескольких мест программы?
Какие ошибки это вызывало?
Поделитесь опытом в комментариях 👇
━━━━━━━━━━━━━━━━━━
📤 Поделитесь статьёй!
Если материал оказался полезным, перешлите все три части друзьям и коллегам, которые программируют ПЛК.
🔁 Репостните материал в профильный чат или канал — возможно, он поможет другим инженерам избежать ошибок.
📚 Больше материалов по CODESYS:
https://t.me/codesys4
#CODESYS #ПЛК #АСУТП #StructuredText #FUNCTION_BLOCK
🧠 РАЗБОР КОДА: R_TRIG
Один экземпляр — два вызова за цикл ПЛК.
Сигналы не изменяются:
Но один и тот же экземпляр
❓ Сколько раз увеличится счётчик за 5 циклов ПЛК?
На первый взгляд ответ очевиден. Но есть подвох! 😉
👇 Попробуйте решить задачу самостоятельно.
В следующем посте — варианты ответа и подробный разбор под спойлером.
#CODESYS #ПЛК #R_TRIG #StructuredText
Один экземпляр — два вызова за цикл ПЛК.
Сигналы не изменяются:
xA = TRUExB = FALSEНо один и тот же экземпляр
R_TRIG вызывается дважды с разными входными значениями.❓ Сколько раз увеличится счётчик за 5 циклов ПЛК?
На первый взгляд ответ очевиден. Но есть подвох! 😉
👇 Попробуйте решить задачу самостоятельно.
В следующем посте — варианты ответа и подробный разбор под спойлером.
#CODESYS #ПЛК #R_TRIG #StructuredText
🧠 РАЗБОР КОДА: R_TRIG
⚠️ Найдите подвох в программе!
В CODESYS объявлены переменные:
В каждом цикле ПЛК выполняется:
Условия:
•
•
•
• Внутренняя память R_TRIG изначально FALSE.
• Код выполняется 5 циклов подряд.
━━━━━━━━━━━━━━━━━━
❓ Чему будет равен iCount после 5 циклов?
А) 0
Б) 1
В) 5
Г) 10
Сначала выберите вариант, затем откройте ответ 👇
🔎 Нажмите, чтобы открыть разбор
✅ Правильный ответ — В) 5.
Разберём первый цикл.
1️⃣ Первый вызов:
fbTrig(CLK := xA);
Поскольку xA = TRUE, а предыдущее состояние FALSE, R_TRIG обнаруживает передний фронт.
fbTrig.Q = TRUE
Счётчик увеличивается:
iCount = 1
2️⃣ Второй вызов:
fbTrig(CLK := xB);
Поскольку xB = FALSE, блок обновляет внутреннюю память значением FALSE.
Теперь fbTrig.Q = FALSE.
На следующем цикле ситуация повторяется!
Первый вызов снова получает TRUE после FALSE и формирует импульс.
Счётчик увеличивается каждый цикл.
Результат:
Цикл 1 → iCount = 1
Цикл 2 → iCount = 2
Цикл 3 → iCount = 3
Цикл 4 → iCount = 4
Цикл 5 → iCount = 5
Итого: iCount = 5.
Хотя xA ни разу не изменялся!
Причина — повторные вызовы одного экземпляра R_TRIG с разными значениями CLK.
━━━━━━━━━━━━━━━━━━
💡 Главная мысль
Если использовать один экземпляр для разных сигналов, они будут влиять на его внутреннюю память.
Для независимых сигналов используйте отдельные экземпляры R_TRIG.
━━━━━━━━━━━━━━━━━━
💬 Получилось ответить правильно?
Напишите свой вариант в комментариях!
📤 Отправьте эту задачу коллеге-программисту ПЛК!
Проверьте, заметит ли он подвох с первого раза. 😉
🔁 Репостните интерактив в профильный чат — пусть больше инженеров проверят свои знания.
📚 Больше разборов CODESYS:
https://t.me/codesys4
#CODESYS #ПЛК #АСУТП #StructuredText #R_TRIG
⚠️ Найдите подвох в программе!
В CODESYS объявлены переменные:
VAR
fbTrig : R_TRIG;
xA : BOOL := TRUE;
xB : BOOL := FALSE;
iCount : INT := 0;
END_VAR
В каждом цикле ПЛК выполняется:
fbTrig(CLK := xA);
IF fbTrig.Q THEN
iCount := iCount + 1;
END_IF;
fbTrig(CLK := xB);
Условия:
•
xA всегда TRUE.•
xB всегда FALSE.•
iCount изначально равен 0.• Внутренняя память R_TRIG изначально FALSE.
• Код выполняется 5 циклов подряд.
━━━━━━━━━━━━━━━━━━
❓ Чему будет равен iCount после 5 циклов?
А) 0
Б) 1
В) 5
Г) 10
Сначала выберите вариант, затем откройте ответ 👇
🔎 Нажмите, чтобы открыть разбор
Разберём первый цикл.
1️⃣ Первый вызов:
fbTrig(CLK := xA);
Поскольку xA = TRUE, а предыдущее состояние FALSE, R_TRIG обнаруживает передний фронт.
fbTrig.Q = TRUE
Счётчик увеличивается:
iCount = 1
2️⃣ Второй вызов:
fbTrig(CLK := xB);
Поскольку xB = FALSE, блок обновляет внутреннюю память значением FALSE.
Теперь fbTrig.Q = FALSE.
На следующем цикле ситуация повторяется!
Первый вызов снова получает TRUE после FALSE и формирует импульс.
Счётчик увеличивается каждый цикл.
Результат:
Цикл 1 → iCount = 1
Цикл 2 → iCount = 2
Цикл 3 → iCount = 3
Цикл 4 → iCount = 4
Цикл 5 → iCount = 5
Итого: iCount = 5.
Хотя xA ни разу не изменялся!
Причина — повторные вызовы одного экземпляра R_TRIG с разными значениями CLK.
━━━━━━━━━━━━━━━━━━
💡 Главная мысль
R_TRIG запоминает предыдущее состояние входа.Если использовать один экземпляр для разных сигналов, они будут влиять на его внутреннюю память.
Для независимых сигналов используйте отдельные экземпляры R_TRIG.
━━━━━━━━━━━━━━━━━━
💬 Получилось ответить правильно?
Напишите свой вариант в комментариях!
📤 Отправьте эту задачу коллеге-программисту ПЛК!
Проверьте, заметит ли он подвох с первого раза. 😉
🔁 Репостните интерактив в профильный чат — пусть больше инженеров проверят свои знания.
📚 Больше разборов CODESYS:
https://t.me/codesys4
#CODESYS #ПЛК #АСУТП #StructuredText #R_TRIG
🎛 Интерактивный симулятор ПИД-регулятора!
Хотите наглядно увидеть, как работают P, I и D составляющие?
Подготовил небольшой симулятор, который позволяет экспериментировать с настройками ПИД-регулятора и наблюдать результат на графиках. 📈
🔧 Что можно делать:
• изменять коэффициенты
• наблюдать реакцию системы;
• изучать влияние параметров на переходный процесс;
• экспериментировать с настройками без реального оборудования.
💻 Симулятор работает локально, без установки.
📎 Файл симулятора опубликую следующим постом.
━━━━━━━━━━━━━━━━━━
📤 Поделитесь симулятором с друзьями и коллегами!
🔁 Перешлите публикацию в чаты по CODESYS и АСУ ТП — пусть больше инженеров смогут разобраться в ПИД-регулировании на практике.
📚 Больше полезных материалов:
https://t.me/codesys4
#PID #CODESYS #ПЛК #АСУТП #Автоматизация
Хотите наглядно увидеть, как работают P, I и D составляющие?
Подготовил небольшой симулятор, который позволяет экспериментировать с настройками ПИД-регулятора и наблюдать результат на графиках. 📈
🔧 Что можно делать:
• изменять коэффициенты
Kp, Ki, Kd;• наблюдать реакцию системы;
• изучать влияние параметров на переходный процесс;
• экспериментировать с настройками без реального оборудования.
💻 Симулятор работает локально, без установки.
📎 Файл симулятора опубликую следующим постом.
━━━━━━━━━━━━━━━━━━
📤 Поделитесь симулятором с друзьями и коллегами!
🔁 Перешлите публикацию в чаты по CODESYS и АСУ ТП — пусть больше инженеров смогут разобраться в ПИД-регулировании на практике.
📚 Больше полезных материалов:
https://t.me/codesys4
#PID #CODESYS #ПЛК #АСУТП #Автоматизация