注:本文为 “ IEC104 协议” 相关合辑。
未整理去重,如有内容异常请看原文。
图片清晰度限于引文原状。
IEC 104 电力规约详细解读 (一) - 报文结构、报文分类、ASDU
张二狗和苗翠花已于 2024-04-23 08:08:13 修改
协议一般规则:
-
平衡方式传输;也就是说每一个过程的会话,没有规定谁从头发起,双方均可
-
一般情况下配电主站作为 TCP 的客户端,配电终端作为 TCP 的服务器
-
TCP 的默认端口号是 2404
一、报文结构

APCI 应用规约控制信息;ASDU 应用服务数据单元 (和 101 协议里定义一致);APDU 应用规约数据单元。
-
启动字符 68H 定义了数据流中的起点
-
APDU 的长度域定义了 APDU 体的长度,它包括 APCI 的四个控制域八位位组和 ASDU。第一个被计数的八位位组是控制域的第一个八位位组,最后一个被计数的八位位组是 ASDU 的最后一个八位位组。ASDU 的最大长度限制在 249 以内,因为 APDU 域的最大长度是 253(APDU 最大值 = 255 减去启动和长度八位位组),控制域的长度是 4 个八位位组。
-
控制域定义了确保报文不丢失和重复传送的控制信息(也就是发送序列号和接收序列号),报文传输启动 / 停止,以及传输连接的监视等。控制域的计数器机制是根据 ITU-T X.25 标准中推荐的 2.3.2.2.1 至 2.3.2.2.5 来定义的
二、报文分类(APCI)
2.1 S 格式 (Numbered supervisory functions, 编号的监视功能格式)

S 帧格式报文不用来传送信息,只用来确认对方的发送序列号。比如,双方可以按频率发送,比如接收 8 帧 I 帧回答一帧 S 帧,也可以要求接收 1 帧 I 帧就应答 1 帧 S 帧,当然也可以不要求(S 帧内容示例参考例 1)。因为 S 帧回复确认的序列号在 byte3、byte4 两个字节,并且 byte3 的 bit1 位置固定是 0,所以在使用 S 帧回复确认时,只需在接收报文的发送序列号 + 2 就可以(参考例 2)。
举例 1:68 04 01 00 0A 00 (接收序列号 = 5)
举例 2:
RECV: 68 FA 6C 67 84 00 0D 1E 03 00 01 00 E8 ... 省略 ...
6C 67 低前高后转换成 0x676C 再右移一位就是 0x33B6 最终发送序列号 10 进制也就是 13238
SEND: 68 04 01 00 6E 67
接受序列号 = 接收报文的发送序列号 + 1 = 13239 = 0x33B7 左移一位 0x676E
再低前高后转换 就是 6E 67
综上得出其实就是在接收来的报文的发送序列号的 byte1 的 bit2 位置上 + 1,也就成了对应 10 进制上 + 2
2.2 U 格式 (Unnumbered control function, 不编号的控制功能格式)

在同一时刻,TESTFR, STOPDT 或 STARTDT 中只有一个功能可以被激活。所以 U 帧格式的控制欲第一个字节就只有 6 种情况,分别是 0x83(TESTER 确认)0x43(TESTER 命令)0x23(STOPDT 确认)0x13(STOPDT 命令)0x0B(START 确认)0x07(START 命令)
举例:68 04 07 00 00 00 START 命令
U 帧和 S 帧是没有 ASDU 的,所以这两种类型的报文长度也就是 6 字节
2.3 I 格式 (Information Transmit Format, 编号的信息传输格式)

遥信、遥测、遥控、遥调、总召、对时等都需要使用 I 格式传送。
举例:后面几篇文章详细说
三、I 格式帧的 ASDU
ASDU(应用服务数据单元),协议原文格式最好去 101 协议去看看,会比较详细。104 和 101 是一样的

-
类型标识符(1 byte)。解析来区分属于哪个过程。比如 0x01 单点遥信、0x0D 段浮点遥测
-
可变结构限定词(1byte)。bit0-bit6 :信息对象的个数 bit7: SQ 信息对象地址是否连续,1 代表连续,也就是信息对象 2 的地址就是信息对象 1 的地址 + 1,信息对象 2 无需再给出它的地址;0 代表不连续,每个信息对象都必须给出自己的地址
-
传送原因(2byte)。
-
ASDU 公共地址。一般是一个变电站一个地址
-
信息对象
-
信息对象地址。也就是点表对应的点位,遥测信息也就是测量点标号
-
信息元素集。对应的值,按照不同的类型标识去解析
-
时标。CP56Time2a 格式 7byte
-
限定词。按照报文类型确定有无限定词。总召唤限定词、复位进行限定词、初始化原因、品质描述词、设置命令限定词

