02-寻址偏移与地址方言


2.2 寻址偏移与地址方言

本节摘要:点表写"40001",报文里却填 0——偏移 1 之差,是 Modbus 现场第一大坑。本节讲清 0-based 与 1-based 两种寻址、PLC 地址方言的换算,以及寄存器内 16 位数据的字节序陷阱。位置:2.1 认识了四类对象,本节处理"地址怎么写才对"。

偏移 1 的战争

Modbus 报文里的寄存器地址是 0 起始的偏移量(0x0000-0xFFFF);而 PLC/组态软件习惯用 1 起始的"40001"式地址。换算规则:

PLC 地址 40001 → 数据模型偏移 0(减 1) PLC 地址 40020 → 偏移 19(减 1) 3x 输入寄存器 30001 → 偏移 0,功能码 04 0x 线圈 00001 → 偏移 0,功能码 01 ​

多数工具(组态软件、调试器)会替你换算,但手写报文或自己写驱动时,偏移差 1 是最常见的"能通但数据全错"的根源:功能码对、校验对、设备也应答了,读回来的却是隔壁寄存器的值——因为它把"读偏移 19"理解成"读第 20 个"。

一个真实点表的方言对照

某电能表点表节选(同一数据,三种写法):

数据 PLC 写法 数据模型偏移 功能码
相电压 A 40001 0 03 读保持
相电流 A 40003 2 03
有功功率 40005 4 03
开关量输入状态 10001 0 02 读离散

注意功率占 2 个寄存器(4、5 两字合成 32 位浮点)——多寄存器数据跨越的地址段要一次读完,否则读到半截值。第 6 章会讲字节序与 32 位数据的完整拼法。

寄存器内 16 位数据的字节序

一个寄存器 16 位 = 2 字节。串口发送时先高字节后低字节(大端,Modbus 默认),但有些设备实现成低字节在前,或 32 位浮点的高低字对调。字节序错误的表现:单寄存器数值离谱(如 1000 变成 7720);32 位浮点完全乱掉。诊断方法:读一个已知值(如额定电压 220),把返回字节按高/低/高字/低字四种组合各解一次,看哪个落在合理范围。

地址方言的完整对照表

把现场最常见的地址写法整理成一张对照表,调试时直接查:

PLC 习惯 Modbus 数据模型 偏移计算 典型功能码
00001 Coil 0 00001-1=0 01 读 / 05 写单 / 15 写多
10001 Discrete Input 0 10001-10001=0 02 读
30001 Input Register 0 30001-30001=0 04 读
40001 Holding Register 0 40001-40001=0 03 读 / 06 写单 / 16 写多
400001 Holding Register 0(扩展 6 位) 400001-400001=0 同上(长地址设备)

注意:3x 与 4x 的"减 1"规则与 0x 相同,都是地址号减 1 得到偏移。有些组态软件的 3x/4x 地址已经内置了减 1,另一些没有——同样的"40001"在不同软件里可能指偏移 0 也可能指偏移 1,跨软件对接时先确认对方的地址口径。

32 位数据:跨寄存器拼装的四种陷阱

超过 16 位的数值(32 位整数、IEEE754 浮点)要占两个寄存器,拼装顺序是现场事故高发区。四种可能的排列:

方案 高字在前/后 高字节在前/后 典型厂商
A 高字在前 高字节在前(大端字大端节) Modbus 规范默认、多数欧洲设备
B 高字在前 低字节在前 部分变送器
C 低字在前 高字节在前 部分国产仪表
D 低字在前 低字节在前(小端字小端节) 部分 PLC 转接实现

诊断口诀:读一个已知的浮点(如 1.0 = 0x3F800000),把收到的 4 字节按 A/B/C/D 各拼一次,落在合理范围的就是正确方案。厂商手册"数据格式"一节通常直接写明,先看手册再调试,能省半天。

偏移对齐的边界用例

点表经常出现"从偏移 0 开始、但 0 号寄存器是保留/版本号"的情况。读连续段时要注意:从保留区开始连续读会把版本号当数据;跨数据类型读(比如 0-1 是版本、2-3 才是温度)会导致解析错位。工程做法:严格按点表定义的"起始偏移 + 长度"分组读,不贪图"从 0 一口气读完"。

易错点补充

  • PLC 程序里的地址与网关映射表不一致:串口转 TCP 网关常做地址重映射,两侧地址表要对齐,否则"上位机读 40001"实际落在设备的另一个寄存器;
  • 把偏移 0 当 40001 直填:直填会整体错一个寄存器,读"设定频率"却拿到"状态字";
  • 浮点跨寄存器读分两次:两次读之间设备可能更新了值,读到的高低字来自不同瞬间,拼出垃圾浮点;必须一次读整段。

易错点清单

  • 手写地址不换算:组态软件里填 40001,自己写驱动时忘了减 1;
  • 32 位数据只读一半:浮点与长整型跨两个寄存器,分两次读会读到瞬态不一致(一边更新一边读);
  • 字节序拿手册当摆设:厂商手册"数据格式"一节通常写明字序与字节序,调试前先读,别靠猜。

要点回顾:报文地址是 0-based 偏移,PLC 习惯地址要减 1;多寄存器数据一次读完;字节序按手册确定并验证。地址方言理清后,下一节实战读一张完整厂商点表。

实战复盘:一个偏移之差让整条产线少读一个寄存器

某水处理项目,PLC 侧点表写"保持寄存器 40001-40010 = 10 台泵的状态",程序里按偏移 0-9 读,一切正常。加装第 11 台泵后,厂商把新泵的状态放在 40011,程序改成读偏移 0-10——结果第 11 台永远读不到。排查发现:厂商点表里的"40011"对应偏移 10,而程序把"数量 11"当成了"读到 40011"(偏移 11),少读了一个。把 PLC 地址当偏移用是这类事故的共性:地址要减 1 才是偏移,数量与末地址不是一回事。

字节序验证的黄金案例

某能源管理项目读三相电表的功率(float32),读回原始字节 00 00 A0 41。按 IEEE754 试解:若按大端字大端节 → 0x0000A041 = 20.0625;若按小端字 → 0x41A00000 = 20.0。电表面板显示 20.0kW,于是确定该表是低字在前(方案 C/D)。把这一结论写进驱动配置后,全厂两百块电表的功率读数全部正确。这个案例说明:一个已知值 + 四种排列试解,比翻遍手册更快确定字序。

作者与出处
原作者:灏天文库
来源:平台策划编纂
整理人: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U