发布于 2025-01-21 23:37:56 字数 1876 浏览 0 评论 0 原文

我正在尝试构建一个函数,该函数总和twincat中任何类型的单个维数阵列。

我对指针的经验不足,所以答案可能很明显,但是我找不到任何解决方案。我阅读了所有这些,它们有所帮助。

The Wonders of ANY

My conceptual code works for an INT数组,但我意识到我必须为每个数据类型编写一个循环以使其正常工作,这似乎是错误的。 我还想避免在循环中遇到一个案例,因为这似乎效率低下。

是否可以将指针(未设置类型)指向(特定类型的指针)?在C中看起来可以,但不确定IEC-61131。

FUNCTION fn_SumArray : DINT
VAR_INPUT 
    inArr : ANY; 
    inElem : ANY;
    
END_VAR

VAR
    i : DINT := 0;
    stepsize : DINT :=1;

    pLREAL : POINTER TO LREAL; //64 bit
    pREAL : POINTER TO REAL; //32 bit
    pBYTE : POINTER TO BYTE; //8 bit
    pWORD : POINTER TO WORD; //16 bit
    pDWORD : POINTER TO DWORD; //32 bit
    pLWORD : POINTER TO LWORD; //64 bit
    pSINT : POINTER TO SINT; //8 bit
    pUSINT : POINTER TO USINT; //8 bit
    pINT : POINTER TO INT; //16 bit
    pUINT : POINTER TO UINT; //16 bit
    pDINT : POINTER TO DINT; //32 bit
    pUDINT : POINTER TO UDINT; //32 bit
    pLINT : POINTER TO LINT; //64 bit
    pULINT : POINTER TO ULINT; //64 bit
END_VAR

--------------------------------------------------
CASE inElem.TypeClass OF
    __SYSTEM.TYPE_CLASS.TYPE_LREAL:    
        stepsize := 8;
        //set generic pointer here
    __SYSTEM.TYPE_CLASS.TYPE_INT:
        stepsize := 2;    
        //set generic pointer here
ELSE
    fn_SumArray :=0;
END_CASE;


    FOR i := 0 TO inArr.diSize-1 BY stepsize DO
            genericPointer:= ADR(inarr.pValue[i]);
            fn_SumArray := fn_SumArray +genericPointer^;
        END_FOR;

 

I'm trying to build a function that sums a single dimension array of any type in TwinCAT.

I'm relatively inexperienced with pointers so the answer may be obvious, but I could not find any solutions. I read through all these and they helped a bit.

T_ARG
Convert Byte arrays
The Wonders of ANY

My conceptual code works for an INT array, but I realized I would have to write a FOR loop for each datatype to make it work and that seems wrong.
I also wanted to avoid having a CASE in a FOR loop as that seemed inefficient.

Is it possible to have a pointer (of unset type) to a pointer (of a specific type)? It looks possible in C, but not sure about IEC-61131.

FUNCTION fn_SumArray : DINT
VAR_INPUT 
    inArr : ANY; 
    inElem : ANY;
    
END_VAR

VAR
    i : DINT := 0;
    stepsize : DINT :=1;

    pLREAL : POINTER TO LREAL; //64 bit
    pREAL : POINTER TO REAL; //32 bit
    pBYTE : POINTER TO BYTE; //8 bit
    pWORD : POINTER TO WORD; //16 bit
    pDWORD : POINTER TO DWORD; //32 bit
    pLWORD : POINTER TO LWORD; //64 bit
    pSINT : POINTER TO SINT; //8 bit
    pUSINT : POINTER TO USINT; //8 bit
    pINT : POINTER TO INT; //16 bit
    pUINT : POINTER TO UINT; //16 bit
    pDINT : POINTER TO DINT; //32 bit
    pUDINT : POINTER TO UDINT; //32 bit
    pLINT : POINTER TO LINT; //64 bit
    pULINT : POINTER TO ULINT; //64 bit
END_VAR

