用电信息采集系统通信协议集合解析与测试工具实战
2026/9/9 21:24:42 网站建设 项目流程

简介:面向电力行业开发、运维及测试人员的电力用户用电信息采集系统通信协议集合与配套测试工具,重点覆盖376.1/376.2/376.3、645、698等常用规约,可用于协议解析、设备联调、故障排查和采集系统功能验证。压缩包共89个文件,约105.57MB,包含37个txt协议说明与解析记录、7个exe测试工具、8个dll动态库、6个pdf文档,以及doc/ini/config等配置与说明文件,可支撑从协议学习到工具使用的完整闭环。具体内容包括QGDW1376.2解析、DLT698-45(1.0)国网电表测试软件、1376.1-2013、376.2Q-GDW集中器下行本地接口协议调试软件、645协议测试与DLT645标准测试程序等,帮助开发者在真实场景中验证帧格式、命令交互和异常处理流程。已有3546人学习下载,适合正在做电力采集主站、集中器或电能表通信模块开发,需要对照标准规约进行联调与测试的技术人员。 干这行的人应该都有同感:搞电力用户用电信息采集系统,最磨人的往往不是业务逻辑,而是协议。主站一套规约,集中器一套规约,到了表计又是另一套规约,现场联调的时候A厂家和B厂家的帧对不上,光靠肉眼看十六进制报文看得头大。我前前后后折腾了小半年,把用采系统里主流的通信协议集合整理成了一套内部规范,又配套做了一套测试工具,才把联调和回归测试的效率拉起来。这篇文章就把这套协议集合的拆解思路和测试工具的实现细节都抖出来,给做用电信息采集、智能表计、物联网网关的同行一个参考。

这套东西适合谁看?如果你正在写采集终端、集中器、表计的嵌入式代码,或者在做主站与终端之间的协议适配,又或者只是接了国网南网的项目需要过协议一致性检测,那下面的内容基本都能直接用。我会从协议在整个系统里的位置说起,再逐个拆传输协议、应用协议,最后把测试工具的造帧、解析、自动化脚本思路完整过一遍。

1. 用电信息采集系统里,通信协议到底在管什么

1.1 先理清三层架构,才知道协议怎么分层

用电信息采集系统在物理上一般分三层:最上面是主站,中间是采集终端,最下面是电能表。主站负责数据汇聚、费控下发、线损分析;采集终端(集中器、采集器、专变终端)负责把主站的命令翻译给下面的表计,也把表计的数据汇总上报;电能表就是最末梢的计量设备。

通信协议就分布在两层链路上。主站与采集终端之间叫上行通道,通常走无线公网、光纤或以太网,常见协议是 DL/T 634.5101(101)、DL/T 634.5104(104)以及电力行业广泛使用的 Q/GDW 1376.1 主站与采集终端通信协议;采集终端与电能表之间叫下行通道,物理层走 RS-485、载波、微功率无线,应用协议最典型的是 DL/T 645-2007 多功能电能表通信协议。两层链路协议不同,所以采集终端本质上是个协议转换网关,这也是为什么做这一点的人必须同时对上下行协议都有概念。

1.2 为什么一个采集系统需要"协议集合"

纯粹从抄表角度看,一个集中器下面可能挂几十上百只表,这些表不一定是同一个厂家的。有些工程是分批改造的,一期装了A家的表,二期装了B家的表,但集中器不能换,所以它必须能同时识别多套协议的变体。国网系统里现在在推 DL/T 698.45 面向对象协议,南网和不少存量项目还在大量使用 DL/T 645,主站与终端之间又各自有 1376.1、101、104 的混杂。协议集合这个概念,本质上就是把上下行所有可能碰到的协议收拢到一个统一的字典和解析框架里,谁的帧来了都能认,谁的命令都能发。

我见过最典型的坑是:一个集中器固件里只写了645的读表逻辑,现场换了一批698.45的新表,直接抄不上数据。所以协议集合不是简单堆代码,而是要有统一的数据模型去承载不同协议的差异。

2. 核心协议逐个拆解:链路层到应用层

2.1 DL/T 645:现场覆盖率最高的电表协议