IEC 104 电力规约详细解读 (二) - 总召唤
张二狗和苗翠花 已于 2024-04-23 08:09:51 修改
1 功能简述
总召唤功能是在初始化以后进行,或者是定期进行总召唤,以刷新主站的数据库。总召唤时请求子站传送所有的过程的变量实际值。定期进行总召唤的周期的是一个系统参数,可以是 15 分钟或者更长的时间。
总召唤的内容包括子站的遥信、遥测等信息。这些信息一般在上报的时候会用 SQ=1 的地址连续的报文进行上报,当然也可以不连续,视情况而定。
2 通信过程
-
先由主站向子站发送总召唤命令帧
-
子站收到后,如果否定,子站会送否定确认,传输结束;如果确认,则子站回送总召唤确认帧
-
子站连续地向主站传送数据。包括但不仅限于不带品质描述词的遥测帧、单点遥信帧、远动终端帧
-
子站信息传送完毕后,发送总召唤结束帧,总召唤过程结束

注意事项:
-
为了让通信双方同步实时数据库,由于中断原因引起的重建链路后的第一次总召唤过程不允许被打断
-
对于非中断原因(如手动总召唤)引起的总召唤回答可以被高优先级数据打断;回答总召唤应该使用 SQ=1 压缩格式传输
3 报文结构

