前阵子去一个客户的机房,采集服务器屏幕上 24 台 PDU 的数据断断续续,隔几分钟就掉几台,几分钟后又自己回来。客户起初觉得是采集程序写得有问题,把代码翻出来让我看。我扫了一眼轮询间隔和超时设置,没什么毛病,就问了一句:这 24 台是怎么接的?
对方的回答是「从机柜一路串下来,中间有几处为了方便,分了叉」。听到这儿我心里基本有数了------问题不在代码,在物理层。
手型拓扑是 RS485 的老毛病
RS485 的设计前提是菊花链,一条线从头串到尾。现场为了省事,从主干上分出支线,就成了手型(也叫星型)拓扑。支线越长,信号在末端反射越厉害,反射回来的波形叠加在原始信号上,接收端判定电平就出错。
拓扑
支线长度建议
24 台设备的表现
现场评价
菊花链
无支线
长期稳定
施工麻烦,改一台要断电
手型短支线
不超过 1 米
一般可用
加柜时需重排
手型长支线
超过 3 米
随机丢包
问题多发
加中继分段
每段独立
稳定,需配地址段
大机房推荐
那次现场有几处支线拉到了五六米,正好落在出问题的区间里。
终端电阻不是可有可无
RS485 总线的两端各需要一只终端电阻,阻值与电缆特性阻抗匹配,常用 120 Ω。缺了它,信号到了末端无处可去,原路反射回来。
配置
短距离(50 米内)
中距离(50 到 300 米)
长距离(300 米以上)
两端各 120 Ω
推荐
必需
必需
只装一端
可用
偶发丢包
频繁丢包
两端都不装
勉强可用
明显丢包
基本不通
中间也装上
电平被拉低
通信失败
通信失败
中间多装电阻是另一类常见错误,多台设备的电阻并联,总线等效负载过重,驱动器推不动,整条线就哑了。
地址冲突的排查套路
地址撞车和拓扑问题的表现很像,都是随机掉设备。区分的办法是逐个单独测:把总线上其他设备断开,只留一台,看能不能读上来。
ini
import serial
from pymodbus.client import ModbusSerialClient
def probe(port="/dev/ttyUSB0", baudrate=9600, addr_range=range(1, 32)):
"""逐个地址单独探测,能读回来的就是总线上真实存在的设备。"""
client = ModbusSerialClient(
port=port,
baudrate=baudrate,
bytesize=8,
parity="N",
stopbits=1,
timeout=0.3,
)
client.connect()
found = []
for addr in addr_range:
rr = client.read_input_registers(address=0, count=2, slave=addr)
if not rr.isError():
found.append((addr, rr.registers))
client.close()
return found
把探测结果和台账对一遍,多出来的就是重复地址,少掉的那台要么地址被改过,要么物理链路断了。
现象
偏向的原因
快速验证
随机掉个别设备
地址冲突或支线过长
单独接一台看是否恢复
全部读不上来
终端电阻缺失、AB 线反接
万用表量 AB 间电压
换一台就掉另一台
地址重复
逐个探测比对台账
距离远的那几台先掉
线路衰减、波特率过高
降到 9600 再试
AB 线反接是施工里频次不低的错误。总线正常时 AB 之间有几百毫伏到几伏的差分电压,量到接近零就要怀疑接反或者短路了。
顺手把波特率也降一档
很多丢包其实是波特率定得太高。1200 米的理论距离是在 9600 波特率下给出的,现场把波特率设成 115200,距离还按 9600 的预期拉,不出问题才奇怪。
波特率
参考传输距离
适用场景
9600
1200 米
跨机房长距离
19200
800 米
同层多柜
38400
500 米
单列机柜
115200
100 米
柜内短距,慎用
那次客户原来是 38400,我把整条线降到 9600,再把三处长支线改成短支线,丢包就停了。改完之后还留了个建议:下回加机柜,直接按每段 16 台加中继来规划,别再往一条总线上堆。
我们出厂前怎么验链路
每台带通信的 PDU 出厂前都要过一遍例行检验,我们厂 2014 年办起来,做配电的老师傅有二十五年经验,这套流程一直没省:耐压 1500 V、绝缘电阻不低于 10 MΩ、接地电阻不大于 0.1 Ω、满载温升不超过 45 K,计量部分与标准表比对,误差控制在 ±1%。
每台设备在出厂时就把通信地址写在铭牌和交付清单上,现场照着清单配,能省掉大半的地址冲突。产品通过 ISO 9001 体系认证,持有 CCC、CE(LVD+EMC)、GS 认证。
有非标需求的,客户把机柜尺寸、通信接口数量和协议版本讲清楚,30 分钟出图,1 小时报价。带 ATS 的产品切换动作做到 ≤7ms 以内,切换过程中通信模块不掉线,轮询不会在切换瞬间丢一个周期。
一台都读不上来,先查什么?
先量 AB 间有没有差分电压,再看终端电阻有没有装,三步之内能排除掉大部分硬故障。程序层面的问题,通常不会让全部设备同时读不上。
加了中继之后地址怎么排?
按物理段分段编号,比如一段用 1 到 16,另一段从 17 开始,台账里同时记地址和所在机柜位置。出了故障定位起来快得多。
物理层的问题,追到代码里去翻是翻不出来的。先把线捋顺、把电阻装对、把地址排清楚,采集自然就稳了。