DL/T 645 是单费率、多费率电能表最常用的通信协议,物理层以 RS-485 为主。它最核心的是帧结构:起始符 68H,6 字节地址域,再一个 68H 起始符,接着控制码、数据域长度、数据域、校验码 CS、结束符 16H。

地址域特别容易踩坑。645 的地址域是低字节在前,也就是表地址要反着放。如果你真拿十六进制串去做字符串匹配,肯定对不上。控制码的高位区分方向(主站请求和从站应答),低四位是功能码,常用的读数据命令是 11H,写数据是 14H,响应时方向位置1,所以读数据应答是 91H。数据域里最关键的是四字节数据标识 DI,它决定了你读的是正向有功电能、实时电压还是事件记录。校验 CS 是帧起始符到数据域最后一个字节的8位累加和,注意不包含结束符,这是手写解析器时最常错的点。

2.2 DL/T 698.45:面向对象的新一代协议

698.45 和 645 完全不是一个思路。它不是简单的"地址+命令+数据",而是引入了基于对象的建模,通过接口类、对象标识 OID、属性描述来访问数据。数据和操作都被抽象成对象,抄表和费控变成对属性和方法的调用,加上它支持 TLS 加密、长帧传输、多级应用层,安全性比 645 高一个量级。

但 698.45 的解析复杂度也明显高。一个 APDU 里面要处理 TLV 编码、对象列表、不同接口类的差异,还要区分 CONNECT、GET、SET、ACTION 等多种操作。第一次写解析器的时候,光一个时间对象的数据类型就能折腾半天。建议做 698.45 功能时先把它官方的接口类文档完整过一遍,别直接上手写代码。

2.3 上行协议:主站和集中器如何对话

上行协议在整个采集链路里容易被低估。Q/GDW 1376.1 是主站与采集终端之间最常用的协议之一,它定义了登录、心跳、参数下发、数据上报、远程升级等一整套应用流程,链路层有自己的帧格式、地址字段、帧序号和防止串帧/丢帧的校验机制。调试时顶层主站抓一个包过来,如果不停做链路层之外的企业码、登录状态判断,光链路层都会出很多问题。

有些地区或项目会用 101/104 远动协议和主站通信,规约结构跟 1376.1 有明显差异,尤其是 104 这种走 TCP 的规约,会有专门的 apci 控制域、序号区、类型标识,调试工具里往往要单独适配。

2.4 协议对比与选型建议

协议应用位置典型物理层帧/报文复杂度是否加密适用场景
DL/T 645-2007终端与电能表RS-485、载波存量表计、长期稳定
DL/T 698.45终端与电能表RS-485、载波可选 TLS新项目、国网采购
Q/GDW 1376.1主站与终端4G/光纤有认证机制用电信息采集主站
DL/T 634.5104主站与终端TCP/IP中高可选SCADA/远动接入

如果你在做新设备选型,下行优先看能不能支持双向协议切换,也就是 645 和 698.45 都保留,避免现场换表之后固件又要重新开发。

3. 测试工具:为什么要自己造轮子

3.1 现成工具不够用的地方

很多人一开始会拿通用串口助手、Modbus 调试工具去抓 645 报文,只能说能看个大概。645 的帧是二进制帧,没有 ASCII 可读性,一串 68 AA AA AA AA AA AA 68 11 04 33 33 34 33 直接贴在终端里,别说校验对不对,就连字段边界都要数半天。Wireshark 虽然能解析不少电力协议,但 645/698.45 这类 RS-485 上的协议本来就不走 IP 链路,抓包也要靠串口透传,整体流程非常别扭。

所以我的思路是自己做一个"协议集合测试工具":把帧构造、帧解析、链路收发、场景脚本、回归断言全部统一进来。工具不一定要图形界面,命令行反而更适合自动化,扔到 CI 里也能跑。

3.2 测试工具的核心模块

工具分成四个模块:帧构造器、帧解析器、通信层、用例引擎。

帧构造器负责按协议规则把所有字段拼成二进制帧,自动算校验码,你需要关心的只有业务参数。帧解析器反过来,把收到的原始字节按照协议帧格式拆解,输出控制码、地址、数据域、校验结果。通信层统一封装串口和 TCP,串口用 pyserial,TCP 用标准库 socket,上层不用关心底层是 RS-485 还是网络。用例引擎负责把"造帧、发帧、等响应、断言结果"串成一条用例,跑完自动出报告。

