☰
Modbus地址规则详解:从协议地址到PLC地址的完整映射指南
2026/10/7 13:08:32 网站建设 项目流程

1. 从一次现场调试的困惑说起:为什么地址对不上

很多刚接触工控的朋友都有过这种经历:PLC程序里明明写了读取40001寄存器,上位机也配置了40001,但数据就是读不上来,要么返回错误码,要么读到的值完全不对。更让人抓狂的是,换一个厂家的设备,同样的地址写法又突然好使了。这时候你上网搜,会看到一堆说法——“40001对应地址0”“30001是输入寄存器”“线圈从00001开始”,看完更晕了。

这个问题的根源在于:Modbus协议本身定义的地址空间,和工程软件里让你填的“地址”,压根不是同一套编号体系。协议里说的是“从0开始的偏移量”,而工程习惯里用的是“从1开始的寄存器编号”,中间还夹着一层功能码的区分。这三层东西混在一起,就成了新手最容易踩的坑。

这篇内容就是把这个坑彻底填平。我会从Modbus的四种数据模型讲起,把协议地址、PLC地址、软件配置地址三者的对应关系掰开揉碎,再结合Modbus Poll、Modbus Slave这些常用工具的实际配置界面,告诉你每个格子里到底该填什么。不管你是用西门子、三菱、汇川还是国产小众PLC,只要涉及Modbus RTU或Modbus TCP,这套规则都是通用的。看完之后,你拿到任何一个Modbus设备的地址表,都能自己推算出软件里该填的数字,不用再靠猜。

2. Modbus的四种数据模型:先搞清楚你在操作什么

2.1 线圈和寄存器不是一回事,别混着用

Modbus协议把设备里的数据分成四大类,这个分类是所有地址规则的根基。很多人一上来就记地址编号,却不知道编号背后的数据类型,结果就是功能码选错、地址填错,怎么调都不通。

第一类是线圈(Coil),英文叫Coil,有的文档翻译成“输出线圈”或“数字输出”。它是最简单的数据类型,每个线圈只有两种状态:ON或OFF,对应二进制的1和0。你可以把它理解成继电器的一个触点,要么吸合要么断开。线圈是可读可写的,上位机可以发命令让设备把某个线圈置1或清0,也可以读回当前状态。典型应用就是控制灯的开灭、阀门的开关、电机的启停。

第二类是离散输入(Discrete Input),有的叫“输入状态”或“数字输入”。它和线圈一样,也是1位数据,只有ON/OFF两种状态。区别在于离散输入是只读的,上位机只能读,不能写。它对应的是物理输入点的状态,比如按钮按没按、限位开关通没通、传感器有没有信号。你没法通过Modbus去“写”一个离散输入,因为它的状态由现场物理信号决定。

第三类是保持寄存器(Holding Register),这是实际项目里用得最多的一类。它是16位数据,可以存0到65535的整数,也可以两个寄存器拼起来存32位整数或浮点数。保持寄存器是可读可写的,上位机可以读当前值,也可以写新值进去。PLC里的设定值、PID参数、配方数据、累计产量,基本都放在保持寄存器里。

第四类是输入寄存器(Input Register),同样是16位数据,但它是只读的。它通常用来存放模拟量采集值,比如温度、压力、流量这些传感器读上来的实时数据。设备厂家把采集到的模拟量放进输入寄存器,上位机只能读,不能改。

这四类数据在协议里是独立编址的,也就是说线圈0和保持寄存器0是两个完全不同的东西,互不干扰。你在软件里填地址的时候,必须先确定自己要操作的是哪一类,再去查对应的地址范围。

2.2 功能码决定了你能干什么

Modbus用功能码来区分操作类型。常用的功能码有这么几个:

功能码操作数据类型读写属性
01读线圈线圈读
02读离散输入离散输入读
03读保持寄存器保持寄存器读
04读输入寄存器输入寄存器读
05写单个线圈线圈写
06写单个保持寄存器保持寄存器写
15写多个线圈线圈写
16写多个保持寄存器保持寄存器写

