Modbus 从站地址冲突:同一条总线上两个设备同号会怎样

2026-08-31

同一条 RS-485 总线上有两台设备被设成同一个从站地址,主站一发问,两台都认为在叫自己、都开口应答,主站收到的是两帧互相干扰的残骸。这篇只讲这一种成因:怎么把它和”地址根本填错”分开,为什么读冲突和写冲突的后果完全不对称,以及用什么顺序把同号的那两台揪出来。要的是总体排查流程,去看 Modbus 读不到数据的 8 步排查,本文不重复那张清单。

先分清:地址填错和地址冲突,初始现象是一样的

这是这件事最反直觉的地方——地址冲突和地址填错,在主站界面上看到的东西可以完全一致,都是”读取超时”。

地址填错,是主站问的那个号总线上没有任何设备认领,没人应答,主站等到超时。地址冲突,是两台设备同时应答,两个驱动器同时把总线往各自的方向拉,采样出来的字节既不是这台发的、也不是那台发的,整帧 CRC 校验过不去,主站按”没收到合法响应”处理——最终也是超时。

所以区分点不在”现象是什么”,而在改变条件之后现象怎么变

观察地址填错地址冲突
重复读同一地址每次都失败,稳定复现时好时坏,偶尔能收到一帧看似正常的数据
把其中一台设备脱离总线没有变化,照样读不到该地址立刻变得稳定可读
换一个请求内容(读别的寄存器)仍然全无应答成功率可能跟着变,因为响应长度变了
其它地址是否正常其它地址不受影响其它地址不受影响

有一条判据很省事:只要这个地址曾经成功读到过哪怕一次,就基本可以排除”总线上没有这个号的设备”。 没人应答的地址不会偶尔答对,而冲突会。

两台同号的设备在总线上到底发生了什么

Modbus 是主从式协议,主站发起请求、从站响应,从站不会主动上报。RTU 帧的开头就是从站地址那一个字节,从站收到帧之后只做一次比较:这个号是不是我。是,就进入应答流程;不是,就丢掉。

关键在于,协议里没有任何机制让两台从站发现彼此重号。它们各自比较、各自得出”是我”、各自开始驱动总线。而 RS-485 半双工总线上同一时刻只允许一个设备驱动,两台一起驱动,差分线上的电平就是两路输出互相拉扯的结果。

再加一层:两台设备的应答内容通常还不一样(各自寄存器里的值不同),叠加出来的字节序列不属于任何一方。CRC 是对整帧算的,这样的帧几乎不可能碰巧校验通过,于是被主站丢弃。这就是为什么冲突的表面症状是”没响应”而不是”数据错”。

那为什么又会”时好时坏”?因为两台从收到请求到开始驱动总线之间的处理耗时并不完全相同。如果这个时间差恰好大到让一台把整帧发完、另一台才开口,主站就可能先收到一帧 CRC 正确的完整响应,把后面那截当噪声丢掉——这一次读取就”成功”了。这个时间差会随请求内容、从站当时的处理状态而变,所以现象在”完全读不到”和”偶尔正常”之间摇摆。站内 Modbus 寄存器映射实战 把这类症状概括成”这地址时好时坏”,说的就是同一件事。

比读不到更麻烦的是这种”偶尔成功”:主站接受的那一帧到底来自哪一台,是不确定的。你可能读回一组数值完全合法、量纲也对的数据,只是它属于另一台设备。这种错误不报错、不报警,只是数据对象错了。

读冲突只是读不到,写冲突是两台一起动

这是本文最想说的一条,也是既有排查清单里最容易被一笔带过的地方。

读类功能码(读线圈、读离散输入、读保持寄存器、读输入寄存器)只取值,冲突的代价是读不到、或者读到另一台的值,设备状态没有被改变

写类功能码就不同了。两台同号设备都判定”是在叫我”,于是都执行了这次写操作,然后都回应答。主站那边因为叠加帧 CRC 不过,判定超时,界面上告诉你”写入失败”——可动作已经在两台设备上都发生了。更糟的是,主站通常会因为超时而重试,于是这个动作被重复下发。

放到展厅现场:你本意是把某台时序器的第 3 路推上电,同号的另一台时序器对应的那一路也跟着动作了;而主站显示写入失败,你还在那边反复点。这就是”我明明什么都没操作成功,可现场有东西在动”的来源。

由此得出一条纪律:怀疑地址冲突的时候,探测只用读功能码,绝不用写功能码去试。 如果非要用写来验证,先把被控回路的负载脱开。地址填错是”什么都没发生”,地址冲突是”发生了你不知道的事”——严重程度不在一个量级。

用减法把同号的那两台揪出来

冲突这件事需要两台才成立,所以定位的核心动作是逐台脱开,看现象在哪一步翻转。脱开可以是断电,也可以是把该设备的 A/B 接线从总线上摘下来。

顺序是这样的:

  1. 记下出问题的那个地址,反复读它,确认现象是”不稳定”而不是”稳定无应答”。
  2. 逐台脱开总线上的从站,每脱开一台就重读那个地址。
  3. 判据不是”读不到了”,而是”从不稳定变成稳定可读”的那一刻——那一刻你刚摘掉的那台,就是冲突的一方。
  4. 把它单独接上主站(总线上只剩它),读回它自己认领的地址,确认无误。
  5. 剩下那台同样单机确认一次,两台的实际地址都拿到手,才算定位完成。

