1. 从零开始:为什么电表地址是“敲门砖”?
大家好,我是老张,在智能电表和能源数据采集这个行当里摸爬滚打了十几年。今天咱们不聊那些虚头巴脑的概念,就聊一个最实际、也最让新手头疼的问题:怎么从一台电表里把它的“身份证号”——也就是电表地址——给读出来。不管你是做系统集成的、做运维的,还是自己捣鼓智能家居想接个电表,第一步都得过这一关。
你可能要问了,电表地址不就是印在表壳上的一串数字吗?没错,但那只是物理标签。在通信的世界里,电表需要一个能被协议识别的逻辑地址,用来在一条总线上(比如一个小区单元的所有电表都接在同一根RS485总线上)唯一地标识自己。没有这个地址,你的集中器或采集器就像在一个人山人海的广场上喊“喂!”,没人知道你在叫谁,自然也就读不到任何数据。
所以,读取电表地址,是整个数据采集流程的“握手”环节,是确认通信链路畅通、协议对上的关键一步。国内电表通信,绕不开两个核心协议:DLT645和DLT698。DLT645更老牌、更通用,几乎是个电表都支持;而DLT698是后来推出的,功能更强大,面向更高级的用电信息采集系统。很多新电表是两者都支持的。咱们今天的目标,就是手把手教你,用这两个协议,把电表地址“掏”出来。
2. 动手前的准备:硬件连接与软件环境
工欲善其事,必先利其器。在发送任何指令之前,你得先和电表“连上线”。别小看这一步,我见过太多人卡在这里,最后发现是线接反了或者串口没选对。
2.1 硬件连接:RS485 vs. 红外
电表通常提供两种通信接口:RS485和红外。你可以把RS485想象成“网线”,稳定、可靠,适合长期固定安装;红外则是“遥控器”,临时抄表、现场调试时用起来很方便。
RS485连接(最常用):你需要准备一个USB转RS485的转换器(市面上几十块钱一个),以及一对双绞线(最好带屏蔽)。电表端子一般标有A(+)、B(-)或485+、485-。连接时务必注意:
- 你的转换器的A+接电表的A+,B-接电表的B-。接反了通常也能工作,但通信距离和抗干扰能力会大打折扣。
- 如果总线上挂接了多块电表,所有电表的A+和B-分别并联在一起,形成总线结构。记得在总线的最远端两个电表上,A、B线之间并联一个120欧姆的终端电阻,这个能有效抑制信号反射,是长距离稳定通信的秘诀,很多人会忽略。
红外连接:你需要一个USB转红外串口的适配器(注意是串口红外,不是家电遥控那种)。对准电表上的红外窗口(一般是个黑色或深色的透明罩子),距离最好在几厘米到一米以内,中间不要有遮挡。红外通信对环境光比较敏感,强光直射可能会干扰通信,尽量在室内或背光处操作。
2.2 软件准备:一个顺手的串口调试工具
不需要复杂的开发环境,一个好用的串口调试助手就行。我个人常用的是AccessPort、友善串口助手或者开源的CuteCom(Linux下)。关键是要能方便地设置端口参数、发送和接收十六进制(HEX)数据。千万别用那种只能发字符串的玩具软件,我们处理的都是二进制数据帧。
串口参数设置(重中之重!):这是第一个坑点。无论是645还是698协议,默认的串口参数大多是:
- 波特率:
2400或9600bps。这是两个最常用的,我建议先从9600开始试。 - 数据位:
8 - 停止位:
1 - 校验位:
Even(偶校验)
一定要在串口调试工具里准确设置这四项。特别是校验位,设成“无校验”是绝对收不到正确回复的。设置好后,先打开串口,如果软件有“流控制”选项,一律选“无”或“None”。
3. DLT645协议读取地址:经典“广播寻址”法
DLT645-2007版是目前的主流,它的帧结构相对简单直接。读取地址的核心思路是发送一个“广播帧”,这个帧里的地址字段用通配符AA填充,总线上所有支持645协议的电表都会响应,在回复帧中带上自己的真实地址。
3.1 广播指令逐字节解析
咱们把原始文章里的那条指令拿出来,掰开揉碎了讲:FE FE FE 68 AA AA AA AA AA AA 68 13 00 DF 16
前导帧(唤醒):
FE FE FE这不是必须的,但强烈建议加上。你可以把它理解成打电话时的“喂?喂?”,用来唤醒处于低功耗休眠状态的电表。有些电表反应“慢半拍”,多发几个FE能提高成功率。帧起始符:
68标志一帧数据的开始,固定不变。地址域(通配符):
AA AA AA AA AA AA这里是关键!6个字节的AA(十进制170)就是广播地址。它告诉所有电表:“不管你们是谁,都请回答我。” 注意,这里是BCD码,AA在BCD码里是个无效数字,因此被定义为广播地址。帧起始符(再次):
68645协议的帧结构是[起始符][地址域][起始符][控制码][数据长度][数据域][校验码][结束符],所以这里又出现一个68。控制码:
130x13这个代码的含义是“读数据”,且是广播读。这是读取地址的固定值。数据域长度:
00因为我们现在只是问地址,不需要附带任何额外的数据,所以长度是0。校验码:
DF这是从第一个68开始,到00(数据域长度)为止,所有字节的算术累加和,只取最低的一个字节(和除以256的余数)。68+AA+AA+AA+AA+AA+AA+68+13+00 = 0x01DF,取低8位就是DF。校验码是电表判断帧是否完整、有无传输错误的重要依据。结束符:
16固定值,标志一帧数据的结束。
发送技巧:在串口调试工具里,选择“HEX发送”模式,把上面这串字节一个不差地输进去,点击发送。记得勾选“发送新行”之类的选项,我们不需要换行符,就发送纯十六进制数据。
3.2 解析返回的地址
如果一切顺利,电表会回复一串数据。我们以示例回复为例:FE FE FE FE 68 14 35 09 03 12 24 68 93 06 47 68 3C 36 45 57 B1 16
- 同样,开头的
FE是前导帧,电表有时会回送更多。 - 找到第一个
68,之后紧跟的6个字节14 35 09 03 12 24,就是这块电表的物理地址(通信地址)!注意,这是BCD码,我们需要把它转换成十进制数字来阅读:0x143509031224转换成十进制就是143509031224。这个号码通常和电表外壳上的条形码或编号的后几位对应。 - 别急,地址在数据域里又出现了一次。在第二个
68之后,控制码93表示“读数据应答”,数据长度06表示后面有6个字节的数据,这6个字节是47 68 3C 36 45 57。这里有个645协议特有的“加33H”规则:数据域中的BCD码,每个字节都加了0x33(即十进制的51)进行混淆。所以,真实的地址需要每个字节减去0x33:47 - 33 = 1468 - 33 = 353C - 33 = 0936 - 33 = 0345 - 33 = 1257 - 33 = 24得到的结果14 35 09 03 12 24,和地址域里的完全一致。这一步验证了地址的正确性。
实战经验:拿到这6字节地址后,请立刻记下来。以后你想读这块电表的电压、电流、电量等数据,就需要用这个真实地址替换掉广播指令里的AA AA AA AA AA AA,进行单点通信。
4. DLT698协议读取地址:更结构化的“服务请求”
DLT698.45协议比645复杂得多,它更像一个完整的物联网通信协议,有明确的客户端、服务器、服务请求的概念。读取地址不再是简单的广播,而是通过一个特定的“对象属性描述符(OAD)”来请求。
4.1 广播指令的构成解析
来看这条698广播指令:68 17 00 43 45 AA AA AA AA AA AA 10 DA 5F 05 01 03 40 01 02 00 00 90 0F 16
起始符和长度域:
68 17 0068是起始符。17 00是长度域,表示后面从控制域开始到帧校验前的字节数。注意这里是低字节在前(Little-Endian),0x0017就是十进制的23个字节。控制域和地址域:
43 45 AA AA AA AA AA AA 1043:控制域,这里表示这是一个“发送/确认”帧,由客户端(主站)发往服务器(电表)。45:服务器地址标志,0x45代表后面的服务器地址是6字节的。AA AA AA AA AA AA:同样是6字节的广播地址,全AA。10:客户机地址(即主站自己的地址),0x10是一个常用默认值。
帧头校验:
DA 5F这是对前面“控制域”到“客户机地址”所有字节计算的一个CRC16校验码,算法是CRC-16/XMODEM。很多开源库都有这个函数。它的作用是确保帧头信息在传输中没有出错。服务请求核心 - APDU:
05 01 03 40 01 02 00 00从这里开始是协议数据单元,是真正的“业务内容”。05 01:GetRequestNormal,普通读取请求。03:PIID(调用标识),用来匹配请求和响应,可以自己定义,这里用0x03。40 01 02 00:这就是关键!对象属性描述符(OAD)。0x40010200这个“魔法数字”在698协议里,就代表“服务器的逻辑设备地址属性”。你可以把它理解为向电表查询“你叫什么名字?”的标准问法。00:时间标签,没有就填00。
帧校验和结束符:
90 0F 1690 0F是整个帧(从长度域到时间标签)的CRC16校验码。16是结束符。
4.2 解读响应并提取地址
电表的响应帧看起来很长,我们抓重点:68 2D 00 ... 05 14 35 09 03 12 24 10 ... 85 01 03 40 01 02 00 01 09 06 24 12 03 09 35 14 ... 16
找到服务器地址:在控制域
C3之后,服务器地址标志05表示地址是6字节,紧接着的14 35 09 03 12 24就是电表的逻辑设备地址!这和645协议读出的地址是同一个东西。698协议在地址域直接给出了明文,不需要加减0x33。验证数据域:继续往下找到APDU响应部分
85 01(GetResponseNormal),后面的OAD40 01 02 00和我们发送的请求对应。数据域长度09 06表示后续有6个字节的数据,这6个字节是24 12 03 09 35 14。注意看:24 12 03 09 35 14这串数字,是不是很眼熟?把它和地址域的14 35 09 03 12 24对比一下。你会发现,数据域里的地址是倒序存放的!这是698协议中OCTET-STRING类型数据的一种常见表现。24 12 03 09 35 14倒过来就是14 35 09 03 12 24。这再次验证了地址的正确性。
698协议的特点:它的回复非常结构化,包含了请求确认、数据、甚至可能的状态信息,信息量比645大得多。解析时一定要有耐心,按照协议文档一层层剥开。
5. 实战排坑指南:当指令发出去没反应时
按照上面步骤操作,大部分标准电表都能读出地址。但如果没反应,别慌,这是常态。我们可以按照以下顺序排查,这也是我踩过无数坑总结的“保姆级”流程:
第一步:检查物理连接与电源
- RS485:用万用表直流电压档测A、B线间的电压。静态时(不通信)应该有个稳定的电压(通常A>B),发送数据时指针会摆动。如果电压为0或极低,检查接线是否松动、转换器是否损坏、电表通信端子是否有电。
- 红外:确保红外适配器已正确安装驱动,并被系统识别为串口。尝试稍微调整角度和距离。有些电表的红外接收窗口有保护膜,记得撕掉。
- 电源:确保电表本身已上电。有些电表在断电后通信模块也不工作。
第二步:确认串口参数与操作
- 再三核对波特率、数据位、停止位、校验位。一个字符都不能错。最常见的就是校验位设成了“无”或“奇校验”。
- 确认你选择的串口号是对的(在设备管理器里查看),并且没有被其他软件占用。
- 发送时,务必是HEX格式,而不是文本格式。发送
AA和发送字符串“AA”是天壤之别。
第三步:尝试所有可能的波特率
- 依次尝试
1200,2400,4800,9600,19200。645协议常用2400和9600;698协议常用2400,9600,19200。红外接口有时会用1200这个较低的速率。 - 每次更换波特率后,重新打开串口,再发送指令。
第四步:调整广播指令细节
- 前导帧:试试多发几个
FE,比如FE FE FE FE FE。也试试不发前导帧,直接发68开头的帧。 - 指令间隔:连续快速发送指令可能会让电表处理不过来。在两条指令之间手动添加500ms到1秒的间隔。
- 指令本身:从网上或不同资料里找到的广播指令字节可能略有差异(特别是698协议),可以多找一两个版本试试。
第五步:终极判断如果以上所有方法(两种协议、多种波特率、多种指令变体)都试遍了,依然没有任何回复,那么极有可能:
- 电表不支持DLT645/698协议:尤其是一些非常老旧的表,或者某些出口到特殊地区的表。它们可能只支持厂家私有的Modbus RTU协议,或者其他非标协议。这时你必须找到电表的原版说明书,按照它的协议来。
- 通信接口硬件故障:可能是电表内部的通信芯片或光耦坏了,也可能是你的转换器坏了。有条件的话,换一个同型号的好电表,或者换一个转换器交叉测试一下。
我遇到过最棘手的一次,是一个工地上的电表,怎么都读不出来。最后发现,电表厂商为了“省事”,把RS485的A、B线定义反了,而且还在内部串了一个非标准的电阻。按照说明书接就不通,把A、B线对调一下,立刻通了。所以,实践出真知,千万别完全迷信说明书。
6. 从地址读取到数据采集:下一步做什么?
恭喜你!当你成功读取到那6字节的地址时,最艰难的一步已经迈过去了。这个地址是你的“通行证”。接下来,你就可以进行真正的数据采集了。
对于DLT645协议,你想读电压,就查协议文档里的“数据标识码”,比如0x02010100代表A相电压。构造一个数据域包含此标识码的帧,用真实地址替换广播地址发送出去,电表就会回复电压值。解析回复时,同样要注意数据域的“减33H”规则和数据的单位(比如电压可能是0.01V/位)。
对于DLT698协议,世界更丰富但也更复杂。你需要查阅它的“对象字典”,找到对应数据项的OAD。比如,总有功电能的OAD可能是00 00 01 00。然后构造类似的GetRequestNormal帧去请求。698协议的数据类型非常丰富,有浮点数、整数、字符串、数组等,解析时需要根据返回的“数据类型标签”来正确处理。
最后给个真心建议:动手操作时,准备一个笔记本,或者建一个Excel表格,记录下每块电表的型号、通信地址、使用的协议、有效的波特率。这些信息在日后维护、扩容时会让你省下大量重复调试的时间。协议通信就像和电表对话,第一次握手成功建立了信任,后面的交流就会顺畅很多。