Счётчик циклов в FB CycleCounter на экране наладчика показывал 14 832. Перезагрузили ПЛК после обновления прошивки - снова 0. Оператор не заметил, а вот учёт наработки насоса для ТО поехал. В другом месте того же проекта таймер задержки пуска «забыл» оставшиеся секунды, хотя насос ещё не крутился. Код FBD не меняли. Менялось только то, что контроллер сделал cold start.
Функциональные блоки в IEC 61131-3 хранят состояние в экземпляре: внутренние переменные, таймеры, шаги автомата. После полного перезапуска без retain это состояние рождается заново из инициализации. Статья объясняет, что именно теряется, как настроить retain для переменных экземпляра, как влияют первый scan и батарея. Не учит рисовать FBD с нуля - это в обзоре FBD.
Короткий ответ
Если FB в FBD «сбрасывается» после перезапуска ПЛК, почти всегда виноваты cold start и отсутствие retain у нужных переменных экземпляра. При полной загрузке или сбросе питания без батареи все VAR экземпляра получают начальные значения из кода; сохраняются только переменные, объявленные с RETAIN / PERSISTENT в правильной области. Первый scan (bFirstRun) может дополнительно перезаписать уставки из Init. Батарея контроллера держит retain в RAM между краткими отключениями 24 В; при её смерти или долгом обесточивании данные теряются. Решение: явно пометить retain то, что должно пережить рестарт; не инициализировать поверх retain в первом цикле; проверить тип download. Таблица ниже: что теряется, почему, какая настройка.
Экземпляр FB и что в нём живёт
Вызов MyValveCtrl_01 на FBD - это не картинка, а экземпляр с памятью. Внутри FB объявляют VAR (состояние на каждый цикл), иногда VAR_INPUT / VAR_OUTPUT, VAR_IN_OUT. Таймер TON, счётчик CTU, шаг iStep автомата - всё это сидит в экземпляре. Пока ПЛК работает, состояние накапливается.
При cold start runtime создаёт экземпляры заново. Без retain внутренние переменные равны тому, что задано при объявлении: iStep := 0, bOpened := FALSE, rIntegral := 0.0. Если в VAR написали := 100 как «уставка по умолчанию», после рестарта снова будет 100, даже если до рестарта оператор выставил 80 через HMI (если 80 не в retain).
Глобальный FB (один экземпляр в GVL) и локальный (вызов на листе) ведут себя одинаково по памяти: важен атрибут retain у полей, а не место на схеме.
Retain переменных экземпляра: как объявить правильно
В CODESYS 3.5 retain для полей FB задают в объявлении переменной экземпляра или внутри типа FB:
VAR iStep : INT := 0; (* потеряется при cold start *) END_VAR VAR RETAIN rSetpoint : REAL := 50.0; (* сохранится, если батарея и область OK *) udiCycleCount : UDINT; END_VARНе всё подряд нужно в retain: выходные команды на клапан безопаснее после рестарта проходить через безопасное состояние и межблокировки, а не «помнить» открыт. В retain - уставки, рецепт, наработка, энергия, серийные счётчики, положение клапана если так записано в регламенте безопасности.
PERSISTENT (где поддерживается) переживает ещё и перепрошивку с очисткой RAM, но медленнее; для счётчиков ТО часто используют именно его.
Изменили структуру FB (добавили поле в середину RETAIN-блока) - старая retain-область может интерпретироваться неверно. После миграции структуры - один контролируемый cold start с backup уставок.
Первый scan: когда Init затирает retain
Отдельный глобальный флаг bFirstScan или метод PLC_PRG в первом цикле часто делает:
IF bFirstScan THEN MyPID.rKp := 1.2; MyTank.iLevelStep := 0; END_IFЕсли rKp в retain, а Init пишет поверх без проверки «только при первом вводе в эксплуатацию», после каждого рестарта Kp снова 1.2. Оператор думает, что retain «не работает».
Правильный паттерн: Init только для не-retain defaults или при bFactoryReset с кнопки наладчика. Retain-поля в первом scan не трогать, если нет явной команды сброса.
В FBD первый scan иногда спрятан в отдельной сети с R_TRIG на системный бит. После загрузки проекта порядок сетей важен: если сеть Init выполняется после сети с FB, FB один цикл уже успел отработать, потом Init сбросил входы.
Cold start, питание и батарея
Краткое отключение 24 В при живой батарее retain обычно держит. Долгое обесточивание шкафа или севшая батарея - retain в RAM обнуляется или заполняется мусором. Симптом: «после выходных всё сбросилось».
Проверка батареи - в регламенте ТО ПЛК, раз в год или по диагностике. На объекте фиксируют дату замены на шильдике внутри шкафа.
Полная загрузка проекта с галочкой «initialize retain» в диалоге CODESYS - намеренный сброс. После такой загрузки не удивляться нулю в счётчиках.
Связь с отладкой ПЛК: после рестарта сначала смотрят retain-переменные в watch, потом FBD-выходы.
FBD-специфика: что ещё сбрасывается
На схеме FBD видны только входы/выходы FB; внутренние VAR не нарисованы. Инженер забывает retain у iState внутри FB_Sequence, потому что на листе всё «выглядит чисто». После рестарта автомат с шага 0, хотя механизм в середине цикла - до сброса механики опасно.
Несколько вызовов одного экземпляра FB на разных листах (ошибка проектирования) дают общую память: рестарт одного места влияет на все вызовы. Retain тут не спасает от логической путаницы.
Библиотечные FB (TON, R_TRIG) хранят состояние внутри. Их внутренности не редактируют; если нужно помнить «остаток времени» через рестарт - выносят tRemaining в retain в обёртке FB или в GVL.
Обёртка FB: retain там, где стандартная библиотека не помнит
Паттерн на объекте: свой FB FB_ValveSeqRetain вызывает стандартную логику, но iStep, udiCycles, rSetpoint объявлены в VAR RETAIN обёртки. После cold start шаг и уставка восстанавливаются, внутренний TON стандартной библиотеки стартует с нуля - это осознанный компромисс.
Другой паттерн - счётчик наработки в GVL RETAIN, а FB только инкрементирует разрешённый импульс. Тогда FBD-лист не меняют, retain виден в одной GVL для аудита ТО.
При ревью проекта ищите FB с iStep без RETAIN на листах последовательностей пуска - типичный техдолг перед первым плановым ТО.
Связь с загрузкой проекта
Если после download FB «как после рестарта», хотя питание не снимали - см. загрузку CODESYS и retain: cold download с инициализацией стирает то же, что и кнопка reset. Отладка экземпляра в online - отладка ПЛК.
Что теряется, причина, настройка
| Что теряется после перезапуска | Причина | Настройка / действие |
|---|---|---|
| Счётчик циклов, наработка часов | Нет RETAIN у переменной | `VAR RETAIN` или PERSISTENT; backup в HMI архив |
| Уставка PID, рецепт | Только в VAR без retain; Init в first scan | RETAIN; убрать перезапись в Init |
| Шаг автомата в FB | `iStep` не retain | RETAIN на шаг; или безопасный сброс механики при старте |
| Остаток таймера TON | Внутренность стандартного TON | Свой FB с retain на `ET`/`остаток`; или принять сброс |
| Выход «клапан открыт» | Выход не retain (часто правильно) | Safe state в init; межблокировка; не retain без расчёта |
| Всё retain разом | Села батарея; долгое обесточивание | Замена батареи; PERSISTENT; журнал уставок |
| Мусор в retain после обновления | Изменена структура RETAIN | Миграция; один cold с документированным сбросом |
| После download «как будто рестарт» | Cold download с инициализацией | Тип загрузки; не сбрасывать retain в диалоге |
| На стенде помнит, на объекте нет | Стенд не отключали; на объекте рвут 24 В | Тест с отключением питания 30 мин |
| HMI показывает старое, ПЛК ноль | Уставка retain только на экране | Единый источник в ПЛК retain |
Проектирование: что не надо retain
Выходы на исполнительные механизмы без подтверждения положения после рестарта не должны «просыпаться» в последнем состоянии по умолчанию - смотрите функциональную безопасность и FAT. Retain на DO_Open без датчика конечника - риск.
Тренды и архив - не retain в ПЛК, а SCADA/HMI.
Тестовые флаги bSimulate - лучше без retain, чтобы после рестарта симуляция не осталась включённой.
Проверка на стенде перед объектом
Сценарий: установить ненулевые уставки и счётчики, записать значения, cold restart ПЛК. Сверить retain-список. Отключить 24 В на 10 минут с батареей и без (если допустимо). Загрузить проект cold с сохранением retain и без - задокументировать разницу.
На FBD в online открыть экземпляр FB, смотреть внутренние RETAIN-поля, не только выходы на листе.
PID и накопители в FB: типичные жертвы cold start
Интегральная составляющая PID в VAR без retain после рестарта с нуля - клапан долго «ползёт» к уставке. Это ожидаемо; если нужно помнить интеграл через краткий рестарт - отдельное решение по регламенту (обычно не retain, а сброс и ручной режим).
Накопленная энергия, сменный счёт брака в FB упаковки - кандидаты в RETAIN/PERSISTENT. Согласуйте с технологом: после рестарта линия продолжает учёт или начинает смену заново.
Несколько экземпляров одного FB на проекте
Cross-reference по имени экземпляра: два вызова SeqLine1 и SeqLine1_Copy с одним именем экземпляра - состояние перетирается. После рестарта «сбросился» тот, кто последний вызвался в цикле. Имена экземпляров уникальны на объект; retain не лечит двойной вызов.
При копировании FBD-листа с другой линии проверьте, что создали новый экземпляр, а не ссылку на чужой.
Журнал и паспорт retain для ТО
В паспорте объекта перечислите FB и GVL с RETAIN/PERSISTENT: наработка насосов, номер рецепта, счётчик продукции. При ТО сверяют фактические значения с журналом смены. Если после плановой замены батареи счётчик обнулился - запись в журнал, не «тихо продолжили».
Для FAT новой линии сценарий: установить тестовые значения retain, cold restart, убедиться в восстановлении, затем симулировать севшую батарею (по процедуре производителя) и зафиксировать ожидаемое поведение для эксплуатации.
Вопросы при работе
Можно ли сделать retain всего экземпляра FB одной галочкой?
Зависит от среды; чаще retain помечают по переменным. «Весь FB retain» без анализа - риск для выходов.
Почему RETAIN есть, а после прошивки ноль?
Прошивка могла очистить область; нужен PERSISTENT или восстановление из backup.
FBD или ST - где retain надёжнее?
Одинаково; важно объявление, не язык листа.
Online Change сбрасывает FB?
Обычно нет, если не меняли структуру экземпляра; при изменении интерфейса FB - может потребоваться полная загрузка и рестарт.
Можно ли вынести все retain FB в отдельную GVL?
Да, для аудита и backup: FB работает с IN_OUT или ссылкой на GVL RETAIN. Удобно при миграции проекта и при FAT-чек-листе.
Сбрасывается ли состояние при watchdog?
Зависит от платформы: watchdog restart часто эквивалентен warm/cold reset. Уточните в документации ПЛК для объекта.
На практике
В проектах на ПЛК СТАБУР под CODESYS 3.5 retain и cold start ведут себя как на типовых контроллерах IEC 61131-3: перед пуском линии имеет смысл вынести в паспорт перечень retain-переменных критичных FB (наработка, рецепт) и проверить батарею в корзине контроллера.
Обсуждение