1 进入DLMS模式

某些电表一开始未进入DLMS传送模式,需要进行切换。按照IEC62056-21协议模式E的规定,先发送以下内容:

  1. 典型的串口设置为:波特率300,校验位Even,数据位7。(也可校验位无,数据位8)

  2. 开启传送请求信息:

    /?!CRLF
    2FH3FH21H0DH0AH
  3. 协议和波特率调整:

    ACKVZYCRLF
    06H32H35H32H0DH0AH

    V:ASCII码的2,代表使用HDLC。

    Y:ASCII码的2,代表使用HDLC。

    Z:ASCII码,波特率选择。

    • 1:600Bd

    • 2:1200Bd

    • 3:2400Bd

    • 4:4800Bd

    • 5:9600Bd

    • 6:19200Bd

  4. 根据以上设置,此时波特率可调整为9600,进入DLMS数据传送。

2 DLMS概况

2.1 基本的传送流程

使用DLMS传送数据,需要先建立链路层连接,建立应用层连接,再进行数据读取或写入,最后关闭连接,如下图所示:

 

2.2 分层结构

DLMS协议传送的每一帧数据都是一个分层结构,典型的结构如下图所示:

 

基本上可以理解为,在原数据的头尾加上一些数据,即为进入下一层。

3 HDLC层

3.1 数据结构

HDLC层数据结构如下所示:

7EHFrame FormatFrame LengthDest AddrSrc AddrControlHCSInformationFCS7EH
111nn12n21

Frame Format:A0H或A8H,A0H表示后面没有后续帧,A8H表示数据未完待续。实际上这个字节有一部分用来描述长度,但一般长度不会超过256,所以可以简单理解。

Frame Length:不包括头尾两个7EH的长度。

HCS和FCS都是校验和,HCS从Frame Format到Control,FCS从Frame Format到Information。具体算法见附录1。

其他内容在下面详述,Dest Addr和Src Addr在3.2节,Control在3.3节。Information是应用层数据,从第8章开始讲述。

3.2 地址

HDLC地址有三种表示方式,分别是1字节、2字节和4字节。

  • 1字节

    编码地址=逻辑设备地址*2+1

  • 2字节

    编码地址(第1字节)=逻辑设备地址*2

    编码地址(第2字节)=物理设备地址*2

  • 4字节

    编码地址(第1字节)=逻辑设备地址高位*2

    编码地址(第2字节)=物理设备地址高位*2

    编码地址(第3字节)=逻辑设备地址低位*2+1

    编码地址(第4字节)=物理设备地址低位*2+1

比较典型的目标地址是1,源地址是16。都用1字节表示方式。

3.3 控制码

3.3.1 帧类型

常用帧的格式如下:

帧类型帧结构
IR R R P S S S 0
RRR R R P 0 0 0 1
RNRR R R P 0 1 0 1
SNRM1 0 0 P 0 0 1 1
DISC0 1 0 P 0 0 1 1
UA0 1 1 F 0 0 1 1
DM0 0 0 F 1 1 1 1
FRMR1 0 0 F 0 1 1 1
UI0 0 0 P 0 0 1 1

RRR为接收序号,SSS为发送序号。P为是否允许回应,一般为1。F为是否发送结束,在窗口大小超过1的时候使用。

RRR和SSS初始都为0。一般情况下,发送数据时,SSS需要加1。接收数据时,RRR会被加1。下次再发送数据,相对于前一帧,RRR加1。如此反复。当RRR或SSS超过7时,复位为0。

在2.1节可以看到各种帧的传送方式,而数据的读取和写入使用I帧,如果需要分段续传则使用RR帧。

3.3.2 控制码计算

为了描述方便,进行以下定义:SF为上次发送的帧,RF为上次收到的帧。SF_R表示SF的RRR部分,SF_S表示SF的SSS部分。RF同理。那么对于本次要发送的帧,其RRR和SSS的计算如下表所示:

SF类型RF类型本次要发送的帧类型RRRSSS
IIISF_R+1SF_S+1
IRRISF_RRF_R
RRIIRF_S+1RF_R
/IRRRF_S+10
/RRRRSF_R0

4 LLC层

LLC层数据结构如下所示:

E6HE6H/E7H00H应用数据
111n

第2个字节,下行为E6H,上行为E7H。也就是发送是E6H,收到的回复是E7H。

5 多层数据组合

本章讲述如何拼合出一条最终发送的命令。在2.2节中,可以看到所有指令都是一个分层结构。

应用层的数据将会在后面介绍,我们现在假定应用层数据如下所示:

应用层数据需要放在LLC层中,也就是在前面加上一个LLC头,变为:

LLC头E6 E6 00
应用层数据05 01 02 2B C8

上面的数据再放到HDLC层中。

