西门子PLC寻址方式
前些时间针对西门子的间接寻址做过一次详细的总结,但是总体来说概念很多并且不够清晰,也没有太多的实际用例,所以这次再谈寻址,主要是梳理西门子寻址里面的重要概念,以及结合使用场景直观体会寻址使用方法。
PLC的系统存储区域
- 过程印象输入PII:
- I
- IB
- IW
- ID
- 过程印象输出PIQ:
- Q
- QB
- QW
- QD
- 位存储器M:
- M
- MB
- MW
- MD
- 定时器T
- 计数器C
- 数据块:
- DB/DI
- DBX/DIX
- DBB/DIB
- DBW/DIW
- DBD/DID
- 局部数据:
- L
- LB
- LW
- LD
- 外设地址(外设寻址最小单位是byte):
- PIB/PQB
- PIW/PQW
- PID/PQD
寻址方式分类
-
直接寻址
- 绝对地址寻址:
- (比如I0.0/Q0.0/DB1.DBX0.0/L10.0/...)
- 符号寻址:
- 给绝对地址分配符号名,并用符号名找到对应变量:(比如给Q0.0命名为“Motor_On”,那么在程序中就能够直接使用“Motor_On”。)
- 绝对地址寻址:
-
间接寻址
- 存储器间接寻址:
- 16位地址指针寻址,通常用来寻址T/C/DB/DI/FB/FC这类块号:
CU C[LW0] // CU指令:计数器增1 UC FC[LW0] // UC指令:无条件跳转 SD T[LW0] // 计时器开始计时 OPN DB[LW0] // 打开DB
- 32位地址指针寻址(区域内),0-2位作为寻址的位地址,3-18位作为寻址的字节地址,19-31位保留。
存储器寻址中的32位指针仅仅用在存储器的内部寻址。
//通常而言,存储器内部寻址的32位指针表示成:P#Byte.bit,如下: L P#10.3 //如果要把一个DINT的常数转换成指针格式的常数,需要把该常数左移3位(或者乘以8)才行,如下: L L#100 // 取一个32位整型的常数100装入ACCU1 SLD 3 // 左移三位 T LD0 // LD0得到P#100.0的指针常数 //32位存储器指针用法举例: OPN DB1 //打开DB1 OPN DI2 //打开DB2,在STL中,分别使用DB/DI作为DB存储器,最多做到同时打开2个DB块 L 4 //取整数4到累加器1 SLD 3 //左移3位 T MD20 //存进一个32位存储器,表达为P#4.0的指针 L DBW[MD20] //装载DB1.DBW4 L DIW[MD20] //装载DB2.DBW4 +I T MW24 //两个整数相加结果传送到MW24
- 寄存器间接寻址:通过CPU的地址寄存器AR1和AR2寻址(AR1和AR2均为32位)的方式
- 区域内间接寻址:0-2位作为寻址的位地址,3-18位作为寻址的字节地址,19-31位保留。
//该间接寻址的表示为:存储器标识符[ARx,地址偏移量],如下: L MW [AR1,P#2.0] //DB块使用区域内寄存器间接寻址: OPN DB1 LAR1 P#10.0 L DBW[AR1,P#12.0] // 实际装载的是10.0+12.0=22.0的地址 //DI,DO使用区域内寄存器间接寻址 L P#8.7 LAR1 A I[AR1,P#0.0] //检查I8.7的结果 = Q[AR1,P#1.1] //输出给到Q10.0,(8.7 + 1.1 = 10.0)
- 区域间间接寻址:0-2位作为寻址的位地址,3-18位作为寻址的字节地址,19-23,27-30位保留,24-26位表达存储区域地址标识;31位固定为1,表达这是一个区域间间接寻址方法。
//该间接寻址的表示为:P# 存储器 字节.位,如下: P#Q15.0 p#DB1.DBX32.0 //用寄存器表达时的表达格式: 访问宽度[ARx,偏移] //如M区的区域间间接寻址 L P#M20.0 LAR1 //把地址从ACCU1装载到AR1中 L 1234 T W[AR1,P#2.0] //如I区的区域间间接寻址 L P#I0.0 LAR2 L W[AR2,P#0.0] T MW0
- 存储器间接寻址:
-
Pointer数据类型
- 长度6个字节,由
WORD + DWORD
得来- Pointer中的WORD表达了数据区:(比如B#16#81表示I区,B#16#82表示Q区,B#16#84表示DB区...)
- Pointer中的DWORD表达的内容和
区域内间接寻址
中的32位指针表达的内容一致。
- 长度6个字节,由
-
ANY数据类型
- 长度10个字节,由原来Pointer(举例中是P#DB1.DBX0.0)的基础上加上了两个WORD,其中较高位表示了数据类型(举例中是BYTE),较地位表示了数据长度(举例中是 100),表达方式:
P#DB1.DBX0.0 BYTE 100
。
- 长度10个字节,由原来Pointer(举例中是P#DB1.DBX0.0)的基础上加上了两个WORD,其中较高位表示了数据类型(举例中是BYTE),较地位表示了数据长度(举例中是 100),表达方式:
寻址方式举例
//直接寻址:
//绝对地址寻址:
A I4.0
L IW10
//符号地址寻址:
A "Motor_On"
L #Num
//间接寻址:
//存储器间接寻址:
//16位指针:
OPN DB[MW10]
SP T["runtime"]
//32位指针:
A I[MD30]
L IW["Number"]
//寄存器间接寻找:
//32位指针区域内间接寻址:
A I[AR1,P#0.0]
L ID[AR1,P#5.0]
//32位指针区域间间接寻址:
A [AR1,P#0.0]
T W[AR1,P#0.0]
间接寻址在实际中的应用
- 给数组批量赋值:
1--MW298作为一个16位地址指针来用,对于16位地址指针而言,直接用int数,不需要也不存在表达成p#..的情况。
2--打开DB用的OPN DB
,如果同时想打开两个DB块的话,另一个DB使用OPN DI
指令。
3--对于双字指针(32位地址指针),这里直接取的P#4.0
,如果使用的常数比如L 4
,这个时候切记需要使用左移指令SLD,再存入一个DWORD类型的变量中。
4--STL中的循环为NEXT..LOOP NEXT
,使用方法很简单:在第一次循环的时候把100给到MW296作为最大循环次数,在循环体结束时又再次装载MW296到累加器1,LOOP NEXT会自动把MW296的值减1,然后继续下次循环直到MW296的值等于0。整个循环过程在一个扫描周期内完成。
5--在循环体内,完成了地址的相加,做到了数组的批量赋值,地址的相加始终应该以P#Byte.bit
形式运算。