(Решение моей проблемы я нашел на сайте запись в блоге Стефана Хеннекена о T_Arg.)
Цель может быть достигнута, но не особенно чисто. Есть два общих типа (которые я пока нашел), которые применимы: ANY_NUM
и T_Arg
.
(Я использую ANY_NUM
, потому что это наиболее подходит для этого примера. ANY
, ANY_REAL
или ANY_INT
также были бы разумными вариантами)
Оба варианта имеют схожую структуру и работают одинаково. Каждая из них представляет собой структуру, содержащую информацию о хранимой переменной: ее тип, указатель на нее и ее размер.
Тем не менее, есть плюсы и минусы для каждого. Для наиболее точного решения этой задачи мы будем использовать T_Arg
.
Вот разница:
ЛЮБОЙ / ANY_NUM / ETC
Преимущество: преобразование переменной в ANY_NUM
выполняется неявно, когда присваивается переменная. Входная переменная не требует предварительного преобразования перед вводом в функцию, что сокращает размер кода.
Кроме того, он принимает только переменные, принадлежащие его домену, поэтому строки не будут использоваться случайно.
Недостаток: ANY_NUM
нельзя объявить за пределами блока VAR_INPUT
, и фактически выдает это сообщение об ошибке при попытке:
Variables of type 'ANY_NUM' only allowed as input of functions.
Поэтому ANY_NUM
нельзя использовать в качестве переменной STRUCT
, даже если эта STRUCT
объявлена как входная функция. Вот почему он не может быть использован для решения этой конкретной проблемы.
T_Arg
Преимущество: T_Arg
можно объявить и использовать где угодно.
Недостаток: T_Arg
требуются функции преобразования для любого ожидаемого типа переменной, например: F_INT()
,F_REAL()
,F_DINT()
и т. д.
Поэтому проверку типов необходимо выполнять до и после ввода.
Пример решения
К сожалению, переменная, хранящаяся в T_Arg
, не может быть изменена напрямую. Чтобы использовать сохраненную переменную, необходимо переместить ее во временную переменную. Таким образом, Value
, Min_
и Max_
потребуется преобразование из типа T_Arg
в тип REAL
/INT
/и т. д.
Поскольку мы пытаемся использовать только один STRUCT
, Value
нужно будет снова преобразовать в T_Arg, как только Bind_Value
закончит манипулировать им.
В общей сложности Value
будет преобразовано три раза при создании экземпляра и дважды за каждый последующий вызов.
Структура:
TYPE Bounded_Value:
STRUCT
Value : T_Arg;
Min_ : T_Arg;
Max_ : T_Arg;
END_STRUCT
END_TYPE
Функциональный блок:
FUNCTION_BLOCK Bind_Value
VAR_IN_OUT
value_struct: Bounded_Value;
// Other variable type declarations
END_VAR
VAR
val_int : INT;
max_int : INT;
min_int : INT;
END_VAR
CASE (value_struct.Value.eType) OF
E_ArgType.ARGTYPE_INT: // If the struct's Value's type is INT
// Copy generic pointer information into typed pointer
MEMCPY(ADR(val_int), value_struct.Value.pData, value_struct.Value.cbLen);
MEMCPY(ADR(max_int), value_struct.Max_.pData, value_struct.Max_.cbLen);
MEMCPY(ADR(min_int), value_struct.Min_.pData, value_struct.Min_.cbLen);
IF val_int > max_int THEN
value_struct.Value.pData := value_struct.Max_.pData;
ELSIF val_int < min_int THEN
value_struct.Value.pData := value_struct.Min_.pData;
END_IF
// Other variable type handlings
END_CASE
ГЛАВНОЕ:
PROGRAM MAIN
VAR
val : INT := -1; //Change this to test
minim : INT := 0;
maxim : INT := 5;
newVal : INT;
bv : Bounded_Value;
bind : Bind_Value;
END_VAR
// Convert INT variables to T_Arg in structure
bv.Value:= F_INT(val);
bv.Max_ := F_INT(maxim);
bv.Min_ := F_INT(minim);
// Bind_Value.value_struct := bv;
bind(value_struct := bv);
// Copy result to newVal
MEMCPY(ADR(newVal), bv.Value.pData, bv.Value.cbLen);
person
Graeme Rock
schedule
30.04.2018
REAL
иLREAL
не являютсяANY_NUM
. Те должны быть преобразованы. С точки зрения математики, какой мы ее знаем, мы считаем ее числом, но с точки зрения типов данныхINT
иREAL
— это разные типы. - person Sergey Romanov   schedule 29.04.2018