4 报文实例解读
这一部分的实例是主站的视角去看,也就是说 SEND 就是主站发送子站接收;RECV 就是子站发送主站接收。
SEND: 68 0E 00 00 00 00 64 01 06 00 01 00 00 00 00 14
-
启动字符:68H
-
APDU 长度:0EH 14 个字节
-
控制域四个八位组:00 00 00 00 第一个字节的 bit0 为 0,第三个字节的 bit0 为 0,所以是 I 格式帧,发送序列号 0,接收序列号 0
-
类型标识:64H CON<100>:= 总召唤命令
-
可变结构限定词:01H SQ=0 地址不连续 信息元素个数 1, 单个
-
传送原因:06 00 -0006H <Cause<6>:= 激活
-
ASDU 公共地址:01 00 =0001H 通常为 RTU 地址
-
第一个信息元素的地址:00 00 00 =000000H
-
第一个信息元素的值(召唤限定词):14H 固定 20
RECV: 68 0E 00 00 02 00 64 01 07 00 01 00 00 00 00 14
-
启动字符:68H
-
APDU 长度:0EH 14 个字节
-
控制域四个八位组:00 00 02 00 第一个字节的 bit0 为 0,第三个字节的 bit0 为 0,所以是 I 格式帧,发送序列号 0,接收序列号 1
-
类型标识:64H CON<100>:= 总召唤命令
-
可变结构限定词:01H SQ=0 地址不连续 信息元素个数 1, 单个
-
传送原因:07 00 -0007H <Cause<7>:= 激活确认
-
ASDU 公共地址:01 00 =0001H 通常为 RTU 地址
-
第一个信息元素的地址:00 00 00 =000000H
-
第一个信息元素的值(召唤限定词):14H
RECV: 68 1A 02 00 02 00 03 04 14 00 01 00 01 00 00 01 02 00 00 02 03 00 00 01 04 00 00 02
-
启动字符:68H
-
APDU 长度:1AH 26 个字节
-
控制域四个八位组: 02 00 02 00 第一个字节的 bit0 为 0,第三个字节的 bit0 为 0,所以是 I 格式帧,发送序列号 1,接收序列号 1
-
类型标识:03H CON<3>:= 双点遥信
-
可变结构限定词:04H SQ=0 地址不连续 信息元素个数 4
-
传送原因:14 00 -0014H <Cause<20>:= 响应站召唤
-
ASDU 公共地址:01 00 -0001H 通常为 RTU 地址
-
第一个信息元素的地址:01 00 00 =000001H
-
第一个信息元素的值:01H 分位
-
第二个信息元素的地址:02 00 00 =000002H
-
第二个信息元素的值:02H 合位
-
第三个信息元素的地址:03 00 00 =000003H
-
第三个信息元素的值:01H 分位
-
第四个信息元素的地址:04 00 00 =000004H
-
第四个信息元素的值:02H 合位
具体双点遥信的报文结构后面在遥信的章节详细说
RECV: 68 2A 04 00 02 00 0D 04 14 00 01 00 01 40 00 00 78 DB 3F 00 02 40 00 00 D8 90 42 00 03 40 00 00 F4 92 42 00 04 40 00 60 50 9A 3F 00
-
启动字符:68H
-
APDU 长度:2AH 42 个字节
-
控制域四个八位组: 04 00 02 00 第一个字节的 bit0 为 0,第三个字节的 bit0 为 0,所以是 I 格式帧,发送序列号 2,接收序列号 1
-
类型标识:0DH CON<13>:= 测量值,短浮点数
-
可变结构限定词:04H SQ=0 地址不连续 信息元素个数 4
-
传送原因:14 00 -0014H <Cause<20>:= 响应站召唤
-
ASDU 公共地址:01 00 -0001H 通常为 RTU 地址
-
第一个信息元素的地址:01 40 00 =004001H =16385 (在 2002 版的协议中规定遥测点位地址范围是 0x4001 ~ 0x5000)
-
第一个信息元素的值:00 78 DB 3F //Float.intBitsToFloat(0x3fdb7800) =>1.715
-
第一个信息元素的品质描述词:00H
-
第二个信息元素的地址:02 40 00 =004002H
-
第二个信息元素的值:00 D8 90 42 //Float.intBitsToFloat(0x4290d800) =>72.422
-
第二个信息元素的品质描述词:00H
-
第三个信息元素的地址:03 40 00 =004003H
-
第三个信息元素的值:00 F4 92 42 //Float.intBitsToFloat(0x4292f400) =>73.477
-
第三个信息元素的品质描述词:00H
-
第四个信息元素的地址:04 40 00 =004004H
-
第四个信息元素的值:60 50 9A 3F //Float.intBitsToFloat(0x3f9a5060) =>1.206
-
第四个信息元素的品质描述词:00H
具体短浮点遥测的报文结构后面在遥侧的章节详细说
RECV: 68 0E 06 00 02 00 64 01 0A 00 01 00 00 00 00 14
-
启动字符:68H
-
APDU 长度:0EH 14 个字节
-
控制域四个八位组: 06 00 02 00 第一个字节的 bit0 为 0,第三个字节的 bit0 为 0,所以是 I 格式帧,发送序列号 3,接收序列号 1
-
类型标识:64H CON<100>:= 总召唤命令
-
可变结构限定词:01H SQ=0 地址不连续 信息元素个数 1 单个
-
传送原因:0A 00 -000AH <Cause<10>:= 激活终止
-
ASDU 公共地址:01 00 -0001H 通常为 RTU 地址
-
第一个信息元素的地址:00 00 00
-
第一个信息元素的值(召唤限定词):14H 固定 20
IEC 104 电力规约详细解读 (三) - 遥信
张二狗和苗翠花已于 2024-04-23 08:11:38 修改
1. 功能简述
遥信,、即状态量,是为了将断路器、隔离开关、中央信号等位置信号上送到监控后台的信息。遥信信息包括:反应电网运行拓扑方式的位置信息。如断路器状态、隔离开关状态;反应一次二次设备工作状况的运行信息,如变压器本体冷却器全停,断路器弹簧未储能等;反应电网异常和一次二次设备异常的事故信息、预告信息等。如差动保护出口,切换继电器同时失磁等
硬遥信和软遥信
-
硬遥信:测控装置端子排对应的遥信(即有电缆接线的),如断路器、隔离开关信号等。
-
软遥信:除硬遥信之外的遥信,主要是一些保护事件,如过流段以及自动化嵌入的应用功能模块产生的运行信息。如五防闭锁提示信息等。
全遥信和变位遥信
-
全遥信:如果没有遥信状态发生变化,测控装置每隔一定周期,定时向监控后台发送本站所有遥信状态信息
-
变位遥信:当某遥信状态发生改变,测控装置立即向监控后台插入发送变位遥信的信息。后台收到变遥信报文后,与遥信历史库比较后发现不一致,于是提示该遥信状态发生改变
单点遥信、双点遥信
-
单点遥信:就是用一位表示一个遥信量,比如断路器位置,只采用一个常开辅助接点,值为 1 或 0,用 1 表示合位,0 表示分位
-
双点遥信:就是用两位表示一个遥信量,需采集动合 / 动断两个辅助接点位置。当动合点值等于 1,且动断点值等于 0,即值为 10,则认为断路器在合位;当动合点值等于 0,且动断点值等于 1,即值为 01,则认为断路器在分位;当两个位置都为 1 或都为 0,则都被认为位置不确定

