DLMS协议开发指引
某些电表一开始未进入DLMS传送模式,需要进行切换。按照IEC62056-21协议模式E的规定,先发送以下内容:典型的串口设置为:波特率300,校验位Even,数据位7。(也可校验位无,数据位8)V:ASCII码的2,代表使用HDLC。Y:ASCII码的2,代表使用HDLC。Z:ASCII码,波特率选择。1:600Bd2:1200Bd3:2400Bd4:4800Bd5:9600Bd6:19200B
1 进入DLMS模式
某些电表一开始未进入DLMS传送模式,需要进行切换。按照IEC62056-21协议模式E的规定,先发送以下内容:
-
典型的串口设置为:波特率300,校验位Even,数据位7。(也可校验位无,数据位8)
-
开启传送请求信息:
/ ? ! CR LF 2FH 3FH 21H 0DH 0AH -
协议和波特率调整:
ACK V Z Y CR LF 06H 32H 35H 32H 0DH 0AH V:ASCII码的2,代表使用HDLC。
Y:ASCII码的2,代表使用HDLC。
Z:ASCII码,波特率选择。
-
1:600Bd
-
2:1200Bd
-
3:2400Bd
-
4:4800Bd
-
5:9600Bd
-
6:19200Bd
-
-
根据以上设置,此时波特率可调整为9600,进入DLMS数据传送。
2 DLMS概况
2.1 基本的传送流程
使用DLMS传送数据,需要先建立链路层连接,建立应用层连接,再进行数据读取或写入,最后关闭连接,如下图所示:
2.2 分层结构
DLMS协议传送的每一帧数据都是一个分层结构,典型的结构如下图所示:
基本上可以理解为,在原数据的头尾加上一些数据,即为进入下一层。
3 HDLC层
3.1 数据结构
HDLC层数据结构如下所示:
7EH | Frame Format | Frame Length | Dest Addr | Src Addr | Control | HCS | Information | FCS | 7EH |
---|---|---|---|---|---|---|---|---|---|
1 | 1 | 1 | n | n | 1 | 2 | n | 2 | 1 |
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 帧类型
常用帧的格式如下:
帧类型 | 帧结构 |
---|---|
I | R R R P S S S 0 |
RR | R R R P 0 0 0 1 |
RNR | R R R P 0 1 0 1 |
SNRM | 1 0 0 P 0 0 1 1 |
DISC | 0 1 0 P 0 0 1 1 |
UA | 0 1 1 F 0 0 1 1 |
DM | 0 0 0 F 1 1 1 1 |
FRMR | 1 0 0 F 0 1 1 1 |
UI | 0 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类型 | 本次要发送的帧类型 | RRR | SSS |
---|---|---|---|---|
I | I | I | SF_R+1 | SF_S+1 |
I | RR | I | SF_R | RF_R |
RR | I | I | RF_S+1 | RF_R |
/ | I | RR | RF_S+1 | 0 |
/ | RR | RR | SF_R | 0 |
4 LLC层
LLC层数据结构如下所示:
E6H | E6H/E7H | 00H | 应用数据 |
---|---|---|---|
1 | 1 | 1 | n |
第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 01 | HCS |
7E | 帧尾 |
接收:
7E | 帧头 |
---|---|
A0 1E | 无后续帧,长度30 |
21 | 源地址16 |
03 | 目标地址1 |
73 | 控制码:UA |
C3 7A | HCS |
81 | 格式标识 |
12 | 长度18 |
05 01 | 发送时应用层最大长度 |
80 | 最大长度128 |
06 01 | 接收时应用层最大长度 |
3E | 最大长度63 |
07 04 | 发送窗大小 |
00 00 00 01 | 一对一帧关系 |
08 04 | 接收窗大小 |
00 00 00 01 | 一对一帧关系 |
07 22 | FCS |
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 | 数据类别 |
---|---|
1 | Data |
3 | Register |
4 | Extended register |
5 | Demand register |
6 | Register activation |
7 | Profile generic |
8 | Clock |
9 | Script table |
10 | Schedule |
11 | Special days table |
12 | Association SN |
15 | Association LN |
17 | SAP assignment |
20 | Activity calendar |
21 | Register monitor |
22 | Singl action schedule |
26 | Utility |
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中一个数据可以是各种类型,包括数字、字符串、数组、结构体等。以下是常用的类型:
编码 | 类型 | 字节数 |
---|---|---|
01H | Array | 指定元素个数 |
02H | Structure | 指定成员个数 |
03H | Boolean | 1 |
05H | Int32 | 4 |
06H | UInt32 | 4 |
09H | Octet-string | 指定长度 |
0AH | Visible-string | 指定长度 |
0FH | Int8 | 1 |
10H | Int16 | 2 |
11H | UInt8 | 1 |
12H | UInt16 | 2 |
需要指定长度的类型,后续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 请求帧
为了简单起见,只读一个地址。请求帧的内容如下:
读要求 | 读数量 | 访问选择 | 地址 |
---|---|---|---|
05H | 01H | 02H | 2字节 |
访问选择02H表示没有附加参数,默认使用。
8.2 回复帧
收到的回复帧内容如下:
读响应 | 响应数量 | 成功 | 具体数据 |
---|---|---|---|
0CH | 01H | 00H |
具体数据的内容是数据类型+数据值
,例如一个Int32类型,类型码是06H,接下来的4个字节描述数值。不同的数据类型可参考7.2节。
8.3 分段数据
当数据过长,需要分段传送时,数据会通过多帧进行传送。第一帧会是完整的数据,后续帧则不会包含LLC头和回复头。如下所示:
第一帧 | HDLC头 | LLC头 | 回复头 | 数据1 | HDLC尾 |
---|---|---|---|---|---|
后续帧 | HDLC头 | 数据2 | HDLC尾 |
解析数据时,需要先把数据接收完,然后拼合所有数据,再进行解析。
9 写入SN数据
9.1 请求帧
为了简单起见,只写一个地址。请求帧的内容如下:
写要求 | 写数量 | 访问选择 | 地址 | 数据数量 | 具体数据 |
---|---|---|---|---|---|
06H | 01H | 02H | 2字节 | 01H |
访问选择02H表示没有附加参数,默认使用。
9.2 回复帧
收到的回复帧内容如下:
写响应 | 响应数量 | 成功 |
---|---|---|
0DH | 01H | 00H |
9.3 响应结果
回复帧中的响应结果解析如下:
响应码 | 解析 |
---|---|
00H | success |
01H | hardware-fault |
02H | temporary-failure |
03H | read-write-denied |
04H | object-undefined |
09H | object-class-inconsistent |
0BH | object-unavailable |
0CH | type-unmatched |
0DH | scope-of-access-violated |
0EH | data-block-unavailable |
0FH | long-get-aborted |
10H | no-long-get-in-progress |
11H | long-set-aborted |
12H | no-long-set-in-progress |
FAH | other-reason |
10 获取LN数据
10.1 请求帧
请求帧的内容如下所示:
获取请求 | Normal模式 | Invoke-Id-And-Priority | 结果类型 | ClassId | OBIS | 属性 |
---|---|---|---|---|---|---|
C0H | 01H | 81H | 00H | 1字节 | 6字节 | 02H 00H |
前3个字节可以固定为表中数值,一般不需修改。结果类型00H为数据,01H为访问结果。属性02H为数值,03H是单位和比率。
数值、单位和比率的关系举例:
数值 | 比率 | 单位 | 数据 |
---|---|---|---|
263788 | -3 | m3 | 263.783 m3 |
593 | 3 | Wh | 593k Wh |
常见单位编码列表见附录3。
10.2 回复帧
回复帧的内容如下所示:
获取回复 | Normal模式 | Invoke-Id-And-Priority | 结果类型 | 数据内容 |
---|---|---|---|---|
C4H | 01H | 81H | 00H |
具体数据的内容是数据类型+数据值
,例如一个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 | |||
电压 | A | 32.7 | ||
B | 52.7 | |||
C | 72.7 | |||
零 | 92.7 | |||
电流 | A | 31.7 | ||
B | 51.7 | |||
C | 71.7 | |||
零 | 91.7 | |||
电网频率 | 14.7 |
附录3 常见单位编码
以下列出电学常见单位编码:
代码 | 单位 |
---|---|
27 | W |
28 | VA |
29 | var |
30 | Wh |
31 | Vah |
32 | varh |
33 | A |
35 | V |
44 | Hz |
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)