多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

电表地址读取实战:DLT645与DLT698协议报文解析与调试技巧

电表地址读取实战:DLT645与DLT698协议报文解析与调试技巧 干过电表调试的人都有这种经历配电房里几十块表排成一排铭牌要么被灰尘糊住要么字迹早就看不清了新装的表也还没来得及建档。你一个个去对编号抄下来再贴标签累不说还容易错。其实不用这么折腾两根线怼到RS485口上发一条读表地址指令表号自己就会报上来。这就是DLT645和DLT698协议里最典型的入门操作——电表地址读取。这篇文章不绕弯子直接讲清楚两代协议下怎么把表号读出来。DLT645这边从帧格式、校验和计算到一条完整的读地址指令一步一步拆给你看DLT698.45这边虽然协议结构和645完全是两个世界但读表号的思路是一样的我也会把实操路径和真实报文的解析方法讲明白。适合电力采集调试、智能化改造、项目运维的朋友也适合刚接触电表通信准备入行的工程师。1. 先搞清楚为什么这两个协议这么重要1.1 读表地址到底解决什么问题先说一个最实际的应用场景。一个配电改造项目下来几十块智能电表要接入采集系统第一件事就是建档——每块表的通信地址要和安装位置对应起来。地址对不上后面采集的数据全串到别人头上轻则抄错数重则整个台区线损算错。这时候如果有一台还能通信的表直接发一条读地址指令表号自己报上来比对着铭牌抄快了不止一倍。还有更麻烦的情况表装好了调试人员发现主站那边收不到数据大概率是表地址设置错了。现场又不能把表拆下来看只能通过通信口把表地址读出来核对。读表地址这个功能几乎是所有电表调试工作的前置步骤。另外很多电表在出厂时通信地址默认是表号但有些项目在安装时会重新设置地址。读出来的“通信地址”不一定等于铭牌表号这个后面我在应答解析里会详细说。1.2 DLT645和DLT698.45的定位差异DLT645是我国多功能电能表通信协议的标准分1997版和2007版实际现场跑的大多是645-2007。它设计得比较“轻”一个报文几十个字节一条帧把控制码、数据标识、数据域全塞进去适合在RS485这种低速链路上跑。DLT698.45则是面向对象的用电信息数据交换协议为了满足智能电网大规模数据交互的需求数据结构比645复杂得多。它引入了对象、属性、方法这些概念读一个数据要像访问对象一样发请求链路层还用了HDLC帧格式带转义和分帧机制。说句实在话645是“一个馒头吃一天”的实用派698是“满汉全席摆一桌”的架构派。现场调645表拿个串口助手手拼报文完全可行调698表手拼报文的成本就高多了但这不代表读表地址这个需求变了只是实现路径变了。2. DLT645读表地址一条指令搞定2.1 645报文结构速览DLT645的帧结构不算复杂一整帧报文由这么几部分组成字段长度说明起始符1字节固定0x68地址域6字节表通信地址BCD码低字节在前起始符1字节固定0x68控制码1字节决定这条帧干什么事数据域长度1字节数据域字节数L数据域L字节随控制码变化有的帧没有数据域L0校验码1字节从第一个起始符到数据域末尾累加和的低字节结束符1字节固定0x16地址域是整个帧最容易搞错的地方。它存的是BCD码每个字节表示两位十进制数字而且是低字节在前。比如表号123456789012BCD展开是12 34 56 78 90 12放到地址域里要反过来A0到底依次是12 90 78 56 34 12两头的顺序别记串了。2.2 读表地址指令逐字节解析读表地址是645协议里的一个特殊命令主站发出去的帧长固定控制码是0x13数据域长度为0。整帧报文长这样68 AA AA AA AA AA AA 68 13 00 DF 16逐字节拆解一下68帧起始符。AA AA AA AA AA AA地址域。读表地址请求不指定具体表所以地址域固定填AA。68第二个起始符。13控制码。0x13是主站请求读表地址。00数据域长度说明后面没有数据域。DF校验码。16结束符。从站收到这条帧后如果应答正常返回的帧长这样68 [表地址6字节] 68 93 00 [CS] 16控制码变成了0x93表示从站正常应答读表地址数据域长度仍然是0。也就是说表号直接在帧的地址域里带回来了不需要在数据域里找。这里有个容易忽略的点返回的地址域是从站自己的通信地址不是主站请求里的AA。读取的时候把返回的6字节地址反转顺序再按BCD码转成十进制就是这块表在通信协议里使用的地址。2.3 校验和怎么算为什么网上有DF和77两个版本很多人第一次算645校验和都会踩同一个坑——到底包不包括第一个起始符0x68。标准里CS是从帧起始符开始到数据域结束所有字节累加后取低8位。注意它把第一个0x68算进去了。以读表地址命令为例CS (68 AA AA AA AA AA AA 68 13 00) mod 256十进制算一下68 170×6 68 19 12471247取低8位就是1247 - 1024 223也就是0xDF。这正好对应上面命令帧里的校验码DF。如果你算出来的CS是0x77说明你把第一个起始符68漏掉了170×6 68 19 11071107 mod 256 0x63不对重算1020 104 19 11431143 mod 256 0x77。对0x77就是漏掉第一个68的结果。网上有人贴0x77的版本就是因为校验范围算错了。实际组帧时建议用软件统一计算别手算特别是数据域比较长的时候手算很容易出错。3. 5分钟实操用串口把表号读出来3.1 硬件准备和接线实操需要的东西很简单一个USB转RS485模块两根线一台装了串口助手的电脑。RS485接线用A/B或者D/D-标记电表那边同理A对A、B对B。接反了不会烧设备但就是收不到应答所以没反应时第一步先检查A/B线是不是接反了。有个小建议最好用带隔离的USB转RS485模块。现场环境复杂电表和电脑之间地电位可能有差异隔离模块能少烧几个USB口。我是吃过亏的普通模块烧了之后电脑USB口也一起报销维修成本够买三个隔离模块了。如果电表是导轨表安装在配电箱里RS485端子通常标在后面接线时注意别碰带电部分安全第一。3.2 串口参数与工具选择DLT645-2007默认串口参数是波特率2400、8数据位、偶校验、1停止位即2400 E 8 1。有些表支持更高波特率比如9600或者19200但第一次通信时最好先用默认参数等建立连接后再根据电表说明书修改。串口工具推荐几类简单的用SSCOM或者UartAssist能发十六进制字节、能看返回数据就够想要协议分析的用格西烽火这种支持自定义报文模板的工具可以自动计算校验和避免手拼出错。工具不追求功能多关键是能清晰地收发十六进制数据。发送时把帧按十六进制填进去比如68 AA AA AA AA AA AA 68 13 00 DF 16点发送正常情况下电表会在几百毫秒内返回一帧。3.3 用Python发送读地址指令串口助手适合临时验证但如果你要批量读取或者集成到自己的采集程序里还是用代码更靠谱。下面这段Python脚本可以完成发送和解析依赖pyserial库import serial def calc_cs(prefix: bytes) - int: return sum(prefix) 0xFF # 读表地址命令68 AA AA AA AA AA AA 68 13 00 prefix bytes.fromhex(68 AA AA AA AA AA AA 68 13 00) cs calc_cs(prefix) frame prefix bytes([cs, 0x16]) print(TX: frame.hex().upper()) ser serial.Serial( portCOM5, baudrate2400, bytesize8, parityE, stopbits1, timeout1, ) ser.flushInput() ser.write(frame) resp ser.read(64) print(RX: resp.hex().upper()) if len(resp) 14 and resp[0] 0x68 and resp[-1] 0x16: addr_in_frame resp[1:7] # 低字节在前的地址域 addr_bcd addr_in_frame[::-1] # 反转成正常BCD顺序 meter_no .join(f{b:02X} for b in addr_bcd) print(表号: meter_no) else: print(未收到有效应答)脚本核心就是两件事发送时算好校验码接收时反转地址域并转BCD。打印出来的表号如果出现A到F的字符说明这块表地址不是纯十进制BCD码或者厂家有其他编码规则需要查表确认。注意如果总线上的表不止一块所有表都可能响应读地址请求返回的数据会乱成一团。正确的做法是读取表地址时保证总线上只有一块表在线。这个我在后面的避坑里还会再强调。3.4 应答报文解析实例假设现场有一块表通信地址是123456789012。在主站端发送读地址命令后收到的原始帧可能是68 12 90 78 56 34 12 68 93 00 19 16怎么把这帧转成表号按顺序做两步第一步取出地址域6个字节12 90 78 56 34 12。第二步反转字节顺序变成12 34 56 78 90 12。因为每个字节本来就是BCD码直接按字节转成两位十进制数字得到12 34 56 78 90 12也就是123456789012。这里再说细一点如果表地址被重新设置过读出来的通信地址可能和铭牌上的表号不一致。遇到这种情况以读出来的为准因为采集系统里配的就是这个地址。如果一个项目里表太多可以读一块、贴一块标签避免后面混淆。4. DLT698.45读表地址协议变了思路别变4.1 698和645的本质区别DLT698.45和DLT645表面上都是电表通信协议但底层设计逻辑完全不一样。645是“面向寄存器”的协议你想读什么就发一条带数据标识的指令数据存在哪个寄存器就去哪个寄存器取698是“面向对象”的协议把电表内部的数据封装成一个个对象比如计量点、设备信息、事件记录每个对象再挂一堆属性读取时按对象属性和路径来访问。链路层也不同。645用的是简化帧格式起始符加结束符中间塞字段698采用的是HDLC帧格式以0x7E开头结尾遇到特殊字符还要做转义处理。这就导致你拿到一帧698报文如果还用645那套“找68、找控制码、找CS”的思路去拆大概率是一头雾水。所以网上一堆人在求“dlt698真实报文”我特别理解。不是不懂协议而是手里没有一份真实的帧做对照光看标准又抽象得不行。4.2 698读表号的操作路径在698协议里读表号这个操作没有一个像645的0x13那样固定的“读地址控制码”。表号属于设备信息类对象更常见的做法是通过“读对象属性”服务去获取。具体对象标识OAD不同厂家定义可能有差异但通常在电表的说明书中会有明确说明。实操中我建议分三步走第一步确认这块表是否真的支持698。很多新表是双协议RS485口默认跑698但可以通过配置切换成645兼容模式。如果你发698报文没反应很可能是表当前跑在645模式两个协议不互通。第二步用厂家提供的调试工具或者支持698的通用调试软件。这类工具一般会内置“读取设备地址”或者“读取表号”的按钮你只需要选好串口和波特率点一下按钮工具就自动把应用层请求封装好往链路层丢再往串口发。这一步避免了手拼HDLC帧的麻烦。第三步如果你要自己写程序实现698报文的封装和解析那就必须得啃标准。链路层要考虑HDLC帧格式包括7E帧头帧尾、转义规则、CRC校验应用层要构造APDU包括协议类型、服务类型、对象属性标识、数据域等。这不是看一篇文章就能搞定的强度建议先找一份真实的抓包报文对照标准逐字节拆一遍。4.3 真实698报文应该怎么拆拿到一帧真实的698报文不要直接拿645的套路去套。我的经验是先分层剥洋葱。第一层是链路层。找开头和结尾的0x7E。注意帧中间的0x7E会被转义成0x7D 0x5E0x7D本身也会被转义成0x7D 0x5D所以不能简单看到0x7E就以为是新帧的开头。先把转义字符还原再按HDLC结构把链路层帧头、地址、控制、分帧序号、帧校验等字段拆出来。第二层是应用层。链路层的数据部分就是APDU也就是应用层协议数据单元。在这里找服务类型和对象标识比如连接请求、读取请求、读取响应。读表号的应答中服务类型和对象标识字段后面跟着的数据才是表号内容。第三层才是真正的数据解析。这层通常比较简单把对象属性返回的十六进制转成BCD或者ASCII字符串就能得到表号。我没有在这里贴一段完整的698报文示例是因为不同厂家的OAD和服务参数差异不小盲目贴一个例子反而容易误导人。最靠谱的方式是抓你自己现场那台表的包然后用标准里的帧格式和APDU结构逐层定位。这也是我为什么说想学698就得靠“真实报文标准对照”这两样东西。5. 现场高频问题与避坑实录5.1 常见问题速查表现象可能原因处理办法发送后完全无响应RS485的A/B线接反交换A/B线再试发送后完全无响应串口参数不对检查波特率、校验位645默认2400 E 8 1发送后完全无响应表当前运行在698模式不支持645切换到645兼容模式或换用698工具有响应但CS校验失败校验和计算范围不对确认包含第一个起始符0x68读出来的地址明显不对没有反转地址域字节顺序低字节在前的6字节需反转再转BCD读取时总线上多块表同时应答读地址命令广播性质多表都会响应保证总线上只有一块表在线645报文能通但698报文不通协议模式冲突看电表配置确认运行协议再操作5.2 几条亲测有效的经验第一条经验现场找不到表号时优先看铭牌和出厂合格证别一上来就接串口。如果表已经在通电运行能抄到铭牌就抄铭牌看不清再接通信线。这不是说通信没用而是效率问题通信是兜底方案。第二条经验读表地址是一个“一次性”操作总线上最好只有一块表这件事千万记牢。如果配电箱里有多块表挂在同一根RS485总线上你得把其他表断电或者临时断开其他表的通信线留一块表在线才能正确读到地址。多条表同时响应返回的数据会互相叠加解析出来乱七八糟。有几次我为了省事没断开其他表结果读出来一帧四不像的报文排查了很久才发现是总线上有其他表在抢答。第三条经验645读出来的地址未必等于铭牌表号。很多采集项目里电表的通信地址被主站或者调试工具重新设置过读取应答帧里返回的是通信地址不是表计铭牌上的出厂编号。建档时一定字段分清楚一个填通信地址一个填表号别混在一起。第四条经验调试698表时建议先在主站端开启抓包监听。很多厂家调试工具可以显示发送和接收的原始报文把这些报文保存下来后续不管是写程序还是排障都是最珍贵的一手资料。我看过太多人遇到问题只会截图截图里又没有原始报文最后只能靠猜。最后再分享一个细节不管是645还是698调试电脑和电表之间用的USB转RS485模块质量会直接影响通信稳定性。便宜的模块在波特率9600以下问题不大一旦波特率拉高或者现场干扰大丢帧概率倍增。如果发现有时候能读出来有时候读不出来先别怀疑表换个隔离模块再试多半就稳了。
返回列表