--------------------------------------------------
CASE inElem.TypeClass OF
    __SYSTEM.TYPE_CLASS.TYPE_LREAL:    
        stepsize := 8;
        //set generic pointer here
    __SYSTEM.TYPE_CLASS.TYPE_INT:
        stepsize := 2;    
        //set generic pointer here
ELSE
    fn_SumArray :=0;
END_CASE;


    FOR i := 0 TO inArr.diSize-1 BY stepsize DO
            genericPointer:= ADR(inarr.pValue[i]);
            fn_SumArray := fn_SumArray +genericPointer^;
        END_FOR;

 

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

ゝ杯具 2025-01-28 23:37:56

据我所知,您必须重复要涵盖的所有类型的代码。 codesys没有 true 通用编程,因此是:

(* DECLARATION *)
METHOD fn_SumArray : BOOL // if TRUE, then error
VAR_INPUT 
    arr_first : ANY_NUM;
    arr_size : DINT;
    sum_out : ANY_NUM;
END_VAR
VAR
    i : DINT;
    ptr_arr: NUMBER_POINTER; // just a UNION with all number type pointers
    ptr_sum: NUMBER_POINTER;
END_VAR

(* IMPLEMENTATION *)
IF (arr_first.TypeClass <> sum_out.TypeClass) THEN
    fn_SumArray := TRUE;
    // set all bytes of sum_out to 0
    FOR i := 0 TO sum_out.diSize - 1 DO
        sum_out.pValue[i] := 0;
    END_FOR
    RETURN;
END_IF

CASE arr_first.TypeClass OF
    __SYSTEM.TYPE_CLASS.TYPE_LREAL:
        ptr_arr._LREAL := arr_first.pValue;
        ptr_sum._LREAL := sum_out.pValue;
        ptr_sum._LREAL^ := 0;
        FOR i := 0 TO arr_size - 1 DO
            ptr_sum._LREAL^ := ptr_sum._LREAL^ + ptr_arr._LREAL[i];
        END_FOR
    // Repeat the above for all ...
ELSE
    fn_SumArray := TRUE;
    // set all bytes of sum_out to 0
    FOR i := 0 TO sum_out.diSize - 1 DO
        sum_out.pValue[i] := 0;
    END_FOR
END_CASE;
// A POINTER for every data type of ANY_NUM
// PS. A pointer has the exact same size for any type
TYPE NUMBER_POINTER :
UNION
    // floating
    _REAL: POINTER TO REAL;
    _LREAL: POINTER TO LREAL;
    
    // unsigned
    _USINT: POINTER TO USINT;
    _UINT: POINTER TO UINT;
    _UDINT: POINTER TO UDINT;
    _ULINT: POINTER TO ULINT;
    
    // signed
    _SINT: POINTER TO SINT;
    _INT: POINTER TO INT;
    _DINT: POINTER TO DINT;
    _LINT: POINTER TO LINT;
END_UNION
END_TYPE
(* DECLARATION *)
PROGRAM PLC_PRG
VAR CONSTANT
    SIZE: DINT := 50;
END_VAR
VAR
    i: DINT;
    arr_int: ARRAY [0..(SIZE - 1)] OF INT;
    sum_int: INT;
    arr_dint: ARRAY [0..(SIZE - 1)] OF DINT;
    sum_dint: DINT;
    arr_real: ARRAY [0..(SIZE - 1)] OF REAL;
    sum_real: REAL;
    first_run: BOOL := TRUE;
    sum_test: REAL;
    test_failed: BOOL;
END_VAR

(* IMPLEMENTATION *)
IF (first_run) THEN
    first_run := FALSE;
    FOR i := 0 TO SIZE - 1 DO
        arr_int[i] := DINT_TO_INT(i);
        arr_dint[i] := i * 10;
        arr_real[i] := DINT_TO_REAL(i) / 10;
    END_FOR
END_IF

fn_SumArray(arr_first := arr_int[0], arr_size := SIZE, sum_out := sum_int);
sum_test := 0;
FOR i := 0 TO SIZE - 1 DO
    sum_test := sum_test + arr_int[i];
