精品课程/业务  
西门子S7-300PLC的V存储区的探索与发现介绍
西门子S7-300plc有V存储区吗?听到这个问题,绝大多数人都会笑起来, V存储区不就是S7 -200的变量存储区吗?S7-300哪里有什么V区?有没有搞错?最近有个网友在网上询问这个问题:“我的疑问也是这个V区,被一堆人鄙视的说是200的吧。另外我有个疑问没见有谁用这个区域编程,麻烦有类似的例子给露露脸啊”,显出了几分急切和无奈。
我也曾经被这个问题困扰过,下面向大家介绍我寻找答案的过程。
首先在STEP 7的帮助中搜索”V区" ,在参数类型ANY和POINTER的帮助中有个存储区编码表,中就有V区,其代码为16#87 ,对V区的描述为"先前的本地数据"。这几个字像天书-样,可能很难有人能看懂。
为了确认翻译的准确性,我将STEP 7切换到英语,“先前的本地数据”的英文为"Previous local data”"。local data一般翻译为“局部数据" ,看来翻译没有问题。德国人的英语水平很高,德国大学图书馆的书籍和杂志大多数都是英语的,不用怀疑德语翻译为英语时失真。
V区与参数类型ANY和POINTER有关,打开STEP 7的帮助目录中的附录,选中其中的“数据类型和参数类型\参数类型\参数类型POINTER的格式”,可以看到参数类型由6个字节组成, 0号和1号字节是DB块的编号,不是数据块内的地址时为0。2~5号字节的格式与寄存器间接寻址的格式相同。下面是寄存 器间接寻址的32位指针格式:
x000 0rrr 0000 0bbb bbbb bbbb bbbb bxx
其中第0~ 2位( xxx ,最低位为第0位)为被寻址地址中位的编号(0~7),第3 ~ 18位( 16个b )为被寻址地址的字节的编号。第24 ~ 26位( rr )为被寻址地址的区域标识号,指针的最高位x为0时,为区域内的间接寻址,最高位x为1时,为区域间(交叉区域)间接寻址。
参数类型ANY可以用来传递一片连续的地址区 ,由10个字节组成。ANY和POINTER用于在块调用时传递输入、输出参数。为了揭开V区之谜,编写了FC1 ,将地址区中相邻的若干个字累加。地址区的起始地址由参数类型为POINTER的输入参数Start_ _Addr提供。P# DB2.DBX0.0也可以改写为DB2.DBX0.0。在OB1 中调用FC1 :
CALL FC   1
Start_ Addr :=P# DB2.DBX0.0 //数据区起始地址
Number :=5                    //需要累加的字数
Result :=DB2.DBD10           //保存运算结果的双整数

图1是运行时监控FC1的结果,累加器1 ( STANDARD )中的数据为十六进制显示格式, AR1是地址寄存器1。终于看到了AR1中的V区地址了!

图1中第一条指令的P#表示指针, 第2个#号表示局部变量。P# #Start_ _Addr就是调用FC1时,用输入参数Start_ Addr传送给FC1的指针P #DB2.DBX0.0 ( 16#0002 8400 0000 )存放的地址。P# #Start_ _Addr ( 16#870000a8 )最低字节16# a8对应的二进制数为2# 10101000 ,其字节部分为2#10101 ,即十进制数21 ,最高字节16#87( 2#1000 0111 )表示存储区为V区。
第一条指令将P##Start_ Addr送给累加器1 ,第二条指令将 累加器1中的数据传送到AR1 ,传送后AR1中的地址为V21.0 (即16#8700 00a8 )。
那么V区到底是什么呢?根据帮助中的解释先前的本地数据" ( Previous local data) , 猜想与局部数据堆栈有关。执行每个块时,它都有自己的临时局部数据。在OB1调用FC1时 , OB1的临时局部数据被保存到局部数据堆栈, FC1则使用它自己的临时局部数据区, OB1的局部数据成为“Previous local data" (以前的局部变量)。根据上述分析, V区很有可能是调用FC1的OB1的局部数据区。
怎样才能证实这个猜想呢?最好能看到AR1中的地址为V21.0时, OB1的局部数据。好在STEP 7的监控功能可以查看块调用时保存在堆栈中的数据。为了能看到某条指令执行后OB1的局部数据,在FC1的第2条指令处设置一个断点。执行完第2条指令后, CPU进入HOLD模式,此时打开CPU模块信息对话框的”堆栈"选项卡,选中B堆栈中的OB1 ,点击"L堆栈"按钮,打开L堆栈对话框, OB1的局部数据堆栈如图2所示。




由图1可知,因为指针常数P#V21.0 ( 16#8700 00a8 )被送给AR1 ,监控区中的AR1列显示V21.0。此时OB1调用FC1的POINTER格式的实参P# DB2.DBX0.0 ( 16#0002 8400 0000 ) ,存放在从OB1的局部变量L B21开始的6个字节中(见图2)。因此AR1中的P#V21.0表示指针常数P# DB2.DBX0.0的值存放在OB1的局部变量区中的地址,换句话说, V区就是调用FC1时OB1的局部数据区。
难怪”没见有谁用这个区域编程" , V区用于监控,在编程时没有使用它。
最后我们来总结一-下块调用时的参数传递过程。如果输入参数为简单数据类型,例如字节、字、整数和双整数,可以通过32位( 4个字节)的累加器1直接传递参数。而ANY和POINTER分别为10个和6个字节, 不能用累加器1直接传递。因此将这些参数的实参(例如16#0002 8400 0000 )暂时保存在OB1从V21.0开始的局部变量中。在被调用的FC1中,P# #Start _Addr提供了保存参数Start_ Addr的实参的地址V21.0 ,在FC1中用寄存器间接寻址指令"L W [AR1,P#0.0]"来读取POINTER实参的第一个字 (数据块编号) , 用指令"L D [AR1,P#2.0]"来读取POINTER实参的2~5号字节(数据块内的变量地址P# DBX0.0 )。间接寻址的操作数地址等于方括号中AR1的地址值加上逗号后面的地址偏移量。
说到这里,我们可以看到传递POINTER参数类型的思路是非常清晰的,“Previous local data"用词是准确的,只不过所用的笔墨太少,背后的复杂过程需要我们猜想和验证。
解决了这个问题后,有一些感触:
1.由于语言和思维方式的差异,老外写的用户手册有的地方很难理解,这并不奇怪。奇怪的是网上有一些高手的"用户手册万能论"。用户手册肯定不是万能的,不可能回答所有的问题,有的问题还需要我们设法去探索和发现,包括用程序来验证我们的假设。
2.这个问题的解决使我惊叹STEP 7强大的功能,如果没有断点和监控堆栈的功能,是不可能搞清楚这个问题的。还有别的PLC有这些功能吗?




上海仰光电子科技:plc培训,plc编程培训,plc培训中心欢迎您的加入
24小时报名热线:13761149023 张老师
总机:021-50782969 周一至周五 9:00-18:00
网址:http://px.shygdz.com
 
上海plc培训班
 
 
联系我们
021-50782969  13761149023

地址:上海市金穗路1501号2栋二楼1203室欧姆龙总部对面
关键词:plc编程培训,上海plc培训班,数控系统培训 变频器维修培训

 
版权所有:上海仰光电子科技有限公司 备案号:沪ICP备16027027号-1 Copyright(c) 2018 shanghai yangguang dianzi All rights reserved.