Modbus地址的那个”5位数地址”
第一次打开 Modbus Poll 调试,看到地址栏里要填 40001,可能会懵。
这串数字是什么意思?为什么是 5 位数?为什么有时候又是 30001、10001?
一、5位数 = 区号 + 序号
Modbus 的地址看着吓人,其实拆开看特别简单:首位数字 + 后四位数字。
首位数字是”区号”,告诉你这数据是什么类型、能不能写。Modbus 把数据切成 4 个独立的区:
0xxxx—— 线圈(Coils),1 位的开关量,能读能写。控制继电器吸合、电机启停,就找它。1xxxx—— 离散输入(Discrete Inputs),1 位开关量,只读。读按钮有没有按下、传感器有没有触发。3xxxx—— 输入寄存器(Input Registers),16 位数值,只读。温度、压力、电流这种实时采集的模拟量。4xxxx—— 保持寄存器(Holding Registers),16 位数值,能读能写。设定值、PID 参数、目标转速这类。
后四位就是序号了。40001 就是”保持寄存器区的第 1 个”,40010 就是第 10 个。
我整理了一张表,自己用的,贴上来:
| 逻辑地址范围 | 数据类型 | 长度 | 权限 | 典型用途 |
|---|---|---|---|---|
| 00001-09999 | 线圈 | 1位 | 读/写 | 继电器、指示灯、电机启停 |
| 10001-19999 | 离散输入 | 1位 | 只读 | 按钮、限位开关、传感器状态 |
| 30001-39999 | 输入寄存器 | 16位 | 只读 | 实时温度、压力、流量 |
| 40001-49999 | 保持寄存器 | 16位 | 读/写 | 设定温度、修改参数、目标转速 |
记住这张表,后面所有的坑都是从这四个区衍生出来的。
二、那个让我骂街的坑:逻辑地址 vs 协议地址
这是整篇文章最关键的一段,也是我浪费最多时间的地方。
你在手册里、在配置软件里看到的 40001,叫逻辑地址,是给人看的,带区号、从 1 开始数。但 Modbus 真正发出去的报文里,根本没有 40001 这个数。
协议里用的是协议地址,从 0 开始数,而且不带区号——区号在功能码里已经隐含了(03H 本身就意味着”我要操作的是保持寄存器”)。
换算就是两步:
- 把区号剥掉:
40001→ 后四位0001 - 减 1(因为对协议来说”第 1 个”就是偏移 0):
0001 - 1 = 0
所以:
- 读
40001→ 报文里起始地址填0 - 读
40010→ 报文里起始地址填9 - 读
40100→ 报文里起始地址填99
线圈(0xxxx)也一样的路数:逻辑地址 00001 → 剥区号 0001 → 减 1 → 协议地址 0。输入寄存器(3xxxx)同理:30001 → 协议地址 0。
我当时就是不知道这个,手册上写 40001,我在 Modbus Poll 里也填 40001,结果设备要么不回,要么回一堆乱码。后来把地址改成 0,数据”啪”地一下就回来了。那一刻我真想给发明这套规则的人写封感谢信。
⚡ 避坑提醒:不同软件/库让你填的到底是逻辑地址还是协议偏移地址,一定要看文档:
- Modbus Poll:默认让你填逻辑地址(直接输
40001),内部自动换算。- NModbus(C# 库):
ReadHoldingRegisters(0, 10)里第一个参数是协议偏移,填0才是读40001。- Python minimalmodbus:
read_register(0)里的0也是偏移地址。- 有些国产调试软件(特别是串口助手类的)又让你填逻辑地址……
每次接手新工具,先发一帧已知的报文验证一下。 搞混了就是一场灾难。
三、40001 里到底存了什么?——答案是:看厂家
这个也是新手容易卡的地方。你以为 40001 是个标准,全世界都一样?不是的。
Modbus 协议只管”数据怎么传”,不管数据是什么。40001 里装什么,完全是设备厂家自己定的:
- A 厂家的温控表,
40001可能是”当前温度”。 - B 厂家的变频器,
40001可能是”运行频率”。 - C 厂家的电表,
40001和40002连起来才是一个完整的 32 位浮点电压值(因为 float 占 4 字节 = 2 个 16 位寄存器)。
所以拿到一个新设备,第一件事不是写代码,是翻它附带的《Modbus 寄存器地址映射表》。没有这张表,你连读哪个地址都不知道。我手头有一块老电表,厂家倒闭了,文档丢了,那块表现在就只能当砖头用。
补充一嘴:3 区和 4 区有时候是一回事
Modbus 标准里,3xxxx(输入寄存器)和 4xxxx(保持寄存器)是两个独立的编号空间。但在实际设备里,很多厂家把它们映射到同一块物理内存——也就是说,你用 03H 读 40001 和用 04H 读 30001,拿到的可能是同一个值。
这不算”违规”,因为协议没禁止这种映射。只有一种情况你需要注意区分:要写数据的时候,一定走 4 区。 3 区从协议角度就是只读的,04H 写完不会有响应(协议根本不支持用 04H 写)。
🔧 小贴士:拿到一个新设备不确定它的地址映射时,开 Modbus Poll,用 03H 从地址 0 开始,一次读 100 个寄存器。看哪些地址返回了数据、哪些报了 02H 异常(地址非法)。两分钟就能把它的寄存器范围摸个大概。这对没有完整文档的老设备尤其管用。
四、最后说几句
理清这三件事——四个区怎么分、逻辑地址怎么换算、地址内容谁说了算——Modbus 调试的 80% 就拿下了。
剩下的 20% 是字节序、异常码、浮点数解析这些细节,后面单独写一篇聊。
说真的,Modbus 这协议 1979 年生的,比我年纪还大,到现在还在工业现场遍地跑,靠的就是它简单、开放、不要钱。但也正因为简单,它把”怎么用”的活儿全甩给了开发者——包括这套让人头大的地址规则。
下次再看到 40001,别慌,它就是个带区号的门牌号而已。
