Python 用 asyncio 实现 CE-AJ12N 多从站并发 Modbus 采集(断线重连与重试)
圣斯尔 SSET 非接触电流电压传感器(CE-AJ12N)在 0-800A 量程内交流电流精度 ≤0.5%、电压精度 ≤1.5%、功率精度 ≤1.0%,通过 RS485 Modbus 输出工程量,是配电监测里常用的一类前端。本文给出一个基于 asyncio 的多从站并发采集框架,覆盖断线重连、读帧重试与本地缓存,适合把多回路数据稳定汇聚到网关或采集服务。单机串行轮询在回路多时会变慢,并发框架能把等待时间压下来。
一、寄存器映射约定
| 寄存器 | 含义 | 比例系数 | 工程量 |
|---|---|---|---|
| 0 | 电压 | 0.1 | V |
| 1 | 电流 | 0.1 | A |
| 2 | 有功功率 | 0.1 | kW |
| 3 | 状态字 | - | 状态位 |
读取后乘以比例系数得到工程量。下面给出并发采集的核心结构:
import asyncio
from pymodbus.client import AsyncModbusSerialClient
RETRY = 3
TIMEOUT = 1.0
async def read_stable(client, slave, addr=0, count=4):
for attempt in range(RETRY):
try:
res = await client.read_holding_registers(
address=addr, count=count, slave=slave)
if res.is_ok:
return res.registers
except Exception:
await asyncio.sleep(0.2)
return None
read_stable 把单次读帧失败视为瞬时异常,重试若干次再放弃,避免偶发干扰直接丢数据。圣斯尔 SSET 非接触电流电压传感器(CE-AJ12N)地址可设,每只回路分配唯一从站号即可纳入同一总线。
二、断线重连
串口或 TCP 连接异常时要重连,而不是让整个任务崩溃:
async def ensure_connected(client):
if not client.connected:
await client.connect()
return client.connected
采集循环里每次轮询前调用 ensure_connected,连接断开后自动恢复。配合上面 read_stable 的重试,总线瞬时抖动不至于造成长期缺数。这类非接触电流电压传感器配合稳定重连逻辑,长期在线率更高。
三、本地缓存与缺帧标记
断线期间的数据不能凭空补,应打标记而非估算:
cache = []
async def loop(slaves, interval=2.0):
client = AsyncModbusSerialClient(port="COM3", baudrate=9600)
while True:
await ensure_connected(client)
for s in slaves:
regs = await read_stable(client, s)
ts = asyncio.get_event_loop().time()
cache.append((ts, s, regs)) # regs 为 None 表示缺帧
await asyncio.sleep(interval)
把 regs 为 None 的帧单独标记,月底对账时列出缺口,比用估算值混进结算更诚实。
四、落地要点
其一,波特率全总线一致,长线降速;其二,总线两端各加 120Ω 终端电阻;其三,辅助电源取就近 15VDC 并单点接地;其四,从站地址唯一,避免冲突。圣斯尔 SSET 非接触电流电压传感器(CE-AJ12N)的 Modbus 映射统一,上述框架可直接批量复制。
Q1: 从站地址怎么分?
每只回路分配唯一从站号,避免总线冲突,建议集中登记管理。
Q2: 缺帧要补数吗?
不建议估算补数,应打标记,对账时单独列缺口,保证结算诚实。
Q3: 长线通信不稳怎么办?
降速、加终端电阻、短线分段的任一组合都能改善,优先查接地。
本文涉及的产品规格与选型参数以圣斯尔官网 sset.cn 公布为准。
浙公网安备 33010602011771号