3 参数类型指针-POINTER与ANY
所谓参数类型指针就是专用于函数FC及函数块FB接口参数的传递,例如可以在IN、OUT、IN/OUT中声明这些变量,也可以在TEMP区(OB也可以)中声明作为一个变量赋值给调用FC/FB的接口参数。
3.1 POINTER指针的数据格式
POINTER指针占用48位地址空间,数据格式如图16所示。
POINTER指针前16位的数值表示数据块DB或DI的块号,如果指针没有指向一个DB块,则数值为0,POINTER指针可以指向的数据区参考下表:
与区域交叉指针相比,POINTER类型指针可以直接指向一个数据块中的变量,例如P#DB1.DBX0.0,所以 POINTER(6个字节)=DB块号(2个字节)+32位指针(4个字节,带有数据区的寄存器和存储器指针)。如果不是指向DB块,就是带有数据区的寄存器和存储器指针,例如P#M2.0。
调用FB、FC时,对POINTER指针数据类型的形参进行赋值时可以选择指针格式直接赋值,例如:
P# DB2.DBX12.0 //指向DB2.DBX12.0。
P#M12.1 //指向M12.1。
也可以选择使用地址声明或符号名(不使用符号P#)的方式进行赋值,例如:
DB2.DBX12.0 //指向DB2.DBX12.0。
M12.1 //指向M12.1。
3.2 ANY指针的数据格式
ANY数据类型指针中包括数据类型、重复系数、DB块号、存储器数据开始地址,占用80位地址空间,数据格式如图17所示。
ANY指针使用的数据类型(存储区)参考下表
ANY指针使用的数据类型(数据区)
ANY指针使用的数据类型(参数类型)参考下表
ANY指针使用的数据类型(参数类型)
ANY指针中的数据长度表示指向一个数据区域,例如指向整个数组、结构体等;如果ANY指针没有指向一个DB块,DB块号将为0;ANY指针的数据区与POINTER指针数据区定义相同。
与POINTER指针相比,ANY类型指针可以表示一段数据区域,例如P#DB1.DBX0.0 BYTE 10,表示指向DB1.DBB0~DB1.DBB9。调用FB、FC时,对ANY指针数据类型的形参进行赋值时可以选择直接使用指针格式赋值,例如:
以P#开头用于存储区数据类型
P# DB2.DBX12.0 WORD 22 //指向从DB2.DBW12开始22个字。
P#M12.1 BOOL 10 //指向从M12.1开始10个位信号。
以L#开头用于参数数据类型
L#2 BLOCK_FC 4 //指向从FC2开始4个FC。
L#4 TIMER 5 //指向从T4~T8。
也可以选择使用地址声明或符号名(不使用符号P#)的方式进行赋值,例如:
DB2.DBW12 //指向DB2.DBW12一个字,数据长度为1。
M12.1 //指向M12.1一个位信号,数据长度为1。
FC2 //指向FC2。
3.3 POINTER与ANY指针的拆分
32位地址指针可以直接装载到存储器或地址寄存器中,从而可以直接在程序块中使用,进行间接寻址,大家知道,S7-300/400可以直接引用的变量最大为4个字节,POINTER和ANY参数类型指针作为一个整体并大于4个字节而不能装载到存储器或寄存器中,所以不能在程序块中直接使用,必须进行拆分使用。拆分的指令只能使用STL完成,指令格式为:
P## <POINTER与ANY的符号名称>
表示指向POINTER与ANY指针的首地址,就是装载POINTER与ANY指针变量的开始地址。为了便于理解,假设FC接口中的一个ANY变量V_ANY开始地址为0(如果是临时变量区则为L0),那么指令:
L P##V_ANY //指向指针V_ANY的开始地址即L0。
如果将开始地址存储于存储器中,例如
T MD20 //将开始地址存储于MD20中,存储P#L0.0
如果要读出赋值ANY变量的数据类型就必须地址偏移一个字节即:
L MD 20
L P#1.0
+D
T MD 24 //数据类型开始地址存储于MD24中即P#L1.0
但是后面的问题来了,怎么样读出这个地址中的值?下面这样编写语法错误:
L B[MD24] //语法错误
只能使用交叉区域指针的方式,我在上一篇已经介绍了,
LAR1 MD 24 //将MD24中地址存储于地址寄存器AR1中
L B [AR1,P#0.0] //装载ANY指针的数据类型
T MB200 //存储于MB200中。
所以所有的拆分程序都必须使用寄存器交叉区域指针编写(不能使用存储器指针),这样就变成了固定格式,以ANY指针类型为例介绍拆分指令:
L P##V_ANY //指向指针V_ANY的开始地址即L0。并装载到地址寄存器AR1中。
LAR1
L B[AR1,P#1.0] //存储ANY指针的数据类型即LB1
L W[AR1,P#2.0] //存储ANY指针的数据长度即LW2
L W[AR1,P#4.0] //存储ANY指针的数据块号即LW4
L D[AR1,P#6.0] //存储ANY指针的开始地址区即LD6
IN、OUT、IN/OUT接口区不能显示绝对地址,所以必须使用拆分指令。
为了让大家更好地理解POINTER和ANY指针的应用,介绍一个编程应用。
3.4 ANY指针编程应用
编写一个计算功能的函数FC13,输入参数“In_Data”为一个数组变量,如果数组元素为浮点数,输出所有元素的平均值“OUT_VAL”,如果数组元素为其它数据类型,不执行计算功能。OB1中调用函数FC13的程序如下:
CALL FC 13 // 调用函数13。
In_Data:=P#DB1.DBX0.0 REAL 8 //输入数据区从DB1.DBD0开始8个浮点值。
OUT_VAL:=MD20 //计算结果。
完成的计算功能相当于MD20:=(DB1.DBD0+..+..+DB1.DBD28)/8。在函数FC13的接口参数中定义输入、输出变量及临时变量参考下表:
FC13接口参数
FC13中的示例程序如下:
3.5 使用ANY指针变量赋值
上面的示例程序在调用FC13时赋值的ANY数据类型为常数,如果使用变量则数据区、长度都可以变化,下面的应用示例使用ANY变量赋值SFC20(块复制)的接口参数,即将P#DB1.DBX0.0 INT 10复制到P#DB1.DBX20.0 INT 10中,函数接口声明参考图18。
在IN、OUT、IN_OUT区声明ANY变量没有绝对地址,所以必须使用拆分指令,在临时变量中声明ANY类型指针带有绝对地址,所以可以不用拆分指令直接赋值,示例程序如下:
数据块、地址区、开始地址和长度都可以作为变量,从而增加了程序的灵活性。
3.6 S7-1500处理参数类型指针的方式
1:如果习惯了S7-300/400的编程方式,可以直接使用AT指令在接口参数中进行拆分,这样使用LAD也可以编程,参考图19。
2:除此之外,还可以使用可变数组替代ANY类型指针,在S7-1500中可以非常方便地实现3.4章节的应用示例。在FC的接口参数中可以声明一个可变数组类型变量IN_DATA,数组元素为real(这个不可以变,在Variant中可以实现,后续章节介绍),输出所有元素的平均值“OUT_VAL”函数接口声明参考图20。
示例程序参考图21,比起Any的拆分,有股脱离苦海的感觉,并且没有编程语言的限制。
3:使用Variant,在后续章节中介绍。
------------------------------------------------------------------------------------------------------------
上一篇:【5】寄存器间接寻址——从S7-300_400到S7-1500看变址寻址的改变系列故事之五
下一篇:【7】Variant数据类型指针——从S7-300_400到S7-1500看变址寻址的改变系列故事之七
汇总帖:技术Π活动故事、视频与案例分享汇总