3.3 工具实现:从帧构造到校验,核心代码直接抄

我先给出 645 的部分。addr_to_bytes 把表地址转成6字节低字节在前,build_read_frame 构造读数据帧,parse_frame 把响应帧解析成可读字段。

import serial import struct def addr_to_bytes(addr: str) -> bytes: # addr 形如 "12345678",按645要求低字节在前 tmp = bytes.fromhex(addr)[::-1] return tmp + b'\x00' * (6 - len(tmp)) def cs(data: bytes) -> int: # 从起始符68到数据域最后一字节的累加和,取低8位 return sum(data) & 0xFF def build_read_frame(addr: str, di: bytes) -> bytes: a = addr_to_bytes(addr) body = b'\x68' + a + b'\x68\x11' + bytes([len(di)]) + di body += bytes([cs(body)]) body += b'\x16' return body def parse_frame(raw: bytes): if len(raw) < 10 or raw[0] != 0x68 or raw[-1] != 0x16: return {'error': 'not a valid dl645 frame'} addr = raw[1:7][::-1].hex() ctrl = raw[7] length = raw[8] data = raw[9:9 + length] cs_val = raw[9 + length] expect_cs = cs(raw[:9 + length]) return { 'address': addr, 'ctrl': hex(ctrl), 'length': length, 'data': data.hex(), 'cs_ok': cs_val == expect_cs, }

用的时候这样:

frame = build_read_frame('12345678', bytes.fromhex('01000000')) print(frame.hex()) resp = b'\x68...' # 现场收到的响应帧 parsed = parse_frame(resp) if parsed.get('cs_ok'): print('校验通过,数据域:', parsed['data']) else: print('校验失败')

这里数据标识 DI 在帧里是按协议规定的顺序拼接的,具体读哪种数据你按规约表格填,读电压、电流、电能,用的 di 字节组都不一样。这段代码的关键思想是:协议细节都被封装在 build 和 parse 两个函数里,后续测试用例只需要关心参数。

4. 实操:用测试工具做一轮一致性验证

4.1 环境准备与连接决策

跑之前先想清楚你要模拟哪一侧。模拟主站时,工具通过串口或网络连到集中器,主动发命令、收响应;模拟终端时,工具要能接收主站连接并回应报文。做下行采集测试时,工具连着的是一只真实的表计或一个能响应协议的虚拟表模拟器。

我用的是 USB 转 RS-485 的适配器,接表计 A/B 端时要确认共地,不然信号飘得没法看。电平不对时表现为"有帧出来但表无响应"。波特率一般设置 2400、4800、9600 三档,先拿默认 2400 测,逐个往上试。

4.2 造帧、发帧、解析响应的一次完整演示

假设现在要通过集中器读一台 645 表计的正向有功总电能,最朴素的流程是这样:

  1. 用 build_read_frame 构造读数据帧。
  2. 如果连的是电表的 RS-485,直接把帧通过串口发给表计;如果连的是集中器,则需要包一层上行协议的命令,使得集中器知道你要下行抄表。
  3. 等待响应,收到帧后用 parse_frame 解析,并断言控制码是应答帧、校验正确、数据域长度符合预期。
  4. 把数据域按数据类型解析成十进制。

下面是通信层封装的样例,连真实表计前用虚拟表做了验证:

def read_meter(port: str, addr: str, di: bytes, baudrate=2400): ser = serial.Serial(port, baudrate, timeout=1) frame = build_read_frame(addr, di) ser.write(frame) raw = ser.read(64) if not raw: return {'error': 'timeout'} return parse_frame(raw)

实测下来,2400 波特率下整个往返在几百毫秒到一秒之间。如果响应超时,第一件事不是调协议,而是检查 A/B 是不是接反、是否共地、终端地址是否匹配。地址错了表也会回帧,但回的是"地址不匹配"之类的错误帧,这种帧解析函数会报地址字段不等于请求地址。

4.3 把单条命令变成自动化用例