END_FOR
IF (sum_int <> REAL_TO_INT(sum_test)) THEN
    test_failed := TRUE;
END_IF

fn_SumArray(arr_first := arr_dint[0], arr_size := SIZE, sum_out := sum_dint);
sum_test := 0;
FOR i := 0 TO SIZE - 1 DO
    sum_test := sum_test + DINT_TO_REAL(arr_dint[i]);
END_FOR
IF (sum_dint <> REAL_TO_DINT(sum_test)) THEN
    test_failed := TRUE;
END_IF

fn_SumArray(arr_first := arr_real[0], arr_size := SIZE, sum_out := sum_real);
sum_test := 0;
FOR i := 0 TO SIZE - 1 DO
    sum_test := sum_test + arr_real[i];
END_FOR
IF (sum_real <> sum_test) THEN
    test_failed := TRUE;
END_IF

rel:

“

如果为每种类型编写相同的代码可以始终使用脚本来自动化这一点:

#!/usr/bin/env python3

code_template = \
"""CASE arr_first.TypeClass OF
{0}
ELSE
\tfn_SumArray := TRUE;
\tFOR i := 0 TO sum_out.diSize - 1 DO
\t\tsum_out.pValue[i] := 0;
\tEND_FOR
END_CASE;
"""

case_template = \
"""\t__SYSTEM.TYPE_CLASS.TYPE{0}:
\t\tptr_arr.{0} := arr_first.pValue;
\t\tptr_sum.{0} := sum_out.pValue;
\t\tptr_sum.{0}^ := 0;
\t\tFOR i := 0 TO arr_size - 1 DO
\t\t\tptr_sum.{0}^ := ptr_sum.{0}^ + ptr_arr.{0}[i];
\t\tEND_FOR
"""

types = ['_REAL', '_LREAL', '_USINT', '_UINT', '_UDINT', '_ULINT', '_SINT', '_INT', '_DINT', '_LINT']

cases = [case_template.format(t) for t in types]
code = code_template.format(''.join(cases))

print(code)

只需使用Python 3.x运行上面的脚本,您就会获得脚本中列出的类型的案例语句代码。

As far as I know, you'll have to repeat the code for all types you want to cover. CODESYS doesn't have true generic programming, so it is what it is:

(* DECLARATION *)
METHOD fn_SumArray : BOOL // if TRUE, then error
VAR_INPUT 
    arr_first : ANY_NUM;
    arr_size : DINT;
    sum_out : ANY_NUM;
END_VAR
VAR
    i : DINT;
    ptr_arr: NUMBER_POINTER; // just a UNION with all number type pointers
    ptr_sum: NUMBER_POINTER;
END_VAR

(* IMPLEMENTATION *)
IF (arr_first.TypeClass <> sum_out.TypeClass) THEN
    fn_SumArray := TRUE;
    // set all bytes of sum_out to 0
    FOR i := 0 TO sum_out.diSize - 1 DO
        sum_out.pValue[i] := 0;
    END_FOR
    RETURN;
END_IF

CASE arr_first.TypeClass OF
    __SYSTEM.TYPE_CLASS.TYPE_LREAL:
        ptr_arr._LREAL := arr_first.pValue;
        ptr_sum._LREAL := sum_out.pValue;
        ptr_sum._LREAL^ := 0;
        FOR i := 0 TO arr_size - 1 DO
            ptr_sum._LREAL^ := ptr_sum._LREAL^ + ptr_arr._LREAL[i];
        END_FOR
    // Repeat the above for all ...
ELSE
    fn_SumArray := TRUE;
    // set all bytes of sum_out to 0
    FOR i := 0 TO sum_out.diSize - 1 DO
        sum_out.pValue[i] := 0;
    END_FOR
