(十四) 现场常见问题排查案例:Modbus不通、数据不对、写入没反应怎么办
GitHub 项目地址:https://github.com/lidecong133/YModbus
Modbus 现场问题,最怕一句话:
“通讯不通。”
这句话太大了。IP 不通叫不通,站号错叫不通,地址差 1 也叫不通,读出来浮点数不对也有人说不通。
我更习惯把问题拆开看。下面这些案例,都是做 Modbus 调试时很常见的情况。
TCP连不上
现象很直接:主站连接192.168.1.10:502失败。
这时还不用讨论功能码和寄存器地址。
先看这些:
- 设备 IP 是否真的是
192.168.1.10 - 电脑和设备是不是同一网段
- 能不能 ping 通
- 端口是不是
502 - 设备是否启用了 Modbus TCP
- 设备是否限制只允许一个连接
- Windows 防火墙或现场网络是否拦截
我一般会先用 CLI 做一个最小读取:
ymodbusread-holding-registers--host 192.168.1.10--port 502--unit-id 1--address 0--quantity 1如果 CLI 也连不上,基本就不要先怀疑你的业务程序。链路没通,后面的地址和字节序都没意义。
TCP连上了,但读取超时
这个比完全连不上更容易误导人。
TCP 连接成功,只说明你连到了那个 IP 和端口。它不保证目标设备真的会响应你的 Modbus 请求。
尤其是 TCP 转 RTU 网关。
你连上的是网关,真正干活的是网关后面的 RTU 从站。如果 UnitId 不对,或者网关后面的串口参数不对,就可能一直超时。
我会先查:
- UnitId 是否对应网关后面的设备站号
- 网关后面的 RTU 设备是否在线
- 网关串口参数是否和设备一致
- 功能码是否支持
- 地址是否有效
- 超时是否太短
可以扫一个小范围 UnitId:
ymodbus scan-units--host 192.168.1.10--port 502--start-unit-id 1--end-unit-id 8--function03--address 0--quantity 1不要一上来扫 1 到 247。现场设备慢时,这个操作会拖很久,还会让人误以为工具卡住。
RTU完全没响应
RTU 没响应,第一反应不要是改代码。
先看物理层和串口参数。
- COM 口是不是选对
- USB 转 RS485 有没有驱动问题
- 波特率是否一致
- 数据位是否一致
- 校验位是否一致
- 停止位是否一致
- SlaveId 是否正确
- A/B 线是否接反
- 总线上是不是有两个主站
- 设备是否需要单独供电或使能通讯
RS485 的 A/B 标识不同厂家还不完全统一。遇到完全没响应,确认参数没问题后,A/B 对调试一下并不丢人,现场经常就卡在这里。
如果你手里有 USB 转 RS485 和从站工具,也可以反过来做个小测试:用 YModbus.SlaveApp 开一个 RTU 从站,看你的主站能不能读到。这样能把真实设备问题和主站程序问题分开。
返回非法数据地址
设备返回Illegal Data Address,说明它收到了请求,只是不接受这个地址。
这不是网络不通。
常见原因:
- 地址差 1
- 功能码选错
- 数量太大,跨过有效区域
- 该型号没有这段寄存器
- 手册里的地址是显示地址,不是协议地址
比如手册写40001 当前值。
我会先试03、地址0、数量1。
如果手册写“地址 1 当前值”,就要判断它到底是协议地址 1,还是从 1 开始的人类编号。
最稳的做法是找一个设备屏幕上能看到的值。比如屏幕显示温度23.5,你就围绕手册里那个温度地址小范围试,不要整段扫。
数值离谱
设备屏幕显示23.5,程序读出来16856或4.1E-41。
这通常不是通讯失败。
设备已经回数据了,只是你解释错了。
按这个顺序查:
- 它到底是整数缩放,还是 float
- 如果是整数缩放,倍率是多少
- 如果是 float,占两个寄存器还是四个寄存器
- 字序是高字在前还是低字在前
- 单个寄存器内部字节序是否特殊
很多设备会把23.5存成235,然后手册写倍率0.1。这时候用 float 解析只会越看越乱。
如果确实是 float,再用RegisterConverter试不同 word order / byte order。
调通以后,把格式写进地址表。不要靠记忆。
写入成功,但设备没动作
这是现场很常见的误会。
Modbus 写成功,只说明设备接受了这个写请求。
它不一定代表设备业务动作已经执行。
比如:
- 参数写入后还要写保存命令
- 设备必须处于远程模式
- 设备必须停机才能改参数
- 写入值超出业务范围,设备内部忽略
- 需要同时写多个寄存器
- 某个使能位没打开
我的习惯是写完立即读回。
如果读回值没变,说明写入没有真正落到设备。
如果读回值变了,但设备没动作,那就看设备业务条件:模式、使能、保存、启动位、联锁条件。
比如变频器,频率写进去了,不代表电机就会转。还可能需要运行命令、方向命令、远程控制模式。
主站说发了,从站说没收到
主站工具和从站工具一起用时,可以按报文方向对照。
主站:
- TX:主站发请求
- RX:主站收响应
从站:
- RX:从站收请求
- TX:从站发响应
正常应该是主站 TX 对上从站 RX,从站 TX 对上主站 RX。
如果主站有 TX,从站没有 RX,查 IP、端口、串口线、防火墙。
如果从站有 RX,但没有 TX,查 UnitId、异常仿真、跳过响应设置。
如果从站有 TX,主站没有 RX,查主站超时、返回方向链路、响应格式。
报文对照能把很多口水仗变成事实。
偶尔成功,偶尔失败
这种问题最磨人。
常见原因:
- 轮询周期太短
- 一次读取数量太大
- 设备响应慢
- RS485 总线干扰
- 网关转发不稳定
- 多个主站同时访问
- USB 转串口质量差
处理时不要一上来就疯狂加重试。
先把轮询周期放大,比如从 100 ms 改到 1000 ms。
再把一次读取数量减小,比如从 100 个寄存器改成 10 个。
然后打开报文,看失败时到底有没有响应。
如果只是偶发抖动,可以加少量重试。如果每次都要靠重试才能成功,那根因还在链路或设备响应上。
一套比较稳的排查顺序
我一般按这个顺序:
- TCP 先查 IP/端口,RTU 先查串口/接线
- 查 UnitId / SlaveId
- 查功能码
- 查地址是否差 1
- 查数量是否太大
- 看异常码
- 看原始报文
- 通讯成功后,再看数据类型、字节序、比例系数
- 写入成功但设备没动作,再查设备业务条件
顺序很重要。
如果链路都没通,就去改字节序,是浪费时间。
如果设备已经返回异常码,还在怀疑网线,也会绕远。
Modbus 调试不是靠猜,是把每一层证据拿出来看。
