本节摘要:总线"快不快"取决于轮询周期的设计:单次问答时间、批量读的收益、超时重试的代价。本节给出一套完整的性能账算法,并处理鲁棒性问题(超时、重试、从站掉线)。位置:数据解释会了,本节解决"整条总线怎么调得快、调得稳"。
一次轮询问答应答的时间由四段组成:
T总 = 请求帧时间 + 从站处理时间 + 响应帧时间 + 主站处理时间 9600 波特、读 1 个寄存器: 请求 8B ≈ 9.2ms;从站处理 ≈ 5-20ms;响应 9B ≈ 10.3ms;主站 ≈ 1ms 单次 ≈ 25-40ms 30 台设备全轮一遍 ≈ 0.75-1.2s(每台读 1 个寄存器时)
这就是"刷新慢"的物理账。三个提速杠杆:升波特率(9600→38400 快 4 倍)、批量读(一次读多个寄存器,摊薄请求与应答的固定开销)、并发/分总线(多条总线并行轮询)。
| 读取方式 | 帧开销 | 读 30 个寄存器总耗时(9600 波特) |
|---|---|---|
| 30 次单读(每次 1 个) | 30×(请求+应答) | 约 600ms+ |
| 3 次批读(每次 10 个) | 3×(请求+应答+数据) | 约 150ms+ |
| 1 次批读(30 个) | 1 次 | 约 60ms |
结论:能批量就批量,一次读 16-32 个寄存器是工程甜点(超过 125 上限会被拒,读太多单字节错误会拖累整包)。但批读的前提是"寄存器连续",点表不连续的量宁可拆组,见第 2 章。
超时与重试要参数化而不是写死:超时按"最慢从站的最坏响应时间 × 2-3"设(从站忙、写 Flash 时会慢到几百 ms);重试次数默认 2-3 次;退避指数增长(100ms 起步);离线降频——从站连续失败 N 次后标记离线,降为慢轮询(如 30s 一次)试探,避免高频轰炸拖慢整条总线。参数集中放在配置表,不同从站可以有不同的超时/重试配置(慢设备与快设备同线共存时尤其重要)。
鲁棒性参数示例: poll.timeout_ms = 200 # 超时 poll.retries = 2 # 重试 poll.backoff_base_ms = 100 # 退避基数(指数增长) poll.offline_probe_s = 30 # 离线后慢轮询间隔 poll.max_consecutive_fail = 3 # 判离线阈值
某水厂 40 台流量计刷新慢(最慢 4s 刷新一次),主管要求 1s 内。优化三步:波特率 9600→19200;把每台"读 4 次单寄存器"改成"1 次批读 4 个";读功能与写功能分线程。优化后整圈轮询约 0.6s,达标。复盘:先算账再动手——把每台设备的读量、总时间列出来,瓶颈在哪一目了然,别盲目升级硬件。
要点回顾:轮询周期 = 帧时间 × 数量,提速靠升波特率与批读;超时/重试/退避/降频四参数化设计保证鲁棒;先算账再动手是调优的第一原则。性能账清楚后,下一章打开安全这个新话题——无认证协议在物联网时代的风险。
理论算完要用实测校准:1 用调试器测单次问答的实际耗时(含从站处理);2 按轮询表算整圈时间并与需求对比;3 超标的环节逐项优化(批量读、升波特率、拆总线);4 加 20% 余量后固化轮询表。实测与理论差 30% 以上时先查异常——可能是某台设备响应慢(从站忙)、有重试在悄悄发生(日志里的重试计数是报警器),或总线上有广播流量干扰轮询节奏。
读与写混跑时,总线管理要避免"写卡住轮询":写操作单独列队(设定值、控制指令通常低频,别插在轮询循环中间);写优先级高于读(控制指令延迟不可接受,读数据可以晚半秒);写后读回验证(写寄存器后立即读回比对,确认写成功再继续)。实现上建议读写分线程/分队列,写队列为空时读线程独占总线,写请求到来时读线程让出——别在轮询循环里同步等写完成,那是"一写卡整线"的根源。
从站掉线(超时超限)后的数据策略要提前设计:读数据保持旧值还是置无效——工业场景强烈建议"保持旧值 + 状态标记"(置 0 会造成假报警,见第 1 章复盘案例);恢复后的重新同步——从站恢复后先读一轮关键寄存器再恢复正常轮询;告警去抖——掉线告警要连续 N 次失败才触发,恢复后自动清除,避免"抖动刷屏"。
问:轮询与写操作能同一个循环吗? 能但别同步等:写操作低频且会阻塞,插在轮询循环里"一写卡整线"。读写分队列,写优先、读让位,写后读回验证。
问:从站忙(异常码 06)怎么处理? 它是正常状态不是故障:设备正在处理高优先级任务(急停、写 Flash)。加大重试间隔平滑处理,别当故障告警刷屏。
问:批量读一次读多少合适? 16-32 个寄存器是甜点:太少浪费请求开销,太多单字节错误拖累整包且超 125 上限会被拒。按点表连续段分组读。