3. 数据编码规则:BCD码与HEX码的区别、数据格式标识(DI0-DI3)、数据项与数据单元的映射关系

各位同学,咱们今天聊点实在的。做智能电表协议开发,编码规则是绕不开的第一道坎。我见过不少新手,上来就对着报文发呆——这串数字到底是啥意思?是BCD码还是HEX码?搞不清楚,后面全乱套。

说白了,国网协议里的数据,不是你想怎么存就怎么存的。它有严格的规矩。今天我就把BCD码、HEX码、DI标识、还有数据映射关系,一次性给你讲透。

3.1 BCD码与HEX码:两个世界的数据表达

先问个问题:电表里存的是数字,但数字怎么表示?

嗯,这里有两种主流方式:BCD码和HEX码。它们看着像,但本质完全不同。

3.1.1 BCD码(Binary-Coded Decimal)

BCD码,说白了就是用4个二进制位表示一个十进制数字。0到9,每个数字占半个字节(4位)。

举个例子:十进制数 1234,用BCD码表示就是 0x12 0x34。你看,两个字节,每个字节的高4位和低4位分别代表一个十进制位。

我个人习惯:在调试电表参数时,看到 0x12 0x34 这种数据,第一反应就是BCD码。千万别当成十六进制数去算,否则你会得到 0x1234 = 4660,完全不是一回事。

BCD码特点:

  • 每个半字节(4位)表示0-9,不会出现A-F
  • 适合显示十进制数值,比如电表读数、电压值
  • 存储效率低,但人类可读性好

3.1.2 HEX码(十六进制码)

HEX码就简单了,它就是标准的十六进制数。一个字节表示0x00到0xFF,对应十进制0到255。

比如:0x12 0x34 作为HEX码,它代表的是 0x1234 = 4660(十进制)。

我在项目中遇到过:有一次现场调试,电表上报的电压值是 0x01 0xF4。新来的同事按BCD码解析,得到 01F4,以为电压是1.94V。我一看就知道不对,这明显是HEX码,0x01F4 = 500,实际电压是500V(乘以系数0.1后是50.0V)。

避坑指南:我曾经因为BCD和HEX搞混,导致一个项目的数据解析全盘重来。记住:国网协议中,电能量数据多用BCD码,瞬时量数据多用HEX码。但这不是绝对的,一定要看数据格式标识(DI)。

3.2 数据格式标识(DI0-DI3):数据的身份证

你想想看,电表里那么多数据——电压、电流、功率、电量、费率……每个数据怎么编码?怎么知道它是BCD还是HEX?

答案就是:数据格式标识,也就是DI0到DI3这四个字节。

DI0-DI3,每个字节都有特定含义。我习惯把它们看作数据的「身份证」——看到DI,就知道这个数据是什么类型、什么格式、什么单位。

3.2.1 DI0:数据项类别

DI0决定了数据属于哪一大类。比如:

DI0值 数据类别 举例
0x00 电能量 正向有功总电能
0x01 最大需量 当前最大需量
0x02 变量 电压、电流、功率
0x03 事件记录 掉电事件、编程事件
0x04 参变量 费率时段、密码

3.2.2 DI1:数据项编号

DI1进一步细分。比如DI0=0x02(变量)时,DI1=0x01表示A相电压,DI1=0x02表示B相电压。

3.2.3 DI2:数据格式与单位

这个字节最关键。它告诉你:

  • 数据是BCD还是HEX
  • 数据长度是多少字节
  • 小数点的位置
  • 单位是什么

举个例子:DI2 = 0x12,表示:

  • 高4位(0x1):BCD码,2字节长度
  • 低4位(0x2):小数点后2位

那么数据 0x12 0x34 解析出来就是 1234,再除以100,得到 12.34

我的小技巧:DI2的低4位表示小数位数,这个值乘以4就是实际的小数点偏移。比如低4位是0x2,表示小数点后2位。但要注意,有些特殊值(如0xF)表示无小数点。

3.2.4 DI3:费率与通道标识

DI3用于区分费率(尖、峰、平、谷)和通道(主副表、三相)。

比如:DI3=0x01表示费率1(尖),DI3=0x02表示费率2(峰)。

3.3 数据项与数据单元的映射关系

好了,现在你知道数据怎么编码了。但还有一个问题:电表里那么多数据,怎么找到我要的那个?

这就涉及到数据项与数据单元的映射关系。

数据项:就是具体的某个数据,比如「正向有功总电能」。

数据单元:是数据在报文中的实际存储位置。

映射关系,说白了就是:给定一个DI(数据格式标识),就能找到对应的数据单元。

3.3.1 映射规则

国网协议里,映射关系是固定的。我总结了一个口诀:

DI0定大类,DI1定小类
DI2定格式,DI3定费率
组合起来查表,数据单元自然现

具体来说:

  1. 用DI0和DI1组成一个索引,查数据项定义表
  2. 找到对应的数据项名称、数据类型、长度
  3. 用DI2确定编码格式(BCD/HEX)和小数点位置
  4. 用DI3确定费率或通道
  5. 最终在报文中找到对应的数据单元

3.3.2 实际例子

假设收到一个数据请求:DI0=0x00, DI1=0x01, DI2=0x12, DI3=0x01

解析过程:

  • DI0=0x00:电能量类
  • DI1=0x01:正向有功
  • DI2=0x12:BCD码,2字节,小数点后2位
  • DI3=0x01:费率1(尖)

那么对应的数据单元就是:正向有功尖费率电能,数据格式为BCD,长度2字节,单位kWh,小数点后2位。

如果报文中的数据是 0x01 0x23,那么实际值就是 1.23 kWh

重要提醒:映射关系不是一成不变的。不同厂家、不同版本的电表,映射表可能有细微差异。我建议你在开发时,一定要拿到电表厂家提供的《数据项定义表》,以那个为准。

3.4 总结与经验

好了,这一章的内容就这些。我最后再唠叨几句:

  • BCD和HEX的区别:记住,BCD是「用二进制表示十进制」,HEX是「用二进制表示十六进制」。看到0x12 0x34,先看DI2,再决定怎么解析。
  • DI0-DI3:这是数据的身份证,一定要吃透。我建议你把常用的DI组合背下来,调试时能省不少时间。
  • 映射关系:别死记硬背,理解规则后,查表就行。我当年做第一个项目时,把映射表打印出来贴在工位上,天天看,慢慢就熟了。

下一章,我会讲报文帧结构——数据在线上到底怎么传的。到时候你会看到,今天学的编码规则,在报文中是怎么体现的。

嗯,今天就到这里。有问题随时问我。