上个月在一个边缘机房帮人调数据采集,现象很典型:一台串口服务器下面挂了 18 台带计量的机柜 PDU,采集程序跑了半小时就开始出现大面积超时,重启网关能好一会儿,然后接着超时。对方的第一反应是"网关不行,换一个带隔离的"。
我没换。先把日志拉出来看了一眼,超时的分布很有规律——不是随机散落的,而是每隔一段时间连续丢一批。这种规律性的丢包,八成不是硬件坏了,是轮询节奏和帧间隔没对上。
先把物理层那几件事排除掉
RS485 这条链路上,真正会让你莫名其妙丢帧的,来来回回就那么几个原因:
检查项
常见错误
怎么验
终端电阻
只在中间某个节点加了,或者两端都忘了加
断电量 A/B 之间电阻,正常应接近 120Ω 或 60Ω
拓扑
拉成星型,主干上挂了好几条支路
应该手拉手串,支路越短越好
地线
各节点地电位差太大,共模电压超出接收器范围
万用表量不同节点 GND 之间的交流电压
波特率
两端设的不一致,或者某台从站出厂默认是另一个值
逐台单独点读,能读通的那台说明参数对
这台串口服务器下面 18 台从站,用的是 9600 波特率。先算一下:一帧读寄存器请求 8 字节,响应按读 10 个寄存器算是 25 字节,加上 3.5 个字符的帧间隔时间,一问一答大概 40 毫秒出头。18 台轮一遍就是 700 多毫秒。如果采集程序设的超时是 200 毫秒,那理论上就应该通——可它设的是 100 毫秒。
把超时从 100 毫秒提到 400 毫秒,超时的频率立刻降了一个数量级,但没归零。
剩下的那些,多半是地址冲突和重试风暴
继续挖,发现真正的问题在后半段:程序里对超时做了三次重试,重试是紧跟着发的,中间没有间隔。RS485 是半双工,从站刚收到一个没来得及处理的请求,下一个请求紧接着又来了,从站的串口缓冲区直接溢出,后面的帧全废。
改法很简单,加两段等待:
# 伪代码:单台从站读取,失败后按退避重试
def read_one(slave_id, addr, count, retries=2):
for i in range(retries + 1):
try:
resp = master.read_input_registers(
slave=slave_id, address=addr, count=count)
time.sleep(INTER_FRAME) # 帧间隔,按波特率算,别写死
return resp.registers
except ModbusException as e:
log.warning("slave %s timeout, retry %s", slave_id, i)
time.sleep(0.2 * (2 ** i)) # 指数退避
continue
return None
关键不是重试次数,是重试之间要有间隔,而且间隔要随失败次数变长。改完之后,18 台连续跑了一整晚,超时次数从每小时几百次降到个位数。
参数
改之前
改之后
说明
单帧超时
100 ms
400 ms
按波特率和帧长倒推,再留一倍余量
帧间隔
无
动态计算
3.5 字符时间,9600 下约 4 ms,实际取 10 ms
重试
3 次立即重试
2 次 + 指数退避
避免半双工总线被打爆
轮询周期
1 s
5 s
电量数据不需要秒级刷新
还有个隐藏更深的坑:地址偏移。有的厂家文档写寄存器地址是 40001,有的写 0x0000,两者差 1。用 read_input_registers 的时候如果直接把 40001 传进去,读出来的数就是错位的,看起来"没超时但数值不对"。我一般先在单台上用功能码 03 和 04 各读一次,对一下文档,确认偏移量再批量上。
现象
大概率原因
排查顺序
全部从站都超时
串口参数 / 接线 / 方向控制
先看波特率和 A/B 有没有接反
部分从站超时
地址冲突 / 该台掉电
逐台点名,记下应答的 ID
数值全为 0 或超大
寄存器偏移量、字节序
核对文档的地址基准和大小端
CRC 校验失败
总线干扰 / 波特率不匹配
换低波特率试,检查终端电阻
选型阶段就该问清楚的几件事
这类问题其实可以在采购阶段就规避掉。带计量的 PDU 在出厂前一般都会做温补标定,计量精度标到 ±1%,但这个数字是在额定量程附近标出来的;如果机柜里只挂了几台轻载设备,电流长期在额定值的百分之几,采集上来的数误差就会明显放大,这时候别急着怀疑网关,先看看实际负载落在哪个区间。
另外,如果机柜是双路供电,通常会带 ATS 做自动切换,切换时间控制在 7 毫秒以内,实测多数落在 5 到 6 毫秒。采集程序遇到切换那一瞬间可能会读到一次异常值,做数据清洗的时候要考虑进去,别让这个尖峰触发告警。
我们厂 2014 年成立,做电源分配这块的核心团队在行业里干了二十五年,厂内按 ISO 9001 跑质量体系,产品做过 CCC,也按 CE 指令里的 LVD 和 EMC 做过评估,另外拿过德国的 GS 认证。非标定制的单子,客户把尺寸和接口要求发过来,我们 30 分钟内出图、1 小时内报价——如果采集点位有特殊要求,尽量在出图阶段就一起提,后面改寄存器表比改外壳尺寸麻烦得多。
协议文档这件事最后说一句。挑厂家的时候,问一下 Modbus 寄存器表是不是公开文档、有没有版本号。有些厂家给的是一张截图,问到细节就说"这个要问技术",后面对接会很累。
有人问过我,能不能直接上 Modbus TCP 就不用管这些了。能,物理层的问题确实少了,但轮询节奏、重试策略、地址偏移这几样一个都跑不掉,只是换个地方踩。
也有人问,18 台是不是太多了、要不要分成两条总线。一般 9600 波特率下一条总线挂 20 到 30 台还能跑,关键是总长度和节点间距,别光看数量。