功能码和数据类型是一一对应的。你选了功能码03,就只能读保持寄存器,不能读线圈。很多调试工具会让你先选功能码,再填地址,这时候地址的含义就由功能码决定了。比如在Modbus Poll里,你选03功能码,地址填0,读的就是保持寄存器的第一个寄存器;你选01功能码,地址填0,读的就是第一个线圈。同样是填0,读的东西完全不一样。

这里有个容易忽略的点:功能码05和06是写单个,15和16是写多个。有些老设备只支持单个写,你用15或16去写就会报错。反过来,有些设备只支持多个写,你用05或06也会失败。调试的时候如果写不进去,先确认设备手册里支持哪些功能码。

2.3 协议地址从0开始,工程地址从1开始

这是整个地址规则里最核心、也最容易搞混的一点。

Modbus协议报文里,地址字段是一个16位无符号整数,范围是0到65535。协议规定,报文中传输的地址是从0开始的偏移量。也就是说,你要读第一个保持寄存器,报文里的地址字段填0;读第二个,填1;读第100个,填99。

但是,工程上为了方便人看,习惯用“从1开始”的编号。第一个保持寄存器叫40001,第二个叫40002,第100个叫40100。这个编号规则是Modbus传统里留下来的,叫“Modicon编号”或“PLC地址”。

所以就有了这个经典换算关系:

软件里填的协议地址 = 工程编号去掉前缀后的数字 - 1

比如你要读40001,去掉前缀4,得到1,再减1,协议地址就是0。你要读40100,去掉前缀4,得到100,减1,协议地址是99。

这个减1的操作,就是无数新手翻车的地方。很多软件界面上写的是“Address”,但没告诉你它要的是协议地址还是工程编号。有的软件很贴心,直接让你填40001,内部自动减1;有的软件要你填0,它发出去的报文地址就是0。你填错了,读到的就是隔壁寄存器的值,或者直接报非法地址错误。

3. 四类地址的编号规则与常见误区

3.1 线圈和离散输入:0xxxx和1xxxx

线圈的工程编号从00001开始,范围通常是00001到09999。离散输入的工程编号从10001开始,范围是10001到19999。这两个都是1位数据,编号前缀分别是0和1。

在协议层面,线圈的地址范围是0到9998(对应00001到09999),离散输入的地址范围也是0到9998(对应10001到19999)。注意,虽然工程编号上前缀不同,但在协议报文里,线圈和离散输入是各自独立编址的,都从0开始。你发功能码01读线圈,地址填0,读的是第一个线圈;你发功能码02读离散输入,地址填0,读的是第一个离散输入。两者互不影响。

这里有个常见的误解:有人以为离散输入的协议地址是从10000开始的。不是的。协议里没有10000这个偏移,离散输入的协议地址也是从0开始。10001只是工程编号,去掉前缀1再减1,得到0。

3.2 保持寄存器:4xxxx的两种编号体系

保持寄存器的工程编号从40001开始,这是最常用的。但这里有一个历史遗留问题:早期的Modicon PLC把保持寄存器分成两类,一类是40001到49999,另一类是400001到465535。前者是5位编号,后者是6位编号。现在大部分设备用的是5位编号,也就是40001到49999,对应协议地址0到9998。

但有些老设备或特殊设备会用6位编号,比如400001对应协议地址0。这时候你看到地址表里写的是400001,就要注意了,它可能不是笔误,而是6位编号体系。判断方法很简单:看地址表里最大的编号是多少。如果最大到49999,就是5位体系;如果最大到465535,就是6位体系。

另外,有些厂家在文档里不写4xxxx,直接写“寄存器地址0”“寄存器地址1”,这时候它说的就是协议地址,你直接填0、1就行,不用减1。所以拿到地址表的第一件事,是确认它用的是哪种编号体系。

3.3 输入寄存器:3xxxx的只读区域

输入寄存器的工程编号从30001开始,范围是30001到39999,对应协议地址0到9998。它和保持寄存器一样是16位数据,但只读。模拟量采集值通常放在这里。