假设目标地址是1,源地址是16,那么Dest Addr=03H,Src Addr=21H。

上面字节串的长度是8,整个HDLC帧的长度(除去头尾7EH)将会是17,也就是11H。

控制码我们假定上次接收的是32H,那么这次发送,SSS加1,也就是34H。

HCS和FCS我们暂不计算。

那么HDLC帧将会如下所示:

HDLC头7E A0 11 03 21 34 HCS HCS
LLC头E6 E6 00
应用层数据05 01 02 2B C8
HDLC尾FCS FCS 7E

上面的字节串就是要发送的内容。

6 建立连接

6.1 建立链路连接

建立链路连接,需发送SNRM帧。SNRM帧可以没有用户数据,也就是在HDLC层,HCS和Information皆为空,Control为SNRM(93H)。

正确的回复是一个UA帧,也就是回复内容的Control是UA(73H)。回复中会带有通信数据长度和窗口大小等信息。

以下是示例报文:

发送:

7E帧头
A0 07无后续帧,长度7
03目标地址1
21源地址16
93控制码:SNRM
0F 01HCS
7E帧尾

接收:

7E帧头
A0 1E无后续帧,长度30
21源地址16
03目标地址1
73控制码:UA
C3 7AHCS
81格式标识
12长度18
05 01发送时应用层最大长度
80最大长度128
06 01接收时应用层最大长度
3E最大长度63
07 04发送窗大小
00 00 00 01一对一帧关系
08 04接收窗大小
00 00 00 01一对一帧关系
07 22FCS
7E帧尾

6.2 建立应用连接

建立应用连接的内容相当复杂,包含了是否加密、使用LN还是SN、读写权限等参数。为了简单起见,使用默认配置即可。

发送的AARQ和回复的AARE都是I帧。

以下是示例报文:

发送:7E A0 2B 03 21 10 FB AF E6 E6 00 60 1D A1 09 06 07 60 85 74 05 08 01 02 BE 10 04 0E 01 00 00 00 06 5F 1F 04 00 20 1E 5D FF FF E8 3F 7E
接收:7E A0 37 21 03 30 6C 7C E6 E7 00 61 28 A1 09 06 07 60 85 74 05 08 01 02 A2 03 02 01 00 A3 05 A1 03 02 01 00 BE 0F 04 0D 08 00 06 5F 1F 04 00 00 02 00 09 60 FA 00 BE A3 7E

7 应用层概况

7.1 LN和SN

读取或写入一个物理量,需要给物理量一个编码。这个编码的表示方式有两种:

  • 逻辑名LN,使用ClassId和OBIS编码表示,同一物理量此编码相同。

  • 短名SN,一个二字节数,代表了一个地址,同一物理量在不同设备上有可能有不同的地址。

7.1.1 ClassId

ClassId具体内容见IEC62056-62,常用的ClassId如下表所示:

ClassId数据类别
1Data
3Register
4Extended register
5Demand register
6Register activation
7Profile generic
8Clock
9Script table
10Schedule
11Special days table
12Association SN
15Association LN
17SAP assignment
20Activity calendar
21Register monitor
22Singl action schedule
26Utility

7.1.2 OBIS

OBIS具体内容见IEC62056-61,它是一个由六字节组成的编码,表示成ABCDEF。

  • A:1为与电有关的对象,其他有与气体、冷水、热水有关的对象,但我们一般只会用到与电有关。

  • B:通道,0是无指定通道,1是通道1,2是通道2,以此类推。一般用0或1都可以。

  • C:具体的物理量,例如是正向有功功率、反向视在功率、电流、电压等。

  • D:物理量的统计方法,有瞬时值、积分值、最大值等。C和D的组合示例如下:

    C含义D含义总编码总含义
    1正向有功功率7瞬时值1.7正向有功功率
    8时间积分值1.8正向有功电能
  • E:0为总量,1为费率1,2为费率2,以此类推。

  • F:一般不用,为255。

常用的OBIS编码见附录2。

7.2 数据类型

在DLMS中一个数据可以是各种类型,包括数字、字符串、数组、结构体等。以下是常用的类型:

编码类型字节数
01HArray指定元素个数
02HStructure指定成员个数
03HBoolean1
05HInt324
06HUInt324
09HOctet-string指定长度
0AHVisible-string指定长度
0FHInt81
10HInt162
11HUInt81
12HUInt162

需要指定长度的类型,后续1个字节是长度,否则是数据内容。

例如,int a=7的表示为:

05 00 00 00 07

string b="book"的表示为:

0A 04 62 6F 6F 6B

byte[] c=[0x04,0x05]的表示为:

01 02 11 04 11 05

struct d={"fox",0x02}的表示为:

02 02 0A 03 66 6F 78 11 02

8 读取SN数据

8.1 请求帧

