Предотвратить сохранение локальных переменных

Предположим, у меня есть функциональный блок POU1, который имеет локальные переменные val1: INT и val2: INT, например.

FUNCTION_BLOCK POU1
VAR
    val1: INT := 1;
    val2: INT := 1;
END_VAR

Теперь предположим, что пользователь FB объявляет его как RETAIN, например.

VAR RETAIN
    p1: POU1;
END_VAR
p1.val1 := 2;
p1.val2 := 2;

Это приведет к тому, что и val1, и val2 сохранят значение 2 в случае теплого сброса, но что, если я не хочу, чтобы это произошло, чтобы сказать val2, то есть я хочу, чтобы val1 сохранил свое текущее значение, но val2 был сброшен в случай теплого сброса (если пользователь объявляет мой FB как RETAIN, иначе я хочу, чтобы оба сбрасывались)

Как я могу этого добиться? (Также тот же вопрос касается PERSISTENT)

PS. Я пробовал {attribute 'init_on_onlchange'} и {attribute 'no_copy'}, но они ничего не дали (может быть, я их неправильно использовал?). Я также попытался создать дополнительный FB с {attribute 'no_instance_in_retain'} и добавить его как локальную переменную POU1, но это привело к ошибке сборки.


person Guiorgy    schedule 23.07.2020    source источник
comment
ты пробовал VAR_TEMP?   -  person Sergey Romanov    schedule 27.07.2020
comment
@SergeyRomanov, извините, но, хотя VAR_TEMP не будет сохраняться между теплыми сбросами, он также не будет сохраняться между обычными вызовами. VAR_TEMP по определению сбрасывается при каждом вызове функционального блока. Мне нужна обычная локальная переменная (которая сохраняет свое значение между вызовами функционального блока), которая сбрасывается после теплого сброса, даже если пользователь FB объявил ее как RETAIN или PERSISTENT   -  person Guiorgy    schedule 28.07.2020


Ответы (2)


Один из способов, который я только что нашел, - это явно реализовать FB_Exit и сбросить в нем эти переменные:

METHOD FB_Exit: BOOL
VAR_INPUT
    bInCopyCode: BOOL;  // TRUE: the exit method is called in order to leave the instance which will be copied afterwards (online change).  
END_VAR
val2 := 1; // reset all variables you don't want retained to their defaults

Кажется, это работает, но не уверен, что это может иметь другие последствия. например Вызывается ли FB_Exit в случае сбоя питания?

person Guiorgy    schedule 23.07.2020

Проблема с FB_Exit или FB_Init и VAR PERSISTENT/RETAIN заключается в том, что я не смог найти согласованное поведение на разных платформах (Twincat/Codesys). И да, есть случаи, когда fb_exit не вызывается, например, в Twincat при холодном сбросе.

Мой подход к этому был бы другим. Я бы не стал использовать ни атрибуты, ни fb_exit, ни fb_init, которые при определенных обстоятельствах могут быть трудны для отладки. Вместо этого я бы использовал простой глобальный FB, подобный этому:

FUNCTION_BLOCK FB_System

VAR
    bInit : BOOL;
    nCycleCount : UINT;
END_VAR

VAR CONSTANT
    cINIT_AFTER_CYCLE : UINT := 2;
END_VAR


IF NOT bInit 
THEN
    nCycleCount := nCycleCount + 1;
END_IF

IF nCycleCount >= cINIT_AFTER_CYCLE
THEN
    bInit := TRUE;
END_IF

METHOD isInit : BOOL

isInit := bInit;

Теперь добавьте ввод в ваш сохраняемый/постоянный FB:

VAR_INPUT
    bSystemInit : BOOL;
END_VAR 

И назовите это так:

fbRetain(bSystemInit := fbSystem.isInit());

Инициализируйте свои значения, если система не инициализирована. Добавьте эту проверку в свою реализацию FB:

IF NOT bSystemInit THEN
    anIntVar := 0;
    //or call a reset() method where you put all your variables that need to be initialized
END_IF 

Если у вас есть много FB, которые нуждаются в такой инициализации, вы можете расширить их с помощью FB, в котором есть этот пример кода. Таким образом, вы можете эффективно повторно использовать свой код.

Сказав это, я должен предупредить вас, что в прошлом у меня было много проблем с постоянными данными. Со мной неоднократно случалось, что постоянные данные повреждались, вызывая проблемы с производством или даже препятствуя запуску среды выполнения.

Если бы мне пришлось проектировать систему с нуля, я бы использовал XML-сервер от Beckhoff или XML-утилиту от codesys для хранения соответствующих производственных данных в xml-файле и извлечения этих данных при запуске во время выполнения.

person Filippo Boido    schedule 23.07.2020
comment
Я предполагаю, что вы объявляете экземпляр FB_System в программе в верхней части основной задачи? И вы называете это в конце основной задачи? Также есть ли способ добиться этого без явного создания экземпляра в программе, например, с использованием глобальных переменных и функции с атрибутом 'call_after_global_init_slot' или подобным (например, если вам это нужно в библиотеке, без задач)? - person Guiorgy; 24.07.2020
comment
FB_System объявляется в списке глобальных переменных и вызывается в любом месте (не обязательно в конце основной задачи). Поскольку значение bInit для fbSystem доступно только для чтения, можно поместить этот FB в список глобальных переменных. - person Filippo Boido; 24.07.2020
comment
Что касается второй части вашего вопроса, FB_System должен работать циклически, потому что FB циклически проверяет, закончилась ли фаза инициализации. Вы решаете, сколько циклов длится эта фаза, благодаря константе cINIT_AFTER_CYCLE. - person Filippo Boido; 24.07.2020
comment
Код, находящийся в библиотеках, также запускается в задаче или не запускается вообще. - person Filippo Boido; 24.07.2020
comment
Я бы не стал использовать это свойство, потому что его сложно отлаживать тому, кто не знает ваш код. - person Filippo Boido; 24.07.2020
comment
Код, находящийся в библиотеках, также запускается в задаче или не запускается вообще, в этом и суть. Из того, что я вижу, пользователю пришлось бы явно запускать FB_System ровно один раз в каждом цикле. Если их нет, то логика работать не будет. Я бы не стал использовать это свойство, потому что его сложно отлаживать тому, кто не знает ваш код. хорошо, и в вашем случае тот, кто не знает, как вызвать FB_System, будет сбит с толку, почему это не работает, не так ли? - person Guiorgy; 25.07.2020
comment
При программировании ПЛК вы ожидаете, что код будет выполняться циклически. Вы можете легко разобраться, когда код структурирован и вызовы видны всем. Есть много других возможностей решить проблему, которая у вас есть в коде. Это также зависит от вашей архитектуры. Однако пример, показанный выше, является очень простой и простой реализацией. - person Filippo Boido; 25.07.2020