【问题标题】:how to create pointer to function in codesys v3如何在codesys v3中创建指向函数的指针
【发布时间】:2017-03-31 11:01:55
【问题描述】:

你能举个例子说明如何在我的库中声明一个指向函数的指针吗?以及如何将指向函数的指针传递给我的外部库?

【问题讨论】:

    标签: c codesys iec61131-3


    【解决方案1】:

    TL;DR:在 CoDeSys v3 中可以进行手提包,而且非常容易。

    在 CoDeSys 中,“函数”实际上是存储在函数表中的函数指针。

    在 CodeSys v2 中,要获取函数的地址,您必须使用 INDEXOF(F_MyFunction),这提供了函数表中函数指针的索引。获取桌子的地址是,呃,读者的练习(可以通过一些体操来检索它)。

    在 CoDeSys v3 中,ADR 代替了INDEXOF,因此ADR(F_MyFunction) 为您提供了指向F_MyFunction 代码的函数指针的地址!

    你猜怎么着:你可以设置函数指针,F_MyFunction(...) 只是通过函数指针调用。

    就这么简单。

    因此,要进行间接函数调用,您需要做的就是声明一个虚拟“函数”,它实际上就像一个可设置的函数指针!

    假设我们有两个要间接调用的目标函数:

    FUNCTION F_Add1: INT
    VAR_INPUT
      param : INT;
    END_VAR
    F_Add1:= param + 1;
    END_FUNCTION
    
    FUNCTION F_Add2: INT
    VAR_INPUT
      param : INT;
    END_VAR
    F_Add2:= param + 2;
    END_FUNCTION
    

    然后我们定义一个“函数指针”,它必须与间接调用的函数具有相同的签名:

    FUNCTION FPTR_Add : INT
    VAR_INPUT
      param : INT;
    END_VAR
    END_FUNCTION
    

    我们还可以有一个分配给函数指针的助手:

    F_FPTR_Assign
    VAR_INPUT
      dst : POINTER TO PVOID;
      src : POINTER TO PVOID;
    END_VAR
    dst^ := src^;
    END_FUNCTION
    

    最后,让我们做一些间接调用:

    // should return 3 if indirect calls work
    FUNCTION F_Test : INT
    VAR
      val : INT;
    END_VAR
    
    F_FPTR_Assign(ADR(FPTR_Add), ADR(F_Add1));
    
    // FPTR_Add points to F_Add1
    val := FPTR_Add(val);
    // here val has value 1
    
    F_FPTR_Assign(ADR(FPTR_Add), ADR(F_Add2));
    
    // FPTR_Add points to F_Add2
    val := FPTR_Add(val);
    // here val has value 3
    
    F_Test := val;
    
    END_FUNCTION
    

    此方法的唯一缺点是调试器不检查函数指针的动态值,因此 step into 的行为类似于 step over。解决方法是在目标函数中设置断点,然后 step intostep over 都会停在那里。

    还有其他方法可以达到这种效果,例如通过直接操作堆栈帧,所以即使这个确切的方法由于 CoDeSys 中的一些变化而停止工作,也有其他方法可以做到这一点。

    【讨论】:

    • 非常感谢。这在 Beckhoff 的 TwinCat3 中也能完美运行!
    • @dotKokott 您可能需要联系您的 Beckhoff 代表并告诉他们,在当今时代,对此类体操的需求是不可接受的。函数指针或等价物是任何现代编程系统的基本功能,而 TC3 不正式支持它们的事实就像是一记耳光。软件工程社区需要对 CoDeSys 和 Beckhoff 等供应商施加巨大压力,这些供应商的开发工具停留在上世纪下半叶。如果他们听到的只是蟋蟀,他们什么都不会改善。我们需要改变。请务必与他们联系。
    • 我个人参与了 Beckhoff TC3 PLC 运行时的大规模迁移,正是因为他们的开发系统非常糟糕,而且在各方面都如此落后,以至于这是对一个人的智力的侮辱。任何软件开发都要求源代码与 git 兼容,并且工具易于自动化。他们提供了一些口头上的服务,但与任何其他现代开发工具相比,这都是一个巨大的谎言,完全倒退。 CoDeSys 和 TC3 都用随机垃圾污染源文件夹,这是第一个大禁忌。从那里只有下坡路
    【解决方案2】:

    codesys 中可以使用指针。要在codesys 中创建指针,您可以这样做

    VAR 
      pVar : POINTER TO BYTE;
      tempVar  : BYTE;
      derefereceVar : BYTE;
    END_VAR
    
    //get a pointer to the byte variable
    pVar := ADR(tempVar);
    

    要取消引用该指针,您会

    derefereceVar := tempVar^;
    

    因此,如果您想将指针作为函数的参数,您可以在上面的示例中将 pVarADR(tempVar) 传递给以 POINTER_TO_BYTE 作为类型的函数的参数。

    【讨论】:

    • 感谢您的回复,但我喜欢创建指向函数的指针,例如在 c 语言中我们这样做:int sum (int num1, int num2) { return sum1+sum2; } int main() { int (*f2p) (int, int); f2p = 总和; int op1 = f2p (10, 13); int op2 = sum (10, 13); printf("输出 1 – 通过指针调用函数:%d",op1); printf("Output2 – 用于直接函数调用:%d", op2);返回0;所以我喜欢在 codesys 中做同样的事情来将此指针发送到我的外部库
    【解决方案3】:

    编辑 09/2020:请参阅本主题中的另一个答案并忘记这个!

    在基于 Codesys 的平台中,可以创建指向数据类型或功能块的指针。在 TwinCAT 3 中也可以创建函数指针,但不能在 PLC 程序中调用。函数指针只能作为外部库组件的参数。

    检查这个: https://infosys.beckhoff.com/english.php?content=../content/1033/tc3_plc_intro/136447627.html&id=4296747249216071915

    【讨论】:

    • 刚刚注意到我收到的这个答案很少有人反对。只是想知道回答问题是否有问题。 Codesys 3的PLC代码中不能做函数指针。
    • 但是您可以,而且 ADR 就是您的做法 - 您链接到的 ADR 文档中没有任何内容与此相反。他们没有记录 ADR 的结果,即如何使用它。这留给自己的努力,但很容易弄清楚。您在 32 位或 64 位内核模式下运行,具有平坦的内存,可以这么说,世界是敞开的。调查内存内容没什么大不了的。
    • 感谢您对这个话题的回答,这很鼓舞人心!
    猜你喜欢
    • 2023-03-12
    • 1970-01-01
    • 1970-01-01
    • 2015-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多