西门子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位指针表达的内容一致。
  • ANY数据类型

    • 长度10个字节,由原来Pointer(举例中是P#DB1.DBX0.0)的基础上加上了两个WORD,其中较高位表示了数据类型(举例中是BYTE),较地位表示了数据长度(举例中是 100),表达方式:P#DB1.DBX0.0 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形式运算。

posted @ 2024-12-20 16:35  不愿透露姓名的小村村  阅读(159)  评论(0编辑  收藏  举报