2. 通信过程

3. 报文结构
遥信报文结构总结起来可以分为三种:
-
信息对象序列(SQ=0),不带时标的单 / 双点信息遥信报文格式
-
信息对象序列(SQ=0),带长时标的单 / 双点信息遥信报文格式
-
单个信息中信息元素序列(SQ=1),不带时标的单 / 双点信息遥信报文格式
按照 DL/T 634.5104-2009 规定,带长时标的单 / 双点信息遥信报文并不存在信息元素序列(SQ=1)的情况
遥信报文的类型标识符 TI 分为 01H(单点信息)03H(双点遥信); 传输原因 COT 分为 03H(突发)05H(被请求)14H(响应站召唤); 遥信对象的地址范围在 2022 版协议中规定为 1H~4000H


4. 报文实例解读
-
例 1 SQ=0, 不带时标的单点遥信
68 0E F8 AD 12 05 01 01 03 00 01 00 A6 01 00 01
-
启动字符:68H
-
APDU 长度:0EH 14 个字节
-
控制域四个八位组:F8 AD 12 05 第一个字节的 bit0 为 0,第三个字节的 bit0 为 0,所以是 I 格式帧,发送序列号 22268,接收序列号 649
-
类型标识:01H CON<1>:= 单点信息
-
可变结构限定词:01H SQ=0 地址不连续 信息元素个数 1, 单个
-
传送原因:03 00 -0003H <Cause<3>:= 突发
-
ASDU 公共地址:01 00 =0001H 通常为 RTU 地址
-
第一个信息元素的地址:A6 01 00 =0001A6H = 第 422 点
-
第一个信息元素的值:01 合位
-
例 2 SQ=0, 不带时标的双点遥信
68 0E 04 00 02 00 03 01 03 00 01 00 01 00 00 02
-
启动字符:68H
-
APDU 长度:0EH 14 个字节
-
控制域四个八位组:04 00 02 00 第一个字节的 bit0 为 0,第三个字节的 bit0 为 0,所以是 I 格式帧;发送序列号 2,接收序列号 1
-
类型标识:03H CON<3>:= 双点信息
-
可变结构限定词:01H SQ=0 地址不连续 信息元素个数 1, 单个
-
传送原因:03 00 -0003H <Cause<3>:= 突发
-
ASDU 公共地址:01 00 =0001H 通常为 RTU 地址
-
第一个信息元素的地址:01 00 00 =000001H = 第 1 点
-
第一个信息元素的值:02 合位
-
例 3 SQ=1, 不带时标的双点遥信
68 10 02 00 02 00 03 83 14 00 01 00 01 01 00 02 02 01
-
启动字符:68H
-
APDU 长度:10H 16 个字节
-
控制域四个八位组:02 00 02 00 第一个字节的 bit0 为 0,第三个字节的 bit0 为 0,所以是 I 格式帧;发送序列号 1,接收序列号 1
-
类型标识:03H CON<3>:= 双点信息
-
可变结构限定词:83H SQ=1 地址连续 信息元素个数 3
-
传送原因:14 00 -0014H <Cause<20>:= 响应站召唤
-
ASDU 公共地址:01 00 =0001H 通常为 RTU 地址
-
第一个信息元素的地址:01 01 00 =000101H = 第 257 点
-
第一个信息元素的值:02 合位 第 257 点
-
第二个信息元素的值:02 合位 第 258 点
-
第三个信息元素的值:01 分位 第 259 点
IEC 104 电力规约详细解读 (四) - 遥测
张二狗和苗翠花已于 2024-04-23 08:12:46 修改
1. 功能简述
遥测,顾名思义就是测量值,由从站上报到主站,有标度化,归一化,短浮点三种类型,再根据是否带有品质描述、是否带试标划分为更细的类型。通常推荐使用短浮点数方式上送。遥测信息对象地址范围为 4001H~5000H.
2. 通信过程

3. 报文结构

