ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Modbus地址规则详解:从协议地址到PLC地址的完整映射指南

Modbus地址规则详解:从协议地址到PLC地址的完整映射指南 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的保持寄存器功能码选03Address填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里功能码选03Address填0Quantity填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就对应VW040002对应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选03Address填0Quantity填1。读设定值Function选03Address填1。读运行状态Function选01Address填0。写启停控制Function选05Address填1Value填1或0。7.2 读不到数据时的排查顺序如果按上面的配置读不到数据按这个顺序排查物理连接RS485的A/B线有没有接反终端电阻有没有接网线通不通这是最基础也最容易忽略的。通信参数波特率、数据位、停止位、校验位是否和设备一致Modbus RTU常见的是9600-8-N-1或19200-8-E-1不一致就通不上。站号Slave ID是否和设备站号一致有的设备站号是拨码开关设置的要看实际拨码。功能码设备是否支持该功能码有些设备只支持03和06不支持01和05。地址地址是否超出范围是否减1了数据类型是否匹配字节序读到的值是否明显不对切换字节序试试。这个顺序是从底层到上层先确保物理层通再查协议层。很多新手一上来就怀疑地址结果查了半天发现是线接反了。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这些变种都会轻松很多。因为不管传输层怎么变数据模型和地址规则是不变的。
返回列表