END_CASE;
// A POINTER for every data type of ANY_NUM
// PS. A pointer has the exact same size for any type
TYPE NUMBER_POINTER :
UNION
    // floating
    _REAL: POINTER TO REAL;
    _LREAL: POINTER TO LREAL;
    
    // unsigned
    _USINT: POINTER TO USINT;
    _UINT: POINTER TO UINT;
    _UDINT: POINTER TO UDINT;
    _ULINT: POINTER TO ULINT;
    
    // signed
    _SINT: POINTER TO SINT;
    _INT: POINTER TO INT;
    _DINT: POINTER TO DINT;
    _LINT: POINTER TO LINT;
END_UNION
END_TYPE
(* DECLARATION *)
PROGRAM PLC_PRG
VAR CONSTANT
    SIZE: DINT := 50;
END_VAR
VAR
    i: DINT;
    arr_int: ARRAY [0..(SIZE - 1)] OF INT;
    sum_int: INT;
    arr_dint: ARRAY [0..(SIZE - 1)] OF DINT;
    sum_dint: DINT;
    arr_real: ARRAY [0..(SIZE - 1)] OF REAL;
    sum_real: REAL;
    first_run: BOOL := TRUE;
    sum_test: REAL;
    test_failed: BOOL;
END_VAR

(* IMPLEMENTATION *)
IF (first_run) THEN
    first_run := FALSE;
    FOR i := 0 TO SIZE - 1 DO
        arr_int[i] := DINT_TO_INT(i);
        arr_dint[i] := i * 10;
        arr_real[i] := DINT_TO_REAL(i) / 10;
    END_FOR
END_IF

fn_SumArray(arr_first := arr_int[0], arr_size := SIZE, sum_out := sum_int);
sum_test := 0;
FOR i := 0 TO SIZE - 1 DO
    sum_test := sum_test + arr_int[i];
END_FOR
IF (sum_int <> REAL_TO_INT(sum_test)) THEN
    test_failed := TRUE;
END_IF

fn_SumArray(arr_first := arr_dint[0], arr_size := SIZE, sum_out := sum_dint);
sum_test := 0;
FOR i := 0 TO SIZE - 1 DO
    sum_test := sum_test + DINT_TO_REAL(arr_dint[i]);
END_FOR
IF (sum_dint <> REAL_TO_DINT(sum_test)) THEN
    test_failed := TRUE;
END_IF

fn_SumArray(arr_first := arr_real[0], arr_size := SIZE, sum_out := sum_real);
sum_test := 0;
FOR i := 0 TO SIZE - 1 DO
    sum_test := sum_test + arr_real[i];
END_FOR
IF (sum_real <> sum_test) THEN
    test_failed := TRUE;
END_IF

The result of the program above:

screanshot of codesys

If writing the same code for every type is too tedious, you can always use a script to automate this:

#!/usr/bin/env python3

code_template = \
"""CASE arr_first.TypeClass OF
{0}
ELSE
\tfn_SumArray := TRUE;
\tFOR i := 0 TO sum_out.diSize - 1 DO
\t\tsum_out.pValue[i] := 0;
\tEND_FOR
END_CASE;
"""

case_template = \
"""\t__SYSTEM.TYPE_CLASS.TYPE{0}:
\t\tptr_arr.{0} := arr_first.pValue;
\t\tptr_sum.{0} := sum_out.pValue;
\t\tptr_sum.{0}^ := 0;
\t\tFOR i := 0 TO arr_size - 1 DO
\t\t\tptr_sum.{0}^ := ptr_sum.{0}^ + ptr_arr.{0}[i];
\t\tEND_FOR
"""

types = ['_REAL', '_LREAL', '_USINT', '_UINT', '_UDINT', '_ULINT', '_SINT', '_INT', '_DINT', '_LINT']

cases = [case_template.format(t) for t in types]
code = code_template.format(''.join(cases))

print(code)

Just run the above script with python 3.x and you'll get the case statements code for the types listed in the script.

我是男神闪亮亮 2025-01-28 23:37:56

我最终要做的是一个案例声明,里面有循环。

