电子说
第三篇 带参数子程序的参数传递过程
一份程序中建立多个子程序,每个子程序完成相对比较独立的功能。而子程序也是围绕主程序的要求,并且还根据主程序给出的条件完成这个要求。此时主程序和子程序之间或者说子程序和它下级的子程序之间,就必然有一些数据的交流。下面将介绍一下这种参数的传递。
再提一下变量表,子程序里面的变量表,这是最重要的上下级程序之间数据传递的方式,但不是唯一的方式。主程序把将要给子程序的数值摆放在一个或一片约定的全局地址,然后子程序读取这些全局的地址……这种做法作为传递参数,最简单不过。但是,这里不讨论这样的传递方式。
现在随便做一个子程序,观察一下在主程序中调用时候的外观。
图1
图2
如图1所示是在主程序里面调用SBR_0的情况,还有一个常见的计数器指令。如图2所示是SBR_0中变量表所填入的变量设置。
图1中一个标注SBR_0的指令块跟计数器指令外观很相似。但是各自的接口和参数都不同。它们都有触点接口和数据接口。现在看看子程序的调用,主程序通过什么渠道把参数传递到子程序。
SBR_0左边上方开始有两个连接着开关触点的接口。
【EN】有能流表示执行这个子程序。没有能流的话将从子程序门口经过,不进入子程序。一个子程序就算没有任何参数都会有这个接口的。
【点输入1】下边也是一个能流型的接口,表示这里有一个开关量的能流输入。
当鼠标指向这个指令块的时候,会弹出一个框,如图3所示。这里说明了所有参数的变量类型(in;in/out;out)和数据类型(b;B;W;D)。
图 3
【字输入】从弹框得知这是一个字型的输入参数。这里接口必须填写一个字型的变量或者常数。
【点输入2】这也是一个布尔量的输入参数,但是因为有其余类型的参数分割,导致没有从开始处连续排列布尔量的输入参数,所以这个布尔量输入也显示为数据接口形式。
【字节入出】从弹框得知这是一个输入输出双向的参数,需要填入一个字节型的变量。
【字输出】这个参数在右侧,位置上已经表明这是一个输出型的参数。
综上所述,输入型的参数将安排在左侧的最上方,并且如果上方有连续的开关量,都会以能流的形式连接这个参数。接下来是数据型的输入参数接口。然后下方是双向的参数接口。右边一律是数据接口形式连接所有输出参数。
上级程序就是通过这样的接口把子程序所需的参数传入到子程序的,再进入到子程序里面。接下来看看子程序方面,得到的参数将会是如何出现的。
观察上面图2这个变量表。自从建立了这个变量表开始,子程序里面的L地址的前面部分就已经成为了子程序参数的载体。L地址从第一个字节开始,往后安排IN参数;IN/OUT参数;OUT参数。按照字节为最小占用单位来安排能流接口的参数,从L0.0开始向更高位连续安排,EN不占用地址。对于布尔量,一个布尔量点占用整个字节,八个以内的连续布尔量点也占用一个字节。下一个非布尔量参数或者不同类型变量(IN、IN/OUT、OUT)从下一个字节开始安排。所以【点输入1】参数分配到L0.0,【字输入】参数分配到LW1。【字节入出】参数分配到LB4。然后子程序使用上级传递的参数就只要读取这些L地址就可以得到。
外面的情况了解了,里面的情况也了解了,参数传递……没说完,还有最不为人知的一部分。
——中间的过程。
中间过程就像一份快递的工作,在上级下级程序之间搬运数据。只要子程序被调用,那么快递就会把指定的数据传送到子程序内。子程序结束后,快递又会把指定的参数传送到上级程序的接口。要是没有接口参数自然没有这个岗位。
作为用户程序,只要上级程序把参数放置到位,又在子程序里面存取对应的L地址,中间怎么从上级传达到下级是无需做任何事情的。这个过程由系统代劳了。但不等于不用理解这个过程。你不知道的事情可能恰恰就在这里。做以下的程序实验一下。
图4
建立三个子程序,各自就只有变量表填写了一行参数,如图4所示。子程序里面无任何用户程序。主程序编辑这样的调用逻辑。把程序下载到PLC,看看执行会怎样?
PLC运行后,由于程序存在QB0和M0.0,没有任何用到的其他地址了,所以我们的焦点就关注着这两个地方,而QB0更是最容易看见。此时输出点还是熄灭的。用状态表把M0.0写入1,与此同时QB0也显示2#10010000(注意硬件的灯高位在右侧,书写二进制高位在左侧。)然后把M0.0写入0,此时QB0变成显示2#11001100。我们再次把M0.0写入1之后QB0再次显示2#10010000 。
为什么输出点会有这样的三种状态呢?用户程序完全没有对输出点做过逻辑和赋值,而子程序里面也没有任何程序。能够有动作的只能是系统的动作了。究竟会是什么时候使输出点得到了一些值?程序里面唯一跟QB0有点关系的就是SBR2子程序了。为什么SBR0、SBR1两个子程序的值会到了SBR2子程序里面去的?那么就要理一理参数传递的中间过程了。
运行初期,网络1不接通,网络2没产生边沿信号。前两个子程序都没有调用。唯独第三个子程序SBR2一直在调用。
接通M0.0,SBR0得到了执行。在进入子程序后,运行子程序用户指令之前,系统把引脚上的IN参数值复制到了LB0。然后执行子程序的用户程序,由于没有程序可运行,退出了子程序。
网络2没有执行子程序。网络3一直在执行。SBR2子程序没有输入参数,没有子程序内容,离开子程序之前,系统必须要给一个值到输出参数。系统的这个动作不会因为程序中有没有内容或者说程序执行的怎么样,而不去做这个传送,它是必然会做这个动作的。那么这个时候,LB0到底是一个什么值呢?我们就要追溯到这个LB0最后赋值的是什么地方。之前由于执行SBR0输入参数使LB0曾经有过2#10010000这个值。这个值由于遵从多重赋值的原因,这个值在当时产生,一直搁置到现在,被SBR2捞上来了,然后就给了QB0。当M0.0恢复到0时,SBR1前的上升沿发生了,调用了一次。就这一次,把LB0写入了2#11001100。在没有什么地方再给LB0写入值的情况下,LB0将不会改变。(当一个子程序不调用的时候,并不会由此使得某些线圈、某些地址自动复位为零,但是仍有不少的人有这样的错觉。)大家也可以参考M0.0,编程软件写入了的值可以一直保持住的。你没有去更改它,还有谁去修改它?所以把一个值写入到某地址之后,就可以一直保持住,SBR2也就可以输出2#11001100这个值。
手册并没有说明局部储存区的值是从何而来,手册上面有一段话,如图5所示。
图 5
我有一个观点,当手册没有清楚说明的情况下,我会假设一种较为合理的假设,然后在日后的编程中一直证实这个假设,并使用这种假设,同时一直关注着这个问题。假如一直使用都没有明确显示这种假设不成立,将认为这是真的,继续使用。我总觉得PLC只会按照有限的法则以固定的方法实施一些运算。既然一个假设一直没有被推翻,那么这个假设可能永远也不会被推翻。
全部0条评论
快来发表一下你的评论吧 !