单条命令验证只是起点。协议一致性测试最怕的是重复劳动,我通常会把常用业务操作整理成一张用例表:

用例编号操作预期结果
TC-01读正向有功总电能返回91H应答帧,数据域6字节电能值
TC-02读电压返回数据域包含A/B/C三相电压
TC-03广播校时表计无应答或按规约返回,时间同步成功
TC-04读事件记录若无事件返回空记录标识
TC-05错误帧响应发送错误地址,返回错误应答帧

每个用例写成 Python 函数,断言解析结果:

def test_read_energy(port, addr): result = read_meter(port, addr, bytes.fromhex('01000000')) assert result.get('cs_ok') is True assert result['ctrl'].endswith('91') print('[PASS] read energy, data=', result['data'])

把这些用例跑一轮,能覆盖绝大多数厂商的协议实现雷区,尤其是"该回帧但不回帧""地址域顺序混乱""校验码算错"这类问题,在自动化下曝光率非常高。

5. 现场问题排查速查:全是踩过坑的经验

5.1 排查思路:链路、帧、业务三层分离

遇到具体问题,我习惯按三层排查:先看物理链路通不通,再看帧格式和校验对不对,最后看业务数据和状态是否符合预期。千万别一上来就疯狂抓包,不然很容易被各种无关的广播帧带偏。

链路层,重点查 A/B 接反、波特率、共地、终端上下拉电阻;帧格式层,重点查地址域顺序、控制码方向位、长度字节、CS 累加和;业务层,重点查数据标识 DI 是否匹配、费率/时标参数、表计是否处于载波休眠或自动轮显状态。

5.2 常见问题速查表

问题现象可能原因排查方法
发送帧后无任何响应485 A/B 接反、波特率不匹配、未共地示波器或串口工具确收
返回错误帧或地址错误地址域反序没处理、长度字段和实际数据不一致用 parse_frame 核对地址和长度
数据域全 0 或明显不对DI 数据标识配错、费率对象选择错误对照规约表核对 DI
偶发超时,重发后正常半双工总线冲突、载波信道抢占增大帧间隔、减少并发命令
CS 校验总是失败手工构造时把结束符 16H 算进累加和严格按帧格式排除结束符
698.45 连接失败TLS 证书不匹配、CONNECT 流程未完成先抓 APDU 看是否在建立安全连接阶段失败
主站和集中器交互超时心跳和登录态异常、链路序号不连续检查登录响应和心跳周期

5.3 几条只有踩过坑才懂的经验

第一个经验,工具比人可靠。凡是需要重复操作的验证,一定要脚本化。手动在终端里拼帧,拼到第五十次的时候一定会打错校验码,而脚本一次都不会错。

第二个经验,虚假的表计模拟器会害死人。我之前用一套自写模拟器测逻辑,表计模拟器永远秒回正确帧,一到现场发现真实表响应慢、偶发补帧,程序直接超时。测试工具必须支持注入延时、注入错误帧、模拟异常长度,才能把边界情况提前暴露出来。

第三个经验,协议版本归档要做进工具。现场最怕的是不知道当前电表固件、集中器固件支持哪个协议版本。我的工具在解析结果里会附带协议类型和版本字段,这样现场排查时可以优先判断是不是版本差异。

6. 最后再分享一点扩展思路

协议集合测试工具做到后面,已经不局限于 645 和 698.45 了。把上行协议也纳进来之后,整套工具可以模拟主站,直接驱动集中器做批量下行抄表,也能模拟终端接主站,验证主站的登录、参数下发、事件上报逻辑。进一步可以加进模糊测试的思路,随机改帧里某个字节,验证终端和主站会不会异常复位或漏处理,这一层往往能提前发现安全性和健壮性问题。

如果团队有条件,还可以把协议解析和用例引擎拆成服务,接到内部 CI 里,每次固件提交都自动跑一遍全协议回归。个人觉得,这套方案的长期价值不在于省了多少手工测试时间,而在于把"协议实现是否正确"这件事变成了可量化、可追溯的自动化结果。踩过那么多坑之后,我的体会是:通信协议调试没有捷径,但好的工具能把"看不懂协议"变成"慢慢看懂了协议",这个过程本身就是最大的收获。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询