为了简单起见,只读一个地址。请求帧的内容如下:

读要求读数量访问选择地址
05H01H02H2字节

访问选择02H表示没有附加参数,默认使用。

8.2 回复帧

收到的回复帧内容如下:

读响应响应数量成功具体数据
0CH01H00H

具体数据的内容是数据类型+数据值,例如一个Int32类型,类型码是06H,接下来的4个字节描述数值。不同的数据类型可参考7.2节。

8.3 分段数据

当数据过长,需要分段传送时,数据会通过多帧进行传送。第一帧会是完整的数据,后续帧则不会包含LLC头和回复头。如下所示:

第一帧HDLC头LLC头回复头数据1HDLC尾
后续帧HDLC头数据2HDLC尾

解析数据时,需要先把数据接收完,然后拼合所有数据,再进行解析。

9 写入SN数据

9.1 请求帧

为了简单起见,只写一个地址。请求帧的内容如下:

写要求写数量访问选择地址数据数量具体数据
06H01H02H2字节01H

访问选择02H表示没有附加参数,默认使用。

9.2 回复帧

收到的回复帧内容如下:

写响应响应数量成功
0DH01H00H

9.3 响应结果

回复帧中的响应结果解析如下:

响应码解析
00Hsuccess
01Hhardware-fault
02Htemporary-failure
03Hread-write-denied
04Hobject-undefined
09Hobject-class-inconsistent
0BHobject-unavailable
0CHtype-unmatched
0DHscope-of-access-violated
0EHdata-block-unavailable
0FHlong-get-aborted
10Hno-long-get-in-progress
11Hlong-set-aborted
12Hno-long-set-in-progress
FAHother-reason

10 获取LN数据

10.1 请求帧

请求帧的内容如下所示:

获取请求Normal模式Invoke-Id-And-Priority结果类型ClassIdOBIS属性
C0H01H81H00H1字节6字节02H 00H

前3个字节可以固定为表中数值,一般不需修改。结果类型00H为数据,01H为访问结果。属性02H为数值,03H是单位和比率。

数值、单位和比率的关系举例:

数值比率单位数据
263788-3m3263.783 m3
5933Wh593k Wh

常见单位编码列表见附录3。

10.2 回复帧

回复帧的内容如下所示:

获取回复Normal模式Invoke-Id-And-Priority结果类型数据内容
C4H01H81H00H

具体数据的内容是数据类型+数据值,例如一个Int32类型,类型码是06H,接下来的4个字节描述数值。不同的数据类型可参考7.2节。

附录1 校验和算法

以下为校验码计算代码:

public static ushort CountFCS16(byte[] buff, int index, int count)
{
    int FCS16 = 0xFFFF;
    for (int pos = index; pos < index + count; ++pos)
    {
        FCS16 = ((FCS16 >> 8) ^ FCS16Table[(FCS16 ^ buff[pos]) & 0xFF]) & 0xFFFF;
    }
    FCS16 = ~FCS16;
    FCS16 = ((FCS16 >> 8) & 0xFF) | (FCS16 << 8);
    return (ushort)FCS16;
}
​
private static readonly ushort[] FCS16Table = {
    0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
    0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
    0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
    0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
    0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
    0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
    0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
    0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
    0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
    0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
    0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
    0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
    0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
    0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
    0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
    0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
    0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
    0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
    0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
    0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
    0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
    0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
    0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
    0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
    0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
    0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
    0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
    0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
    0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
    0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
    0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
    0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
};

附录2 常见OBIS编码

在以下的编码中,只列出CD部分,A部分为1,B部分为0或1,E部分为0,F部分为255。

物理量相位方向有无功编码
电能有功15.8
正向有功1.8
无功3.8
视在9.8
反向有功2.8
无功4.8
视在10.8
A正向有功21.8
无功23.8
视在29.8
反向有功22.8
无功24.8
视在30.8
B正向有功41.8
无功43.8
视在49.8
反向有功42.8
无功44.8
视在50.8
C正向有功61.8
无功63.8
视在69.8
反向有功62.8
无功64.8
视在70.8
功率有功15.7
正向有功1.7
无功3.7
视在9.7
反向有功2.7
无功4.7
视在10.7
A正向有功21.7
无功23.7
视在29.7
反向有功22.7
无功24.7
视在30.7
B正向有功41.7
无功43.7
视在49.7
反向有功42.7
无功44.7
视在50.7
C正向有功61.7
无功63.7
视在69.7
反向有功62.7
无功64.7
视在70.7
电压A32.7
B52.7
C72.7
92.7
电流A31.7
B51.7
C71.7
91.7
电网频率14.7

附录3 常见单位编码

以下列出电学常见单位编码:

代码单位
27W
28VA
29var
30Wh
31Vah
32varh
33A
35V
44Hz

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