问题出现在一次调试过程中,具体见我的求助帖http://www.ad.siemens.com.cn/club/bbs/post.aspx?a_id=1381183&b_id=4&s_id=23&num=4#anch 帖子4楼是我的分析结果,最近调试结束,趁休息时间将此问题汇总总结一下分享给大家。
问题:大家可以测试一下下面这个情况:
FC2函数:
OB1调用:
本意是想在M1.0=1时,将两个输入值分别赋值输出,然后M1.0=0时,各自保持各自在M1.0=1时的数值,而实际情况是在M1.0=1时,各情况正常,在M1.0=0时,DB1.DBD4和DB1.DBD12的值一直为最后一次M1.0=1时DB1.DBD12的数值。在更换为M区变量进行测试,则没有此情况。
问题1:DB作为全局变量为什么会有这种现象?
问题2:M和DB变量的区别在哪里?
我们先研究一下在OB1中多次重复调用FC的原理
我们创建FC1函数(我们具体不讨论函数实际意义,只是通过变现出来的现象分析原因)
接口 名称 数据类型
IN: In Pointer
Out: Out Real
Temp: Temp Word
L P##In
LAR1
L W [AR1,P#0.0]
T #Temp
OPN DB [#Temp]
L D [AR1,P#2.0]
LAR1
L D [AR1,P#0.0]
T #Out
BE
FC1程序基本相当于move指令
在OB1中多次重复调用FC1(第二次引入MD,主要是想看一下M数据和DB数据的调用区别)
CALL FC 1
A1:=DB1.DBD0
A2:=DB1.DBD4
CALL FC 1
A1:=MD8
A2:=MD12
CALL FC 1
A1:=DB1.DBD8
A2:=DB1.DBD12
具体思路是通过执行断点来查看执行每次fc1调用后,输出值的变化情况
我们先看一下OB1的L堆栈
图中LB21-LB26(蓝色线区域)为调用FC时,OB1传输给FC输入对应的地址(相当于L21.0对应FC中的V21.0);LB27-LB30(红色线区域)是变量的数值(具体是哪个变量的数值我们下面分析)
我们给所有变量赋值(为了便于观察我们设置以16进制显示)
我们分别设置3个断点,看一下每次断点处OB1的L堆栈信息(每个断点处为上一个调用结束时的信息)
第一个FC调用结束,在断点2处:
我们可以看出LB21-LB26:00 01 84 00 00 00为Pointer地址,对应为DB1.DB0.0,即传输给FC1的输入值对应的地址;LB27-LB30:00 00 00 0A为输出DB1.DBD4的值。
第二个FC调用结束,在断点3处:
此处跟上面不太一样:LB21-LB26:00 00 83 00 00 40为Pointer地址,对应为M8.0,即传输给FC1的输入值对应的地址;LB27-LB30:00 00 00 0A不是其对应的数值14,还是上次FC1调用后的值。我们由此猜测,LB27-LB30保存的仅为db块数据,M的值不在ob1的临时堆栈保存,应该是直接在M分配的固定的存储位置更改,这可能是DB块变量和M、I、Q的一个很重要的区别。
第三个FC调用结束,在断点1处:
我们可以看出LB21-LB26:00 01 84 00 00 40为Pointer地址,对应为DB1.DB8.0,即传输给FC1的输入值对应的地址;LB27-LB30:00 00 00 1E为输出DB1.DBD12的值。
通过上面的分析,我们可以得出问题的答案:
1、在OB1的L堆栈中,LB27-LB30保存DB变量数据,并传递给此时FC输出对应的DB变量;
2、I/Q/M变量和DB变量不同之处在于,在调用时,I/Q/M变量的变化是对应直接在其区域中更改,而DB变量在通过OB1的L堆栈中LB27-LB30赋值(LB27-LB30的值大部分情况下是正确的,但在文中开头情况下,由于M1.0=0,程序运行此处未做Move运算,无法给DB1.DBD4赋值,所以LB27-LB30值没有变化,但是LB27-LB30值还是要赋给DB1.DBD4,所以所有FC调用的输出均为最后一次DB变量的存入的值。