不像我希望的那样优雅,但仍然具有功能。

FUNCTION fn_SumArray : REAL
VAR_INPUT 
    inArr : ANY; //Array to size
    inElem : ANY; //Any element in the array
END_VAR

VAR
    i : DINT := 0;
    pBYTE : POINTER TO BYTE; //8 bit
    pSINT : POINTER TO SINT; //8 bit
    pUSINT : POINTER TO USINT; //8 bit
    pWORD : POINTER TO WORD; //16 bit
    pINT : POINTER TO INT; //16 bit
    pUINT : POINTER TO UINT; //16 bit
    pDINT : POINTER TO DINT; //32 bit
    pUDINT : POINTER TO UDINT; //32 bit
    pDWORD : POINTER TO DWORD; //32 bit
    pREAL : POINTER TO REAL; //32 bit
    pLREAL : POINTER TO LREAL; //64 bit
    pLWORD : POINTER TO LWORD; //64 bit
    
END_VAR
//---------------------------------
CASE inElem.TypeClass OF
    __SYSTEM.TYPE_CLASS.TYPE_SINT:
        FOR i := 0 TO inArr.diSize-1 BY 1 DO
            pSINT := ADR(inarr.pValue[i]);
            fn_SumArray := fn_SumArray + pSINT^;
        END_FOR;
    __SYSTEM.TYPE_CLASS.TYPE_USINT:
        FOR i := 0 TO inArr.diSize-1 BY 1 DO
            pUSINT := ADR(inarr.pValue[i]);
            fn_SumArray := fn_SumArray + pUSINT^;
        END_FOR;
    __SYSTEM.TYPE_CLASS.TYPE_WORD:
        FOR i := 0 TO inArr.diSize-1 BY 2 DO
            pWORD := ADR(inarr.pValue[i]);
            fn_SumArray := fn_SumArray + pWORD^;
        END_FOR;    
    __SYSTEM.TYPE_CLASS.TYPE_INT:
        FOR i := 0 TO inArr.diSize-1 BY 2 DO
            pINT := ADR(inarr.pValue[i]);
            fn_SumArray := fn_SumArray + pINT^;
        END_FOR;    
    __SYSTEM.TYPE_CLASS.TYPE_UINT:
        FOR i := 0 TO inArr.diSize-1 BY 2 DO
            pUINT := ADR(inarr.pValue[i]);
            fn_SumArray := fn_SumArray + pUINT^;
        END_FOR;    
    __SYSTEM.TYPE_CLASS.TYPE_DINT:
        FOR i := 0 TO inArr.diSize-1 BY 4 DO
            pDINT := ADR(inarr.pValue[i]);
            fn_SumArray := fn_SumArray + pDINT^;
        END_FOR;    
    __SYSTEM.TYPE_CLASS.TYPE_UDINT:
        FOR i := 0 TO inArr.diSize-1 BY 4 DO
            pUDINT := ADR(inarr.pValue[i]);
            fn_SumArray := fn_SumArray + pUDINT^;
        END_FOR;    
    __SYSTEM.TYPE_CLASS.TYPE_DWORD:
        FOR i := 0 TO inArr.diSize-1 BY 4 DO
            pDWORD := ADR(inarr.pValue[i]);
            fn_SumArray := fn_SumArray + pDWORD^;
        END_FOR;
    __SYSTEM.TYPE_CLASS.TYPE_REAL:
        FOR i := 0 TO inArr.diSize-1 BY 8 DO
            pREAL := ADR(inarr.pValue[i]);
            fn_SumArray := fn_SumArray + pREAL^;
        END_FOR;    
    __SYSTEM.TYPE_CLASS.TYPE_LREAL: 
        FOR i := 0 TO inArr.diSize-1 BY 8 DO
            pLREAL := ADR(inarr.pValue[i]);
            fn_SumArray := fn_SumArray + pLREAL^;
        END_FOR;    
ELSE
    fn_SumArray :=0;
END_CASE;

What I ended up going with was a case statement, with for loops inside.