-
归一化值。2 字节,最高位 D15 为符号位 0 正数 1 负数;D14~D0 为数据位取值范围 0-32767
-
短浮点数,4 字节,IEEE STD745 标准定义,不再赘述,如果你是用 Java 开发,可以直接调用 Float.intBitsToFloat(int)
-
标度化值。
4. 报文实例解读
RECV: 68 12 0E 00 10 00 0D 01 03 00 01 00 02 40 00 00 78 DB 3F 00
-
启动字符:68H
-
APDU 长度:12H 18 个字节
-
控制域四个八位组:0E 00 10 00 第一个字节的 bit0 为 0,第三个字节的 bit0 为 0,所以是 I 格式帧,发送序列号 7,接收序列号 8
-
类型标识:0DH CON<13>:= 带品质描述词的短浮点数
-
可变结构限定词:01H SQ=0 地址不连续 信息元素个数 1, 单个
-
传送原因:03 00 -0003H <Cause<3>:= 突发
-
ASDU 公共地址:01 00 =0001H 通常为 RTU 地址
-
第一个信息元素的地址:02 40 00 =004002H = 第 16836 点
-
第一个信息元素的值:00 78 DB 3F //Float.intBitsToFloat(0x3fdb7800) =>1.715
-
第一个信息元素的品质描述词:00 未溢出 / 未被闭锁 / 未被取代 / 当前值 / 有效
IEC 104 电力规约详细解读 (五) - 遥控
张二狗和苗翠花已于 2024-07-17 11:47:35 修改
1. 功能简述
遥控命令用来实现对一个可操作设备状态的改变。在配电自动化中,包括单点命令和双点命令。通常,单点命令用于控制单点信息对象;双点命令用于控制双点信息对象。
2. 通信过程
主站下发遥控选择命令,子站进行遥控选择返校,若成功则回答遥控选择成功报文,若失败则回答失败报文。主站下发取消遥控命令或者遥控执行命令行。字站予以确认。子站皆以报文的镜像确认。

3. 报文结构


4. 报文实例解读
SEND:68 0E 06 00 0A 00 2D 01 06 00 01 00 02 60 00 81
-
启动字符:68H
-
APDU 长度:0EH 14 个字节
-
控制域四个八位组:06 00 0A 00
-
类型标识:2DH CON<45>:= 单点遥控
-
可变结构限定词:01H SQ=0 地址不连续 信息元素个数 1, 单个
-
传送原因:06 00 -0006H Cause<6>:= 激活
-
ASDU 公共地址:01 00 =0001H 通常为 RTU 地址
-
第一个信息元素的地址:02 60 00 =006002H 点号 24578
-
第一个信息元素的值:81H 遥控选择 控合
RECV:68 0E 0A 00 06 00 2D 01 07 00 01 00 02 60 00 81
-
启动字符:68H
-
APDU 长度:0EH 14 个字节
-
控制域四个八位组:0A 00 06 00
-
类型标识:2DH CON<45>:= 单点遥控
-
可变结构限定词:01H SQ=0 地址不连续 信息元素个数 1, 单个
-
传送原因:07 00 -0007H Cause<7>:= 激活确认
-
ASDU 公共地址:01 00 =0001H 通常为 RTU 地址
-
第一个信息元素的地址:02 60 00 =006002H 点号 24578
-
第一个信息元素的值:81H 遥控选择 控合
SEND:68 0E 08 00 0C 00 2D 01 06 00 01 00 02 60 00 01
-
启动字符:68H
-
APDU 长度:0EH 14 个字节
-
控制域四个八位组:08 00 0C 00
-
类型标识:2DH CON<45>:= 单点遥控
-
可变结构限定词:01H SQ=0 地址不连续 信息元素个数 1, 单个
-
传送原因:06 00 -0006H Cause<6>:= 激活
-
ASDU 公共地址:01 00 =0001H 通常为 RTU 地址
-
第一个信息元素的地址:02 60 00 =006002H 点号 24578
-
第一个信息元素的值:01H 遥控执行 控合
RECV:68 0E 0C 00 08 00 2D 01 07 00 01 00 02 60 00 01
-
启动字符:68H
-
APDU 长度:0EH 14 个字节
-
控制域四个八位组:08 00 0C 00
-
类型标识:2DH CON<45>:= 单点遥控
-
可变结构限定词:01H SQ=0 地址不连续 信息元素个数 1, 单个
-
传送原因:07 00 -0006H Cause<7>:= 激活确认
-
ASDU 公共地址:01 00 =0001H 通常为 RTU 地址
-
第一个信息元素的地址:02 60 00 =006002H 点号 24578
-
第一个信息元素的值:01H 遥控执行 控合
RECV:68 0E 0E 00 08 00 2D 01 0A 00 01 00 02 60 00 01
-
启动字符:68H
-
APDU 长度:0EH 14 个字节
-
控制域四个八位组:0E 00 08 00
-
类型标识:2DH CON<45>:= 单点遥控
-
可变结构限定词:01H SQ=0 地址不连续 信息元素个数 1, 单个
-
传送原因:0A 00 -000AH Cause<10>:= 激活结束
-
ASDU 公共地址:01 00 =0001H 通常为 RTU 地址
-
第一个信息元素的地址:02 60 00 =006002H 点号 24578
-
第一个信息元素的值:01H 遥控执行 控合
IEC 104 电力规约详细解读 (六) - Java 解析开发要点
张二狗和苗翠花已于 2024-04-22 19:38:52 修改
1. 前言
最近在研究广东电网的 101 与 104 规约,也就是 DL/T634.5101-2002 和 DL/T634.5104-2009。因为要做一个规约解析的软件(基于 Android 平台的),刚开始接触的也是一头雾水,因为没有接触过这方面的知识,所以就在网上搜索各种技术帖,大神经验什么的。
后来在网上找到了一个软件–IEC8705 (报文翻译工具).exe,这个可以解析一些 101(平衡式)的实例,效果图贴一下。
但有些还是解析不了,并且在网上也找不到他的源码,所以就很苦恼。也找到一些 C++ 的源码,但是由于技术有限,我看不懂。下面就和大家来看看我写的这个简单的 Java 语言的规约解析。先贴一下效果图(我就在控制台简单演示一下,没有做可视化界面)。
GitHub 地址:https://github.com/mujave/iec
2. Java 版效果图
3. 规约详细解释
先看一下我总结的关于规约解析的几个图
101 的规约总结

