🧠 Odot Automation: Retain и Persistent Retain
✅ Корректная работа с энергонезависимой памятью в процессорах C3351, C4374, B2341.
📘 Инструкция для программистов CODESYS 3.5 SP19 (по материалам официальной техподдержки Odot).
📘 Инструкция для программистов CODESYS 3.5 SP19 (по материалам официальной техподдержки Odot).
Retain vs Persistent
два уровня сохранения| Характеристика | RETAIN | PERSISTENT RETAIN |
|---|---|---|
| Отключение питания | ✅ сохраняется | ✅ сохраняется |
| Тёплый перезапуск (Online Reset) | ✅ сохраняется | ✅ сохраняется |
| Холодный перезапуск (Cold Start) | ❌ сбрасывается | ✅ сохраняется |
| Сброс исходного состояния (Reset Origin) | ❌ сбрасывается | ❌ сбрасывается |
| Требуется настройка пути | нет | да (PersistentVars / атрибут persistent) |
❗ Важное уточнение: PERSISTENT RETAIN не работает без явного указания экземплярного пути (instance path) в редакторе PersistentVars или через атрибут
{attribute 'persistent' := '"/путь/к/файлу.dat"'}. Без этого шага переменная ведёт себя как обычный RETAIN.
🔧 Порядок действий для PERSISTENT
проверено на C3351/C4374/B2341- 1. Объявите переменную в глобальном списке или
VAR GLOBAL PERSISTENT RETAIN. - 2. Создайте объект PersistentVars в дереве проекта (Application → Добавить объект → Power‑Down Hold Variable).
- 3. Добавьте экземплярный путь – в открывшемся редакторе правой кнопкой → Add Instantiation Path и выберите вашу переменную.
- 4. Альтернативный способ – использовать атрибут прямо в коде (работает в т.ч. для локальных PERSISTENT):
{attribute 'persistent' := '"/usr/persistent_data.dat"'}
VAR PERSISTENT RETAIN
nCounter : WORD := 0;
END_VAR
VAR PERSISTENT RETAIN
nCounter : WORD := 0;
END_VAR
📁 Путь может быть любым доступным для записи местом в файловой системе контроллера (обычно /usr/).
📋 Готовый пример
Retain и Persistent счётчики
// -------- Global Variables --------
VAR_GLOBAL RETAIN
g_nRetainCounter : WORD := 0;
END_VAR
{attribute 'persistent' := '"/usr/persistent_counter.dat"'}
VAR_GLOBAL PERSISTENT RETAIN
g_nPersistCounter : WORD := 0;
END_VAR
// -------- MAIN --------
VAR
t100ms : TON;
bFirst : BOOL := TRUE;
END_VAR
IF bFirst THEN
bFirst := FALSE;
g_nRetainCounter := g_nRetainCounter + 1;
g_nPersistCounter := g_nPersistCounter + 1;
END_IF
t100ms(IN := NOT t100ms.Q, PT := T#100MS);
IF t100ms.Q THEN
g_nRetainCounter := g_nRetainCounter + 1;
g_nPersistCounter := g_nPersistCounter + 1;
END_IF
%QW0 := g_nRetainCounter;
%QW1 := g_nPersistCounter;
VAR_GLOBAL RETAIN
g_nRetainCounter : WORD := 0;
END_VAR
{attribute 'persistent' := '"/usr/persistent_counter.dat"'}
VAR_GLOBAL PERSISTENT RETAIN
g_nPersistCounter : WORD := 0;
END_VAR
// -------- MAIN --------
VAR
t100ms : TON;
bFirst : BOOL := TRUE;
END_VAR
IF bFirst THEN
bFirst := FALSE;
g_nRetainCounter := g_nRetainCounter + 1;
g_nPersistCounter := g_nPersistCounter + 1;
END_IF
t100ms(IN := NOT t100ms.Q, PT := T#100MS);
IF t100ms.Q THEN
g_nRetainCounter := g_nRetainCounter + 1;
g_nPersistCounter := g_nPersistCounter + 1;
END_IF
%QW0 := g_nRetainCounter;
%QW1 := g_nPersistCounter;
✔️ После компиляции и Create Boot Application значения PERSISTENT будут сохраняться даже при холодном старте.
🧪 Валидация: Данный метод протестирован на контроллерах C3351, C4374, B2341 (с батареей и без). RETAIN работает при наличии батареи, PERSISTENT – всегда, при корректно назначенном пути.
🙏 Благодарность пользователю Вадим П. за постановку задачи и инженеру техподдержки Odot Automation Damant за оперативное предоставление разъяснений нюансов настройки Persistent‑переменных.
Остались вопросы?
📍 Национальный склад в Новосибирске
отгрузка за 1 день
отгрузка за 1 день