有个坑要注意:有些设备把模拟量放在保持寄存器里,而不是输入寄存器。这时候你用功能码04去读输入寄存器,读不到东西;要用功能码03去读保持寄存器。反过来,有些设备把设定值放在输入寄存器里(虽然协议规定输入寄存器只读,但有些厂家会这么做),你用功能码03去读保持寄存器也读不到。所以调试的时候,如果读不到数据,先确认设备手册里这个数据到底放在哪类寄存器里。

3.4 地址偏移的边界:别超出设备实际范围

协议地址范围是0到65535,但实际设备不可能有这么多寄存器。一般PLC的保持寄存器也就几百到几千个,线圈也是几百个。你填的地址如果超出了设备实际支持的范围,设备会返回异常码02(非法数据地址)。

比如设备只有100个保持寄存器,协议地址0到99。你填100,设备就报错。这时候你要查设备手册,确认它的寄存器数量。有些设备手册里写的是“保持寄存器40001到40100”,那就是100个,协议地址0到99。你填99可以,填100就报错。

还有一个边界情况:读多个寄存器的时候,起始地址加上数量不能超出范围。比如设备有100个寄存器,你从地址99开始读10个,就会读到地址99到108,其中100到108超出范围,设备会报错。所以读多个的时候,要确保起始地址加数量减1不超过最大地址。

4. 用Modbus Poll和Modbus Slave实测地址对应关系

4.1 Modbus Poll里填的到底是什么地址

Modbus Poll是调试Modbus最常用的工具之一。打开软件,点“Setup”里的“Read/Write Definition”,会弹出一个对话框。里面有几个关键字段:

  • Slave ID:从站地址,就是设备的站号。
  • Function:功能码,选01、02、03、04等。
  • Address:地址,这里填的是协议地址,从0开始。
  • Quantity:读取数量。
  • Scan Rate:扫描周期。

重点看Address这个字段。如果你要读工程编号40001的保持寄存器,功能码选03,Address填0。如果你填1,读到的就是40002。软件界面上不会帮你自动减1,你得自己算好。

但有些版本的Modbus Poll在Address旁边有个小提示,或者你可以右键选择“PLC Addresses (Base 1)”,这时候填1就对应40001。这个选项在不同版本里位置可能不一样,但逻辑是一样的:Base 0就是协议地址,Base 1就是工程编号。我个人的习惯是统一用Base 0,自己心里清楚减1的规则,这样换任何软件都不会乱。

4.2 Modbus Slave模拟从站时的地址设置

Modbus Slave是用来模拟从站设备的。你可以在里面定义寄存器、线圈,然后让Modbus Poll去读。设置的时候,同样要选功能码和起始地址。

比如你要模拟一个设备,有10个保持寄存器,工程编号40001到40010。在Modbus Slave里,功能码选03,Address填0,Quantity填10。然后你可以在表格里看到10行数据,第一行对应协议地址0,也就是40001。你改第一行的值,Modbus Poll读40001就能看到变化。

这里有个实用技巧:用Modbus Slave配合Modbus Poll,可以快速验证地址换算对不对。你先在Slave里把地址0的值设成一个特殊数字,比如12345,然后在Poll里用不同的地址去读,看哪个地址能读到12345。这样就能反推出正确的地址偏移。这个方法在调试陌生设备时特别管用,因为你可以控制从站的行为,排除设备本身的干扰。

4.3 用错误码反推地址问题

Modbus的错误码是调试的好帮手。常见的和地址相关的错误码有:

错误码含义可能原因
02非法数据地址地址超出设备支持范围,或数据类型不对
03非法数据值写入的值超出范围
01非法功能码设备不支持该功能码
04从站设备故障设备内部错误

如果你看到错误码02,基本可以确定是地址问题。这时候先检查:地址是不是超出了设备手册里写的范围?功能码和数据类型是不是匹配?比如你用功能码03去读输入寄存器的地址,设备可能报02,因为保持寄存器里没有那个地址。

错误码9003这个热搜词,其实不是标准Modbus错误码。标准错误码是1到4,加上128后的异常响应。9003可能是某个特定软件或设备的自定义错误码,比如连接超时、校验错误之类的。遇到这种非标准错误码,查设备手册或软件帮助文档更靠谱。

