📘 Часть 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