//////////////////////////////// buffer声明为pointer输入变量,DB_ID声明为word临时变量
L P##buffer ///读取指针基址,父程序调用时,buffer=DB2.DBX0.0
LAR2 ///装入AR2
L W [AR2,P#0.0] ///这时读取是到底是什么?一直没有搞清楚,仿真读的是2,2是DB块号,但不知道为什么是2?我曾经有两种理解,一种理解是:在前述DB2中,读取以指针(基址+偏移)寻找到的字,就是在DB2中第0个字,似乎不对。另一种理解是:以指针(基址+偏移)作为一个双字数据,读取它的一个低字,这个低字包含DB号信息,但这个理解也说不通。两种理解似乎都不能与西门子的说法相符?西门子说pointer类型是6字节,而AR是4字节,6字节对4字节?
T #DB_ID ///作为DB号
OPN DI [#DB_ID] ///将这个DB作为背景数据块打开
L D [AR2,P#2.0] ///此处也有同样的疑问?还有偏移量(+P#2.0)是以字节为单位加的,还是以前面数据宽度(比如双字D)为单位加的?
LAR2 ///装入AR2
以问题上希望前辈们解释一下,看过很多网上的解释和西门子的说法一直没搞清楚,头大了!
最佳答案
1:首先需要了解 POINTER 的结构 POINTER是一个类似于C语言中指向指针的指针
见图1
POINTER 类型占用 6个字节,0-1字节是存放实参的DB号,2-5字节是存放 地址指针。
L P##buffer ///读取指针基址,父程序调用时,buffer=DB2.DBX0.0
LAR2 ///装入AR2
L W [AR2,P#0.0] //根据图中所示,0-1字节就是指向DB块号码(如果不是DB区,那么就是0)
//所以 W[AR2,P#0.0]值是2,根据你的描述,你错误理解了POINTER的用法,POINTER 不直接指向DB2里面的数据(所以叫它指向指针的指针)在系统调用子程序的时候有一个实参到形参的赋值过程。在你的程序里BUFFER 就是形参,DB2.BDX0.0就是实参,父程序在调用子程序时,在实参到形参的参数赋值过程中会用到L堆栈(根据POINTER结构,把数据存放到L区中)。在子程序中,L buffer 这句 就是取出 POINTER在 L区中地址。LAR2就是把首地址 存放到AR2中。
L W[AR2,P#0.0] 可以理解成 L LW[AR2,P#0.0],至于AR2 指向L0.0还是L20.0 这个是由PLC自己管理的,你不需要担心(假设系统在实参到形参的赋值用到了 L20.0开始的6个字节)。实参DB2.DBX0.0 中到BUFFER赋值的过程中就会按照POINTER 的结构 把相关的DB号信息和地址指针DBX0.0的值 赋值到 LB20-LB25中。
L BUFFER 累加器中地址指针值为 160(20*8)
LAR2 AR2值为160
L W{AR2,P#0.0] 就是 L LW[AR2,P#0.0] ,AR2中的地址指针是 20*8=160,所以相当于 L LW20 LW20中的值为2,为实参的DB号
OPN DI [#DB_ID] ///将这个DB作为背景数据块打开 打开DB2
L D[AR2,P#2.0] 相当于 L LD22, LD22 中存放 实参的DB2.DBX0.0 的偏移地址 DBX0.0
LAR2 //注意这个时候 AR2的值 不在指向 L20.0 了,指向DBX0.0 。
如果下面 再有 L W[AR2,P#2.0] 就相当于 L DB2.DBW2了 ,不在指向LW22了。
图片说明:
提问者对于答案的评价:
谢谢热心回答,明白了
补充一个问题:
L P##ABC
ABC除了声明为POINTER外,还能声明为其它类型吗?若有请举例回答。
(关于P##ABC我之前的理解是:P#(#ABC),#ABC是局部符号变量,前面P#是把后面的变量指针化,不知对否?)
专家置评
已阅,最佳答案正确。好需要了解变量的直接寻址和间接寻址、存储器间接寻址和寄存器间接寻址、寄存器内部区域间接寻址和交叉区域间接寻址等知识点。
原创文章,作者:more0621,如若转载,请注明出处:https://www.zhaoplc.com/plc224065.html