5. 不同PLC品牌的地址写法差异

5.1 西门子PLC的Modbus地址映射

西门子S7-200 SMART和S7-1200/1500支持Modbus通信,但地址映射有自己的规则。以S7-200 SMART为例,它作为Modbus从站时,保持寄存器对应V存储区。你在Modbus地址表里看到的40001,可能对应VW0或VW2,具体要看组态时的映射设置。

西门子的Modbus库指令里,通常有一个参数叫“HoldStart”,指定保持寄存器的起始地址。比如你设HoldStart为&VB0,那么Modbus地址40001就对应VW0,40002对应VW2(因为VW是16位,占两个字节)。这里要注意字节和字的区别,别把VW和VB搞混了。

S7-1200/1500用MB_SERVER指令做从站时,需要配置“MB_HOLD_REG”参数,指向一个DB块或M区。地址映射关系在指令的背景数据块里可以查到。西门子的文档写得比较清楚,但第一次配置的时候容易在数据长度和字节序上出错。

5.2 三菱FX系列和Modbus RTU

三菱FX系列PLC加485扩展板后,可以通过Modbus RTU协议通信。FX5U自带Modbus TCP主站功能,配置起来更方便。三菱的地址写法是D寄存器、M继电器这些,和Modbus的4xxxx、0xxxx不是一一对应的,需要做映射。

比如FX5U做Modbus TCP主站时,你要读从站的40001,在指令里填的可能是“40001”或者“0”,取决于指令的参数定义。三菱的Modbus指令通常有“起始地址”和“数量”两个参数,起始地址填的是协议地址还是工程编号,要看指令手册。我遇到过有的指令要填0,有的要填1,不统一。所以换品牌的时候,第一件事就是翻手册确认地址基准。

5.3 国产PLC和仪表的地址表解读

国产PLC和仪表的Modbus地址表通常比较直接,但格式五花八门。有的写“寄存器地址:0000H”,这是十六进制的协议地址;有的写“40001”,这是工程编号;有的写“保持寄存器1”,这是从1开始的序号。

解读的时候,先看有没有“H”后缀,有就是十六进制。再看数字范围,40001到49999是5位工程编号,0到9998是协议地址。如果写的是“1”,那可能是工程编号的第1个,对应协议地址0。如果写的是“0”,那就是协议地址0。

最稳妥的办法是拿Modbus Poll去试。先按最可能的解释填一个地址,读一下,看返回值对不对。如果不对,换另一种解释再试。试的时候一次只改一个变量,别同时改功能码和地址,不然出了错不知道是哪个的问题。

6. 地址计算中的字节序和数据类型陷阱

6.1 16位数据的高低字节顺序

Modbus寄存器是16位的,但传输的时候是两个字节。这两个字节谁先谁后,就是字节序问题。Modbus协议规定,报文中的寄存器数据是大端序,也就是高字节在前,低字节在后。比如寄存器值0x1234,传输时先发0x12,再发0x34。

但有些设备内部是小端序,或者软件解析的时候用了小端序,就会导致读到的值变成0x3412。这时候你看到的数据就是错的,但不是地址问题,是字节序问题。解决方法是看设备手册里有没有字节序说明,或者在软件里找“Swap”或“Byte Order”选项,切换一下试试。

6.2 32位数据的寄存器组合方式

如果要读32位整数或浮点数,需要两个连续的寄存器。这两个寄存器谁是高16位、谁是小16位,也有不同约定。常见的有:

  • 高字在前:第一个寄存器是高16位,第二个是低16位。
  • 低字在前:第一个寄存器是低16位,第二个是高16位。

比如浮点数1.0的IEEE 754表示是0x3F800000。高字在前的话,寄存器0是0x3F80,寄存器1是0x0000;低字在前的话,寄存器0是0x0000,寄存器1是0x3F80。你读到的两个寄存器值一样,但组合方式不同,解析出来的浮点数就完全不同。

调试的时候,如果读到的浮点数明显不对(比如变成几万或几亿),先检查寄存器组合方式。很多Modbus调试工具支持直接显示浮点数,但需要你选对“Data Format”和“Register Order”。