104 规约总结

具体的 104 协议解释也可以参考 https://blog.youkuaiyun.com/wojiuguowei/article/details/79413142
4. 名词解释
这里所说的名词解释,并不是对一些名词的定义的解释,因为这不是我的专业领域,下面我主要针对报文所代表的名词在代码里怎样解释(解析)说一下。
控制域(平衡式)

在报文解析中,我就是按照图里面的取值方法对对应的字节进行取值,然后进行逻辑判断,将结果加到解析结果里面,由于后四位所代表的平衡链路功能码在这里是固定的,所以可以采取枚举或者反射(常量) 的方式进行解析
地址域(以 104 的信息体地址为例)
在规约中地址才用的低前高后(低位在前高位在后)的规则
例如:68 10 08 00 02 00 09 01 03 00 01 00 01 40 00 2B 02 00(黄色部分为信息体地址)

所以 这个信息体的地址为 01 40 00 >0x004001=16385
时标 CP56Time2a

解析代码如下
/**
* 时标CP56Time2a解析
*
* @param b 时标CP56Time2a(长度为7 的int数组)
* @return 解析结果
*/
public static String TimeScale(int b[]) {
StringBuilder result = new StringBuilder();
int year = b[6] & 0x7F;
int month = b[5] & 0x0F;
int day = b[4] & 0x1F;
int week = (b[4] & 0xE0) / 32;
int hour = b[3] & 0x1F;
int minute = b[2] & 0x3F;
int second = (b[1] << 8) + b[0];
result.append("时标CP56Time2a:20");
result.append(year).append("-");
result.append(String.format("%02d", month)).append("-");
result.append(String.format("%02d", day)).append(",");
result.append(hour).append(":").append(minute).append(":");
result.append(second / 1000 + "." + second % 1000).append("\n");
return result.toString();
}
遥测量的解析
在 101 的遥测中定义到有三种类型的值,分别是归一化值,标度值,短浮点数,具体的定义大家可以参考 “电力 101/104 规约中遥测量类型转换”,下面我说一下在 Java 中怎么解析这三种类型的值。直接上代码了。
public class Main {
public static void main(String[] args) {
Telemetry telemetry = new Telemetry();
System.out.println(telemetry.Bytes2Float_NVA(0xa4, 0x6a));// 报文数据的为A4 6A(低位在前,高位在后) ,为0x6AA4
System.out.println(telemetry.Bytes2Float_SVA(0xa4, 0x6a));// 报文数据的为A4 6A(低位在前,高位在后) ,为0x6AA4
System.out.println(telemetry.Bytes2Float_IEEE754("3e0779a6"));
//报文数据 A6 79 07 3E = 0x3e0779a6 = 0.1323(IEEE754 短浮点数)http://lostphp.com/hexconvert/
}
}
/**
* 遥测量解析
*
* @author zhangyu
*/
public class Telemetry {
/**
* 归一化值
*/
public static float Bytes2Float_NVA(int low, int high) {
float fVal;
int nva = (high << 8) + low;
// 符号位1位,0为正数,1为负数,后面的为补码表示,
// 正数的补码和原码相同不需要转换。对于负数,先取反码再加1得到补码的补码,就是原码了。
int symbol = (high & 0x80);//符号位:0表示正数,1表示负数
if (symbol == 0x80)
fVal = -1* (((nva ^ 0xffff) + 1) & 0x7fff);// (nva ^ 0xffff) + 1 :补码的补码 ,取出后面的15位数据乘上-1得到值
else fVal = nva;
return fVal / 32767;//这里的32767值的是一个量纲,一般这个参数是主站和从站商定的
}
/**
* 标度化值
*/
public static float Bytes2Float_SVA(int low, int high) {
float fVal;
int nva = (high << 8) + low;
int symbol = (high & 0x80);//0表示正数,1表示负数
if (symbol == 0x80)
fVal = -1* (((nva ^ 0xffff) + 1) & 0x7fff);
else fVal = nva;
return fVal;
}
/**
* 短浮点数
*
* @param data 从低位到高位按顺序
* @return
*/
public static float Bytes2Float_IEEE754(String data) {
return Float.intBitsToFloat(Integer.valueOf(data, 16));
}
}
对于短浮点数的计算,在 Java 的文档里有这样的说明。

