
今天说一个PLC编程的基础知识块调用的值传输与指针传输。我们以使用最广泛的博途PLC为例子。在块调用时会传递参数被传递的参数可以是值也可以是指针。这是一个知识点。不过平时对这个知识点没有什么感觉。我也如此虽然知道这个事情但是似乎与我平时编程关系不大。but上周的调试经历让我在这个问题上整整付出了几个小时的心思才越过这道坎。这几个小时我更多在思考为什么我的预期与实际程序监控完全不同心里的冲突很激烈。为了让伙计们少走类似的弯路今天就说说块调用的值传输与指针传输。为了突出问题这里不把我遇到的真实问题拿来说。我把我遇到的真实问题简化后分享给大家。先介绍这个例子。图 1项目如图1很简单。1个FC1个OB11个数据块。图 2数据块中的内容也很简单如图2。我们整个项目只对Flag1进行操作。图 3如图3在OB1中调用FC1。并设置观察点1这个观察点用来观察Flag1的值。在OB1调用FC1时引脚“tag_INOUT”的实际参数是Flag1。图 4图4是FC1的情况。该FC有一个IN-OUT引脚“tag_INOUT”。在该FC1内部对Flag1进行置位操作。到此所有程序和数据到此就介绍完毕。观察程序执行的情况。在FC1中对标志位进行置位标志位的值是1在观察点1标志位是0。奇怪不整个程序都没有复位标志位的程序可是可是可是结果使人意外。伙计们阅读到此可以先缓一缓神不要急于向下看结果。先想5分钟这是为什么。我遇到的实际情况比这个要复杂得多。我遇到的问题卡了我几个小时。我怀疑了各个可能出问题的地方试图修正程序但都失败。在观察点1标志位为什么被复位了呢好了我们给出答案和分析。观察图3我们知道在图3调用FC1时刻network 1Flag1是0。在调用FC1后CPU运行FC1中的程序当运行完FC1的network 1后图4Flag1是1。然后CPU会结束FC1的运行返回OB1中。在结束FC1运行前CPU会做一件事这件事情就是将在FC1中的运行结果输出到FC1的输出引脚以及输入输出引脚。问题就出现在这里。在FC1中变量tag_INOUT始终是0因为在FC1中从没对这个变量进行置位操作。在结束FC1运行返回OB1时刻CPU将tag_INOUT值是0的值赋值给Flag1。此时Flag1的值就是0了。好了完全能解释通了。上一段介绍的就是函数引脚的值传输。值传输在类似上述的一些情况容易出问题。所以博途引入了函数引脚的指针传输。下面我们看看指针传输是否能修正这个问题。我们首先对FC1的引脚进行改造。图 5我们不更改FC1的程序只更改引脚。我们把gDB中的结构体复制到FC1的引脚中。图 6在OB1中把gDB中的结构体放到FC1中的引脚其余都不改。然后下载程序进行监控我们发现这个错误已经得到修正Flag1的值和编程者的意图一致了。当输入输出引脚是结构体时在调用程序块时引脚向程序块内部传输的是指针不是值。在结束FC1调用前不会把FC1中的相关值赋值给引脚。所以也就不会复位Flag1了。这一段就是程序块引脚指针传输的原理。另外在程序块内对IN-OUT中的结构变量操作是对引脚实际参数的直接操作。这种直接操作本质上就是利用指针对数据进行操作所以称为引脚的指针传递。好了稍微有点绕。需要反复琢磨一下就明白了。在IT的高级语言中同样存在着函数引脚的值传输和指针传输。比如在C#中如果引脚增加关键字REF那么这个引脚就是指针传输。但是在博途中由于没有REF或者类似的关键字所以很容易忽视程序块传输的到底是值还是指针。这也是为什么会给我带来这么大调试困扰的重要原因。因为虽然我知道这个知识点但是出现问题时并不会天然的想到是这个问题。如果博途日后的版本能把值传输还是指针传输显性化那么碰到类似的问题就容易排查了。总结这次调试的遭遇让我想起了一句老话别拿豆包不当干粮。伙伴们有啥问题欢迎在此讨论。关注我会有更多技术博客在这里分享。