6.3 地址对齐和批量读取的注意事项

读多个寄存器的时候,起始地址和数量要合理。有些设备要求起始地址必须是偶数,或者读取数量必须是偶数,这是地址对齐的要求。比如你要读40001到40010,起始地址0,数量10,没问题。但如果你从40002开始读9个,起始地址1,数量9,有些设备可能报错。

批量读取的时候,尽量一次读连续的寄存器,减少通信次数。但也不要一次读太多,有些设备对单次读取数量有限制,比如最多读125个寄存器。超过限制会报错。一般一次读几十个比较稳妥,既不会太慢,也不会触发限制。

7. 调试实战:从地址表到软件配置的完整流程

7.1 拿到地址表后的第一步:确认编号体系

假设你拿到一份设备地址表,上面写着:

参数名地址数据类型读写
温度4000116位整数只读
设定值4000216位整数读写
运行状态00001布尔只读
启停控制00002布尔读写

第一步,确认编号体系。40001和40002是5位工程编号,对应协议地址0和1。00001和00002是线圈工程编号,对应协议地址0和1。

第二步,确认功能码。温度是只读的保持寄存器,用功能码03读,地址0。设定值是读写保持寄存器,读用03地址1,写用06地址1。运行状态是只读线圈,用功能码01读,地址0。启停控制是读写线圈,读用01地址1,写用05地址1。

第三步,在Modbus Poll里配置。读温度:Slave ID填设备站号,Function选03,Address填0,Quantity填1。读设定值:Function选03,Address填1。读运行状态:Function选01,Address填0。写启停控制:Function选05,Address填1,Value填1或0。

7.2 读不到数据时的排查顺序

如果按上面的配置读不到数据,按这个顺序排查:

  1. 物理连接:RS485的A/B线有没有接反?终端电阻有没有接?网线通不通?这是最基础也最容易忽略的。
  2. 通信参数:波特率、数据位、停止位、校验位是否和设备一致?Modbus RTU常见的是9600-8-N-1或19200-8-E-1,不一致就通不上。
  3. 站号:Slave ID是否和设备站号一致?有的设备站号是拨码开关设置的,要看实际拨码。
  4. 功能码:设备是否支持该功能码?有些设备只支持03和06,不支持01和05。
  5. 地址:地址是否超出范围?是否减1了?数据类型是否匹配?
  6. 字节序:读到的值是否明显不对?切换字节序试试。

这个顺序是从底层到上层,先确保物理层通,再查协议层。很多新手一上来就怀疑地址,结果查了半天发现是线接反了。

7.3 用Modbus Scan快速摸清设备地址

Modbus Scan是一个扫描工具,可以自动遍历地址范围,找出设备实际响应的地址。当你没有设备地址表,或者地址表不准的时候,这个工具特别好用。

用法很简单:设置好通信参数和站号,选功能码,设定起始地址和结束地址,点扫描。工具会逐个地址去读,把能读到的地址和值列出来。你可以根据读到的值反推这是什么数据。比如扫描保持寄存器0到100,发现地址0的值是25,地址1的值是60,结合设备是温控器,可能25是当前温度,60是设定温度。

扫描的时候注意,不要扫太快,有些设备响应慢,扫太快会漏掉。也不要扫太大范围,65536个地址全扫一遍要很久。一般先扫0到200,覆盖大部分常用地址。

8. 几个容易踩的坑和我的实操心得

8.1 地址减1不是绝对的,要看软件定义

前面说了协议地址从0开始,工程编号从1开始,所以软件里填协议地址时要减1。但这不是绝对的。有些软件界面上写的是“Address”,但它内部已经帮你减了1,你填1它就发0。有些软件写的是“Register”,要你填工程编号,你填40001它自动转成0。

判断方法:看软件帮助文档,或者用Modbus Slave做对照实验。你在Slave里把地址0设成特殊值,然后在Poll里填不同的地址去读,看填哪个能读到。这个方法最可靠,比看文档还准。

8.2 线圈和寄存器的地址是独立的,别串了

