2. Modicon 数据对象与地址体系

在 Modicon(现施耐德电气 Modbus 体系)的世界里,上位机要读到一个 PLC 内部变量,必须先回答两个问题:这个变量属于哪一类数据对象?它在协议报文里用什么地址去访问?前者决定语义(是开关量还是数值、是只读还是可写),后者决定报文中的功能码与偏移量。理解这两层映射,是后续用 Modbus 采集数据、排查“读不到/读错位”问题的根基。

四类基本数据对象

Modicon 把可访问的数据按“位/字”和“只读/可读写”两个维度切成四个区,这是整个地址体系的骨架:

  • 线圈(Coil,0x 区):可读可写的单比特输出量,对应 PLC 内部位变量或实际数字量输出(如继电器、指示灯)。上位机可置位/复位。
  • 离散输入(Discrete Input,1x 区):只读单比特输入量,对应实际数字量输入(如按钮、限位开关)。上位机只能读,不能写。
  • 输入寄存器(Input Register,3x 区):只读 16 位字,通常存放模拟量采集值、状态字、只读测量量。
  • 保持寄存器(Holding Register,4x 区):可读可写 16 位字,是最常用的数据区,用于存放设定值、控制字、配方参数、需要下发的数值。

记忆口诀是“0 线圈、1 离散、3 输入、4 保持”,其中 0 和 1 是位对象,3 和 4 是字对象。注意:这里的 0x/1x/3x/4x 是传统 Modicon 参考号,不是报文里真正发送的数值,二者之间还差一次映射。

参考号、协议地址与偏移量

Modbus 报文(PDU)里并不携带“40001”这样的参考号,它只携带功能码 + 起始地址 + 数量。以保持寄存器为例,功能码 0x03(读保持寄存器)的报文地址字段是从 0 开始计数的偏移量。因此存在一条关键换算关系:

协议地址(PDU 偏移)= 参考号 − 区基址
保持寄存器:40001 → 偏移 0;40002 → 偏移 1;40100 → 偏移 99
线圈:00001 → 偏移 0;离散输入:10001 → 偏移 0;输入寄存器:30001 → 偏移 0

很多上位机软件(组态王、Kepware、PLC 触摸屏)在界面上让你填“40001”或“4x:1”,内部会自动减 1 再发报文;而有些库(如 pymodbus、libmodbus)直接要求填偏移量 0。这就是“地址差 1”问题最常见的来源——把参考号当偏移量直接发出去,结果整体错位一个寄存器。

地址映射关系图解

下图把四类数据对象、参考号区间、功能码与协议偏移量的对应关系放在一张图里,便于对照查阅:

Modicon 四类数据对象与地址映射 数据对象 参考号区间 功能码 协议偏移量(PDU) 线圈 Coil 可读可写 · 位 00001 ~ 09999 0x 区 0x01 读线圈 0x05 写单线圈 0x0F 写多线圈 00001 → 偏移 0 00010 → 偏移 9 离散输入 只读 · 位 10001 ~ 19999 1x 区 0x02 读离散输入 (无写功能码) 10001 → 偏移 0 10008 → 偏移 7 输入寄存器 只读 · 16 位字 30001 ~ 39999 3x 区 0x04 读输入寄存器 (无写功能码) 30001 → 偏移 0 30005 → 偏移 4 保持寄存器 可读可写 · 16 位字 40001 ~ 49999 4x 区 0x03 读保持寄存器 0x06 写单寄存器 0x10 写多寄存器 40001 → 偏移 0 40100 → 偏移 99 换算规则:协议偏移量 = 参考号 − 区基址(0x/1x 基址 1,3x/4x 基址 1,均从 1 开始编号)

寻址方式与常见误区

实际工程中,寻址方式取决于上位机/库的约定,常见三种写法:

  1. 参考号写法:直接写 40001、10001,软件自动换算。组态软件、部分 PLC 编程软件采用这种。
  2. 区号 + 偏移写法:如 “4x:0” 或 “HR:0”,表示保持寄存器偏移 0,即 40001。Kepware、部分 OPC 服务器采用。
  3. 纯偏移写法:直接写 0、1、99,配合功能码使用。pymodbus、libmodbus 等代码库采用这种。

最容易踩的坑有三个:其一,把 40001 直接当偏移 0 发送,导致读到的数据整体后移一位;其二,混淆 3x 与 4x,用 0x03 去读输入寄存器,PLC 返回异常码 0x02(非法数据地址);其三,忽略寄存器数量上限,一次读超过 125 个保持寄存器(0x03 上限)或 2000 个线圈(0x01 上限),PLC 会拒绝或分帧。

判断地址是否正确的实用方法:先读一个已知值的寄存器(如 PLC 中固定写入 1234 的 40001),确认读回值正确后,再按偏移量推算其他地址。若读回值整体错位,优先检查是否多减/少减了 1。

数据类型与字节序

四类对象中,位对象直接对应 0/1;字对象是 16 位,但实际工程中常需要 32 位整数、浮点数。此时需要把两个连续寄存器拼起来,并处理字节序。Modbus 标准规定寄存器内高字节在前(大端),但 32 位数据存在四种常见排列:

排列方式寄存器顺序字节顺序典型设备
ABCD高字在前高字节在前多数 Modicon/施耐德
CDAB低字在前高字节在前部分仪表
BADC高字在前低字节在前部分西门子网关
DCBA低字在前低字节在前部分国产仪表

例如把 40001、40002 拼成 32 位整数,若 40001=0x0001、40002=0x0002,按 ABCD 排列结果为 0x00010002=65538;按 CDAB 排列则为 0x00020001=131073。上位机若字节序设错,读到的数值会完全不对,但寄存器地址本身没错——这是排障时要区分开的两类问题。

不要用“读到的值不对”直接判定地址错误。先确认地址偏移是否正确,再确认数据类型与字节序是否匹配,最后才怀疑 PLC 内部变量是否真的被写入。三步分开验证,能大幅缩短排障时间。

小结与实操建议