带参数的用户定义函数
User defined functions with params
在 codesys 中,一些函数支持其他语言中通常称为 'params' 的函数,即可以采用不同数量的类似类型变量的函数。例如 ADD 运算符(梯形图中的函数)。
我的问题是,是否有任何方法可以在用户定义的函数中执行相同的操作?
到目前为止我唯一的想法是采用 ARRAY [*] OF SOMETHING
并使用 LOWER_BOUND
和 UPPER_BOUND
进行计算。这确实有效,但要求用户每次要调用我的函数时都创建一个额外的数组变量。例如,我们有连接 2 个字符串的 CONCAT
函数。假设我想要一个 CONCAT_ALL
函数,它接受 n 个字符串并将它们全部连接起来:
STRS: ARRAY [0..9] OF STRING := [STR1, STR2, STR3, STR4, STR5, STR6, STR7, STR8, STR9, STR10];
// This works, but I want to avoid creating an array variable!
CONALL1: STRING := CONCAT_ALL(STRINGS := STRS);
// This doesn't work!
CONALL2: STRING := CONCAT_ALL(STRINGS := [STR1, STR2, STR3, STR4, STR5, STR6, STR7, STR8, STR9, STR10]);
(编辑:如我所问,我使用的是 Schneider Electric Machine Expert 1.2 或 CODESYS 编译器 3.5.12.80)
简短回答:无法将 n 个参数传递给函数。
结构化文本是一种强静态类型语言,专为硬实时要求而设计,它不像 Python 那样的脚本语言。
如果您的代码中有很多您不想在 python 中执行但在您的实时循环中执行的字符串操作(并且您应该根据您的要求评估是否真的有必要)还想做的舒服,那就得下点功夫,自己建一个字符串操作库。
之后你可以像这样进行非常舒适的函数调用:
sResult := F_Concat6(str1,str2,str3,str4,str5,str6);
我明白采用从其他编程语言学到的思想和编程模式很诱人,但与普通用户编程相比,结构化文本和实时工业控制编程确实是另一种野兽。
我的意思是,语言的设计是有特定原因的,当正确理解和应用这些原则时,坚如磐石的架构就会从中衍生出来。
总而言之,我的两点建议是:
按照您所在领域的预期思考和编写软件,不要从其他领域移植不兼容的工作方法。
不可以将 n 个参数传递给函数。
但是你可以传递一个数组,其中 none 个元素是固定的。 Codesys 2.3 的语法。
FUNCTION CONCAT_ALL : STRING(250)
VAR_INPUT
asParts: POINTER TO ARRAY[0..10000] OF STRING(20); (* Array of strings *)
iNum: INT; (* Number of elements *)
END_VAR
VAR
iCount: INT; (* For cycle *)
END_VAR
FOR iCount := 0 TO 10000 DO
IF iCount > iNum THEN
EXIT;
END_IF;
CONCAT_ALL := CONCAT(CONCAT_ALL, asParts^[iCount]);
END_FOR;
END_FUNCTION
PROGRAM PLC_PRG
VAR
(* Array 1 to test *)
asTest1: ARRAY[1..2] OF STRING(20) := 'String 1', 'String 2';
(* Array 2 to test *)
asTest2: ARRAY[1..3] OF STRING(20) := 'String 1', 'String 2', 'String 3';
s1: STRING(250);
s2: STRING(250);
END_VAR
s1 := CONCAT_ALL(ADR(asTest1), 2);
s1 := CONCAT_ALL(ADR(asTest2), 3);
END_PROGRAM
这是字符串连接器功能块的面向对象示例:
首先我们定义一个有两个方法的接口:
INTERFACE I_MultipleConcat
METHOD concatString : I_MultipleConcat
VAR_INPUT
sTarget : STRING;
END_VAR
METHOD getResult
VAR_IN_OUT
sRetrieveResult : STRING(1000);
END_VAR
然后是实现接口的功能块:
FUNCTION_BLOCK FB_MultipleConcat IMPLEMENTS I_MultipleConcat
VAR_OUTPUT
uiLen : UINT;
END_VAR
VAR
sResult : STRING(1000);
END_VAR
//-------------------------------------------------------------------
METHOD concatString : I_MultipleConcat
VAR_INPUT
sTarget : STRING;
END_VAR
//make sure that the length of sResult is not exceeded
IF uiLen + INT_TO_UINT(LEN(sTarget)) <= (SIZEOF(sResult)-1)
THEN
//add uiLen as offset to sResult memory access
memcpy(ADR(sResult) + uiLen,ADR(sTarget),LEN(sTarget));
uiLen := uiLen + INT_TO_UINT(LEN(sTarget));
END_IF
//return the instance of this FuncBlock in order to concat new strings
//with concatString() or pass the result to another STRING with getResult()
concatString := THIS^;
//-------------------------------------------------------------------
METHOD getResult
VAR_IN_OUT
sRetrieveResult : STRING(1000);
END_VAR
sRetrieveResult := sResult;
sResult := '';
uiLen := 0;
你可以这样称呼它:
IF NOT bInit
THEN
bInit := TRUE;
//s1 must be a STRING(1000) otherwise compile error
fbMultipleConcat
.concatString('Test1 ')
.concatString('Test2 ')
.concatString('Test3 ')
.getResult(s1);
END_IF
未来有希望!
在 Codesys V3.5 SP16 中,似乎终于可以使用带有可选参数的 FUNCTION 和 METHOD。当然这会出现在非codesys的产品中,比如TwinCAT和Schneider,在以后的版本中。
这意味着您终于可以创建一个包含 100 个参数的 CONCAT 并仅使用例如 3 个参数调用它!厉害了。
https://www.codesys.com/fileadmin/data/Images/Download/features-and-improvements-V35SP16-en.pdf
在 codesys 中,一些函数支持其他语言中通常称为 'params' 的函数,即可以采用不同数量的类似类型变量的函数。例如 ADD 运算符(梯形图中的函数)。
我的问题是,是否有任何方法可以在用户定义的函数中执行相同的操作?
到目前为止我唯一的想法是采用 ARRAY [*] OF SOMETHING
并使用 LOWER_BOUND
和 UPPER_BOUND
进行计算。这确实有效,但要求用户每次要调用我的函数时都创建一个额外的数组变量。例如,我们有连接 2 个字符串的 CONCAT
函数。假设我想要一个 CONCAT_ALL
函数,它接受 n 个字符串并将它们全部连接起来:
STRS: ARRAY [0..9] OF STRING := [STR1, STR2, STR3, STR4, STR5, STR6, STR7, STR8, STR9, STR10];
// This works, but I want to avoid creating an array variable!
CONALL1: STRING := CONCAT_ALL(STRINGS := STRS);
// This doesn't work!
CONALL2: STRING := CONCAT_ALL(STRINGS := [STR1, STR2, STR3, STR4, STR5, STR6, STR7, STR8, STR9, STR10]);
(编辑:如我所问,我使用的是 Schneider Electric Machine Expert 1.2 或 CODESYS 编译器 3.5.12.80)
简短回答:无法将 n 个参数传递给函数。
结构化文本是一种强静态类型语言,专为硬实时要求而设计,它不像 Python 那样的脚本语言。
如果您的代码中有很多您不想在 python 中执行但在您的实时循环中执行的字符串操作(并且您应该根据您的要求评估是否真的有必要)还想做的舒服,那就得下点功夫,自己建一个字符串操作库。
之后你可以像这样进行非常舒适的函数调用:
sResult := F_Concat6(str1,str2,str3,str4,str5,str6);
我明白采用从其他编程语言学到的思想和编程模式很诱人,但与普通用户编程相比,结构化文本和实时工业控制编程确实是另一种野兽。
我的意思是,语言的设计是有特定原因的,当正确理解和应用这些原则时,坚如磐石的架构就会从中衍生出来。
总而言之,我的两点建议是:
按照您所在领域的预期思考和编写软件,不要从其他领域移植不兼容的工作方法。
不可以将 n 个参数传递给函数。
但是你可以传递一个数组,其中 none 个元素是固定的。 Codesys 2.3 的语法。
FUNCTION CONCAT_ALL : STRING(250)
VAR_INPUT
asParts: POINTER TO ARRAY[0..10000] OF STRING(20); (* Array of strings *)
iNum: INT; (* Number of elements *)
END_VAR
VAR
iCount: INT; (* For cycle *)
END_VAR
FOR iCount := 0 TO 10000 DO
IF iCount > iNum THEN
EXIT;
END_IF;
CONCAT_ALL := CONCAT(CONCAT_ALL, asParts^[iCount]);
END_FOR;
END_FUNCTION
PROGRAM PLC_PRG
VAR
(* Array 1 to test *)
asTest1: ARRAY[1..2] OF STRING(20) := 'String 1', 'String 2';
(* Array 2 to test *)
asTest2: ARRAY[1..3] OF STRING(20) := 'String 1', 'String 2', 'String 3';
s1: STRING(250);
s2: STRING(250);
END_VAR
s1 := CONCAT_ALL(ADR(asTest1), 2);
s1 := CONCAT_ALL(ADR(asTest2), 3);
END_PROGRAM
这是字符串连接器功能块的面向对象示例:
首先我们定义一个有两个方法的接口:
INTERFACE I_MultipleConcat
METHOD concatString : I_MultipleConcat
VAR_INPUT
sTarget : STRING;
END_VAR
METHOD getResult
VAR_IN_OUT
sRetrieveResult : STRING(1000);
END_VAR
然后是实现接口的功能块:
FUNCTION_BLOCK FB_MultipleConcat IMPLEMENTS I_MultipleConcat
VAR_OUTPUT
uiLen : UINT;
END_VAR
VAR
sResult : STRING(1000);
END_VAR
//-------------------------------------------------------------------
METHOD concatString : I_MultipleConcat
VAR_INPUT
sTarget : STRING;
END_VAR
//make sure that the length of sResult is not exceeded
IF uiLen + INT_TO_UINT(LEN(sTarget)) <= (SIZEOF(sResult)-1)
THEN
//add uiLen as offset to sResult memory access
memcpy(ADR(sResult) + uiLen,ADR(sTarget),LEN(sTarget));
uiLen := uiLen + INT_TO_UINT(LEN(sTarget));
END_IF
//return the instance of this FuncBlock in order to concat new strings
//with concatString() or pass the result to another STRING with getResult()
concatString := THIS^;
//-------------------------------------------------------------------
METHOD getResult
VAR_IN_OUT
sRetrieveResult : STRING(1000);
END_VAR
sRetrieveResult := sResult;
sResult := '';
uiLen := 0;
你可以这样称呼它:
IF NOT bInit
THEN
bInit := TRUE;
//s1 must be a STRING(1000) otherwise compile error
fbMultipleConcat
.concatString('Test1 ')
.concatString('Test2 ')
.concatString('Test3 ')
.getResult(s1);
END_IF
未来有希望!
在 Codesys V3.5 SP16 中,似乎终于可以使用带有可选参数的 FUNCTION 和 METHOD。当然这会出现在非codesys的产品中,比如TwinCAT和Schneider,在以后的版本中。
这意味着您终于可以创建一个包含 100 个参数的 CONCAT 并仅使用例如 3 个参数调用它!厉害了。
https://www.codesys.com/fileadmin/data/Images/Download/features-and-improvements-V35SP16-en.pdf