线圈地址0和保持寄存器地址0是两个不同的东西。你在Modbus Poll里选功能码01读地址0,读的是线圈;选功能码03读地址0,读的是保持寄存器。两者互不干扰。但有些设备的地址表里,线圈和寄存器用了同一套编号,比如线圈00001和寄存器40001,这时候你要看清楚数据类型,别用错功能码。

我遇到过一种情况:设备手册里写“地址0:运行状态”,没写是线圈还是寄存器。我用功能码03去读,读不到;换成01,读到了。所以地址表里没写数据类型的时候,两种都试试,看哪个能通。

8.3 批量读取时地址溢出的问题

读多个寄存器的时候,起始地址加数量不能超过设备支持的最大地址。比如设备有100个保持寄存器,协议地址0到99。你从地址95开始读10个,就会读到95到104,其中100到104超出范围,设备报错。

解决办法是分段读。先读95到99,再读0到4(如果允许回绕的话),或者调整起始地址,确保不超出范围。有些设备支持回绕读取,地址超过最大值后自动回到0,但这不是标准行为,不要依赖。

8.4 不同软件的地址基准不一样,换软件要重新确认

Modbus Poll用协议地址,Modbus Slave也用协议地址,但有些组态软件(比如组态王、力控)可能用工程编号。你在Modbus Poll里填0能读到的,在组态王里可能要填40001。换软件的时候,第一件事就是确认它的地址基准。

我的习惯是:不管用什么软件,先在Modbus Poll里把地址确认好,记下协议地址。然后在其他软件里,如果它要工程编号,就加1再加前缀;如果它要协议地址,就直接填。这样就不会乱。

8.5 浮点数读取的寄存器顺序要试

读浮点数的时候,如果读到的值明显不对,先检查寄存器顺序。常见的有ABCD、CDAB、BADC、DCBA四种组合。ABCD是高字在前、高字节在前,CDAB是低字在前、高字节在前,等等。不同设备厂家的约定不同,试一遍就知道了。

试的时候,写一个已知的浮点数到设备里(如果可写),然后读回来,看哪种组合能还原。如果设备只读,就找一个已知的物理量,比如温度25.5度,看哪种组合能解析出25.5。

8.6 地址表里的“保留”地址别乱用

有些地址表里会标注“保留”或“Reserved”,这些地址不要用。它们可能是厂家内部使用的,或者未来扩展用的。你写了值进去,可能没效果,也可能导致设备异常。只用地址表里明确标注了功能的地址。

8.7 调试记录要留好

每次调试,把站号、通信参数、功能码、地址、字节序这些信息记下来。下次再调同样的设备,直接翻记录,不用重新试。我见过太多人调完就忘,下次换个人来调,又从头试一遍,浪费时间。

记录的时候,最好把Modbus Poll的配置文件也保存下来,下次直接加载。Modbus Poll支持保存配置,包括功能码、地址、数量这些,很方便。

9. 从地址规则延伸到协议理解

地址规则看起来是个小问题,但它背后是Modbus协议的设计哲学:简单、分层、可扩展。四种数据模型对应四种功能码,地址从0开始偏移,工程编号从1开始方便人看,这些设计都是为了在简单和实用之间找平衡。

理解了地址规则,你再去看Modbus报文,就能看懂每个字段的含义。比如一个读保持寄存器的请求报文:站号、功能码03、起始地址高字节、起始地址低字节、数量高字节、数量低字节、CRC校验。起始地址字段填的就是协议地址,从0开始。你填40001,报文里就是0;你填40100,报文里就是99。

再进一步,你可以用串口调试助手手动发报文,不用Modbus Poll也能读数据。比如发01 03 00 00 00 01 84 0A,就是读站号1的保持寄存器地址0的1个寄存器。返回01 03 02 00 19 79 84,表示站号1、功能码03、2字节数据、数据值0x0019即25。手动发报文能帮你更深入地理解协议,也能在工具不好用的时候应急。

地址规则是Modbus的入门课,也是基本功。把这套规则吃透,后面学Modbus TCP、Modbus RTU over TCP、Modbus ASCII这些变种,都会轻松很多。因为不管传输层怎么变,数据模型和地址规则是不变的。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询