还有一些 ASDU 里的信息体的解析过程代码,有点多,就不一一贴出来了
代码已经发布到 GitHub,需要的伙伴可以直接下载
5.104 规约解析遇到的一些难题
报文类型的区分
101 报文区分定长和变长两种,而 104 规约都是变长的报文。但是对于 104 来说,其控制域决定了 104 报文分别属于三种类型(I 帧 S 帧 U 帧)。所以在解析 104 到控制域的时候,是在解析 104 的第一个难题。我先说一下我自己的区分逻辑。

-
我是用控制域的第一字节去和 3 做位运算(因为和 3 做位运算就可以得到第一字节的 D1/D0 两位),从上面的图中我们可以看到,结果如果是 1 的话就是 S 格式,如果是 3 的话就是 U 格式,其他 的结果就是 I 格式的报文。
-
第二种方式是我在和一个网友交谈中得到的,他是运用奇数或者偶数来区分的,这里我列一个表格 ,这样的话如果第一个字节是偶数就是 I 帧,否则判断第三字节是 0 就是 U 帧。这样也可以区分报文的类型
但是我认为还是做位运算效率会更高,计算奇偶性还需要用到 % 这样的运算。
| 类型 | 第一字节 | 第二字节 | 第三字节 | 第四字节 |
|---|---|---|---|---|
| S 帧 | 奇(1) | 0 | 偶 | — |
| I 帧 | 偶 | — | 偶 | — |
| U 帧 | 奇 | 0 | 0 | 0 |
位运算的运用
在解析规约的时候,我一般都是运用的位运算 (&),这样既可以提高程序的效率,也有助于理解。首先在规约的定义中有很多的一个字节中的不同位代表一个含义,这种时候就运用到了位运算,这样就可以直接将对应位的值提取出来,例如那可变结构限定词这个字节来举个例子。最高位的 D7 代表的是信息元素地址的连续性,其中 0 不连续 1 连续,所以我们只需要拿这个字节和 128 (0x80) 做位运算就可以得到 D7 这一位,如果结果是 10000000 就说明是 1 连续。这个地方更直观一点的判断方法就是 ((B&0x80)>>7)==1? 连续:不连续。

###时标的解析