Not as elegant as I had hoped, but still functional.

FUNCTION fn_SumArray : REAL
VAR_INPUT 
    inArr : ANY; //Array to size
    inElem : ANY; //Any element in the array
END_VAR

VAR
    i : DINT := 0;
    pBYTE : POINTER TO BYTE; //8 bit
    pSINT : POINTER TO SINT; //8 bit
    pUSINT : POINTER TO USINT; //8 bit
    pWORD : POINTER TO WORD; //16 bit
    pINT : POINTER TO INT; //16 bit
    pUINT : POINTER TO UINT; //16 bit
    pDINT : POINTER TO DINT; //32 bit
    pUDINT : POINTER TO UDINT; //32 bit
    pDWORD : POINTER TO DWORD; //32 bit
    pREAL : POINTER TO REAL; //32 bit
    pLREAL : POINTER TO LREAL; //64 bit
    pLWORD : POINTER TO LWORD; //64 bit
    
END_VAR
//---------------------------------
CASE inElem.TypeClass OF
    __SYSTEM.TYPE_CLASS.TYPE_SINT:
        FOR i := 0 TO inArr.diSize-1 BY 1 DO
            pSINT := ADR(inarr.pValue[i]);
            fn_SumArray := fn_SumArray + pSINT^;
        END_FOR;
    __SYSTEM.TYPE_CLASS.TYPE_USINT:
        FOR i := 0 TO inArr.diSize-1 BY 1 DO
            pUSINT := ADR(inarr.pValue[i]);
            fn_SumArray := fn_SumArray + pUSINT^;
        END_FOR;
    __SYSTEM.TYPE_CLASS.TYPE_WORD:
        FOR i := 0 TO inArr.diSize-1 BY 2 DO
            pWORD := ADR(inarr.pValue[i]);
            fn_SumArray := fn_SumArray + pWORD^;
        END_FOR;    
    __SYSTEM.TYPE_CLASS.TYPE_INT:
        FOR i := 0 TO inArr.diSize-1 BY 2 DO
            pINT := ADR(inarr.pValue[i]);
            fn_SumArray := fn_SumArray + pINT^;
        END_FOR;    
    __SYSTEM.TYPE_CLASS.TYPE_UINT:
        FOR i := 0 TO inArr.diSize-1 BY 2 DO
            pUINT := ADR(inarr.pValue[i]);
            fn_SumArray := fn_SumArray + pUINT^;
        END_FOR;    
    __SYSTEM.TYPE_CLASS.TYPE_DINT:
        FOR i := 0 TO inArr.diSize-1 BY 4 DO
            pDINT := ADR(inarr.pValue[i]);
            fn_SumArray := fn_SumArray + pDINT^;
        END_FOR;    
    __SYSTEM.TYPE_CLASS.TYPE_UDINT:
        FOR i := 0 TO inArr.diSize-1 BY 4 DO
            pUDINT := ADR(inarr.pValue[i]);
            fn_SumArray := fn_SumArray + pUDINT^;
        END_FOR;    
    __SYSTEM.TYPE_CLASS.TYPE_DWORD:
        FOR i := 0 TO inArr.diSize-1 BY 4 DO
            pDWORD := ADR(inarr.pValue[i]);
            fn_SumArray := fn_SumArray + pDWORD^;
        END_FOR;
    __SYSTEM.TYPE_CLASS.TYPE_REAL:
        FOR i := 0 TO inArr.diSize-1 BY 8 DO
            pREAL := ADR(inarr.pValue[i]);
            fn_SumArray := fn_SumArray + pREAL^;
        END_FOR;    
    __SYSTEM.TYPE_CLASS.TYPE_LREAL: 
        FOR i := 0 TO inArr.diSize-1 BY 8 DO
            pLREAL := ADR(inarr.pValue[i]);
            fn_SumArray := fn_SumArray + pLREAL^;
        END_FOR;    
ELSE
    fn_SumArray :=0;
END_CASE;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文