设备多的时候可以先二分:RS-485 是手拉手串联的总线,从中间断开就分成两段,分别接主站试——哪一段单独接的时候那个地址稳定可读,冲突的另一台就在另一段里。要注意断开处的终端匹配条件变了,这只是调试期的临时手段,别当成长期接法;总线本身的布线纪律见 RS485 总线设计

新装现场反过来用加法更快:先只让一台上电,逐台加回,加到哪一台开始出现不稳定,冲突就在这一台和已经在线的某台之间。

两个容易走弯路的做法,提前说清楚:

  • 别用”改个地址试试”来定位。 你改的很可能是没问题的那台,冲突依然存在,只是换了个号,还把原本正确的地址表搞乱了。
  • 别信图纸上的计划地址表。 只要实际地址和计划地址分叉,冲突就会出现。脱开过程中每台单机读回来的那个号,才是可信的,最后要落到一张逐台读回来的地址表上(读回指总线上只挂这一台时用主站确认,不是拿图纸抄一遍)。

三种看着像地址冲突、实际不是的情况

  • 广播地址。 站内《Modbus 寄存器映射实战》写明,写类功能码可以向站号 0 广播,所有从站执行但都不回应。现象是”设备动了、主站等不到响应”,和写冲突长得很像。区分只要看一眼请求帧的第一个字节:是 0,那是你自己发的广播,不是冲突。
  • 总线上有两个主站。 一条 RTU 总线只能有一个主站发起请求,这条在 Modbus 协议速查 里叫单主站原则。两个主站抢线,同样是两个驱动器同时驱动、同样 CRC 失败。区分点很硬:双主站会让总线上所有地址一起受影响,地址冲突只影响那一个地址。 把另一个主站的轮询停掉,现象跟着消失,就是它。
  • 总线匹配或负载引起的不稳定。 这类问题也表现为偶发失败,但它与地址无关——把同一台设备改成别的地址,照样不稳;而地址冲突是”这个号不稳、别的号都好”。既有排查清单里”单台单独接都通、串到一条总线上就掉几台”那一类,多半要往这个方向走,而不是往冲突方向走。

网关和 TCP:冲突的边界在哪一段

Modbus TCP 的帧头里带事务标识和单元 ID,单元 ID 相当于串行链路那边的从站地址。这里有个边界必须划清楚:

两台各有自己 IP 的 TCP 设备,即使单元 ID 相同也不构成冲突。 它们在两条互相独立的 TCP 连接上,主站按连接区分对象,响应又靠事务标识对号入座,物理上根本不共享一条总线,没有”同时驱动”这回事。

冲突只发生在共享同一段物理总线的地方。典型是”Modbus TCP 网关下挂一段 RS-485”:网关把请求里的单元 ID 翻译成串口从站地址转发出去,下游那段总线上如果有两台同号,冲突照样成立,而且症状会以”网关这个 IP 上某个单元 ID 读不稳”的形式浮上来,容易被误当成网络问题。

所以排查的第一步其实是先确定可能发生冲突的物理段:把设备按”挂在哪条串行总线上”分组,不同组之间地址重复是允许的。这里有个容易忽略的坑——图纸上分成两段、地址各自独立编号,实际施工时两段被并到了一起,于是原本合法的重复地址瞬间变成冲突。总线拓扑对不上图纸的现场,这条要优先怀疑。

改址和地址规划:怎么让冲突不发生

同型号设备如果出厂默认地址一致,不逐台改址就直接串上总线,冲突是必然的,不是概率问题。所以正确的次序是设备进场时在单机状态下先改好地址、读回确认,再上总线。全部接完再来改,你连”它现在是几号”都读不出来——冲突恰恰让这个读取变得不可靠。

几件具体的事:

  • 改址的方式各家不同(拨码开关、设备菜单、或写某个配置寄存器),生效时机也不同,以设备手册为准。改完不要默认它已经生效,必须在单机在线的状态下读回验证一次。
  • 地址表记录的应该是读回来的实际地址,不是计划分配的地址。这两者一旦分叉,后面所有排查都会被带偏。
  • 编号留出段位:同类设备占一段,扩容时从该段往后取,别随手挑一个”看起来没用过”的号。站内《Modbus 读不到数据》把从站地址的有效范围写作 1–247,编段时按这个空间规划即可,通常远远够用。
  • 拆改之后要复核。设备被临时借调、替换、挪位之后,一台从别处拆回来的设备可能还带着原来的地址,接进来就成了冲突来源。

最后说一个最容易栽的坑:把地址冲突当成”设备坏了”直接换机。 换上去的新设备如果是同型号、同出厂默认地址,问题会原样保留下来,你还平白多了一次拆装和一次误判。判断”设备坏了”之前,先把它单独接到主站上读一次——总线上只有它一台的时候能不能通,是这一切的分水岭。

需要展厅软硬件方案或定制开发?

留言讨论

评论发布后会被人工复核,违规内容将被删除。

    还没有人评论,来说说你的看法

    如果发表没有反应,可以前往联系我们告诉我们。

    这个页面有问题?

    提交时会附带当前页面地址和浏览器信息,帮助我们定位问题。不填联系方式即为匿名。