首先时标这里一共有 7 个字节,下面对这几个字节的含义以及解析方法做一下解释:
-
年 (byte 7): 这里只有后面的 7 位有效,但是第 8 位填充的是 0,所以这一个字节直接转换形成 int 就可以了。
-
月 (byte 6): 同上
-
小时 (byte 4): 同上
-
分钟 (byte 3): 同上
-
日 (byte 5 [bit 1~5]): 第五字节的后 5 位表示的是日,byte5 & 0x1F 就可以得到 (0x1F = 0001 1111), 例如第五字节是 87 (87 = 0x57 = 0101 0111),其中 010 指的是星期,10111 指的是 day。这里使用 87 & 0x1F 就可以得到 23。使用 87 & 0xE0 就可以得到 64,然后再用这个结果除以 32 就可以得到结果,如果说除以 32 不太理解的话,也可以用结果右移运算 64>>5 也可以得到结果 。
-
毫秒 (byte 1 and byte 2): 这个地方首先是低前高后的问题 (这个为题不太明白的可以先翻一下下面的第四个问题),( byte 2 << 8 ) + byte 1 ,这个地方我用一个表格说明一下 (例如第一字节是 6E,第二字节是 2A)。

/**
* 时标CP56Time2a解析
*/
public static String TimeScale(int b[]) {
String str = "";
int year = b[6] & 0x7F;
int month = b[5] & 0x0F;
int day = b[4] & 0x1F;
int week = (b[4] & 0xE0) / 32;
// int week = (b[4] & 0xE0) >> 5;
int hour = b[3] & 0x1F;
int minute = b[2] & 0x3F;
int second = (b[1] << 8) + b[0];
str += "时标CP56Time2a:" + "20" + year + "-"
+ String.format("%02d", month) + "-"
+ String.format("%02d", day) + "," + hour + ":" + minute + ":"
+ second / 1000 + "." + second % 1000;
return str + "\n";
}
/**
* 时间转16进制字符串
*/
public static String date2HStr(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
StringBuilder builder = new StringBuilder();
String milliSecond = String.format("%04X", (calendar.get(Calendar.SECOND)* 1000) + calendar.get(Calendar.MILLISECOND));
builder.append(milliSecond.substring(2, 4));
builder.append(milliSecond.substring(0, 2));
builder.append(String.format("%02X", calendar.get(Calendar.MINUTE) & 0x3F));
builder.append(String.format("%02X", calendar.get(Calendar.HOUR_OF_DAY) & 0x1F));
int week = calendar.get(Calendar.DAY_OF_WEEK);
if (week == Calendar.SUNDAY)
week = 7;
else week--;
builder.append(String.format("%02X", (week << 5) + (calendar.get(Calendar.DAY_OF_MONTH) & 0x1F)));
builder.append(String.format("%02X", calendar.get(Calendar.MONTH) + 1));
builder.append(String.format("%02X", calendar.get(Calendar.YEAR) - 2000));
return builder.toString();
}
低前高后的问题
这里讲一下低前高后的问题,拿这个 104 规约的信息对象地址举例。例如 34 12 00 这是原报文的字节,再具体解析的时候我们要把它转成 0x001234=4660,其实这里和上面的毫秒的解析方式一样。

- IEC104 协议 | 帧格式 / 调试(篇 1)-优快云博客
https://blog.youkuaiyun.com/u013669912/article/details/144622175 - IEC104 协议 | 帧格式 / 调试(篇 3)-优快云博客
https://blog.youkuaiyun.com/u013669912/article/details/155851169
via:
-
IEC 104 电力规约详细解读 (一) - 报文结构、报文分类、ASDU_104 规约详细介绍及报文解析-优快云 博客
https://blog.youkuaiyun.com/ZhangYu971014/article/details/135889376 -
IEC 104 电力规约详细解读 (二) - 总召唤_iec104 总召唤报文-优快云 博客
https://blog.youkuaiyun.com/ZhangYu971014/article/details/135983190 -
IEC 104 电力规约详细解读 (三) - 遥信_104xieyi 信息元素值-优快云 博客
https://blog.youkuaiyun.com/ZhangYu971014/article/details/136072736 -
IEC 104 电力规约详细解读 (四) - 遥测_iec104 规约标准 遥测-优快云 博客
https://blog.youkuaiyun.com/ZhangYu971014/article/details/136994209 -
IEC 104 电力规约详细解读 (五) - 遥控_104 遥控-优快云 博客
https://blog.youkuaiyun.com/ZhangYu971014/article/details/138089077 -
IEC 104 电力规约详细解读 (六) - Java 解析开发要点
https://blog.youkuaiyun.com/ZhangYu971014/article/details/79841555 -
IEC 60870-5-104 详细解读_张二狗和苗翠花的博客-优快云 博客
https://blog.youkuaiyun.com/zhangyu971014/category_12562718.html
1470

被折叠的 条评论
为什么被折叠?



