1. 为什么电力调度都在聊IEC104
刚入行电力自动化那会儿,跟着师傅去变电站调试,师傅丢给我一份协议文档,封面上印着“IEC 60870-5-104”,说:“把这玩意儿吃透,你就能在这个行业混饭吃了。”我那时候以为他在开玩笑,后来才明白,这玩意儿确实是电力远动通信的硬通货。
先说清楚IEC104是什么。全称是“IEC 60870-5-104”,是国际电工委员会制定的电力系统远动通信协议,简单说就是电网调度中心和变电站、发电厂、新能源场站之间用来传数据的一套“通用语言”。它把IEC 60870-5-101的应用层数据,通过TCP/IP网络来承载,实现了从传统的串口通信到网络化通信的升级。
这套协议能做什么?一句话概括:上送遥测、遥信,下发遥控、遥调。遥测就是电压、电流、有功、无功这些模拟量,遥信就是开关位置、保护动作信号这些状态量,遥控就是调度端下发合闸、分闸指令,遥调就是调整变压器分接头或有功出力。电力系统的“四遥”功能,全部跑在IEC104上。
哪些场景会用到IEC104?举几个最典型的:电网调度自动化系统(SCADA)与变电站综自系统的通信、风电场和光伏电站的AGC/AVC控制、配电自动化终端(DTU/FTU)的数据上报、储能电站的能量管理平台接入。可以说,凡是需要把现场设备数据送到远方调度端的项目,大概率绕不开IEC104。
这篇文章适合谁看?如果你是刚接触电力通信的调试工程师、做电力监控软件开发的技术人员、或者搞新能源场站接入的集成工程师,这篇文章会把IEC104从协议原理到实际调试的完整链路讲透,还会穿插一些我在现场踩过的坑。我尽量用大白话把协议细节讲明白,保证你读完能直接上手干活。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. IEC104协议整体设计与核心思路拆解
2.1 为什么选择TCP/IP作为传输层
IEC104之所以选择TCP/IP,核心逻辑就一个字:省。省什么?省线、省设备、省维护成本。
早期的IEC101走串口,一条通道只能点对点连接,调度中心和每个厂站之间得拉专线或者租用通信通道,一个厂站一个通道,通道多了以后,调度端的通信管理机接口都不够用。而TCP/IP网络是天然的多对多架构,调度端只要开一个IP端口,理论上可以接入无数个厂站,只要网络能通,厂站侧也只需要一个网口,把数据送进调度数据网即可。
另外一个关键原因是传输可靠性。TCP协议自带三次握手、确认重传、拥塞控制机制,解决了串口通信中数据错帧、丢帧后难以恢复的痛点。IEC104把“传输可靠”这件事完全交给了TCP/IP协议栈,自己只管应用层的数据组织和业务逻辑,这让协议设计变得非常清爽。
2.2 协议栈结构:把101的应用层搬上网络
IEC104的协议模型可以用一句话理解:应用层沿用IEC101,传输层换成TCP,中间加一个APCI适配层。
APCI的全称是“应用协议控制信息”,它是IEC104在TCP之上增加的一个薄薄的壳,负责区分不同类型的帧、处理启动/停止/测试等控制功能。APCI加上ASDU(应用服务数据单元)组合在一起,就是一个完整的IEC104报文。
这里要特别强调一点:IEC104不是重新发明了一套应用层协议,而是把IEC101里那套成熟的数据模型、类型标识、传送原因、公共地址、信息对象地址全部保留了。这意味着,如果你之前写过IEC101的设备驱动,迁移到IEC104时,只要修改传输层代码,应用层的解析逻辑可以复用一大半。
2.3 三帧类型:I帧、S帧、U帧的分工
IEC104的帧类型是整个协议的基础设施,哪怕后面ASDU内容再复杂,也是装在这些帧里面跑的。
I帧,全称“信息传输帧”,是真正干活的帧。它的APCI里带发送序号N(S)和接收序号N(R),承载ASDU数据,负责传送遥测、遥信、遥控、时钟同步、总召等所有业务数据。
S帧,全称“监视帧”,不带ASDU,只有接收序号N(R),作用是纯确认。当设备收到一帧I帧但暂时没有数据要回送时,就发一个S帧告诉对方“你的第N帧我收到了,继续发”。
U帧,全称“控制帧”,不带序号,负责连接管理。启动建立连接用STARTDT,停止连接用STOPDT,测试链路用TESTFR,这是通信双方握手的关键帧。
这三个分工非常重要,我遇到过不少开发者在写协议栈时,把S帧当普通报文忽略掉,结果导致对端因为接收序号不连续而不断重传,整个通信链路卡死。
2.4 IEC104与IEC101的关键差异
做了这么多年协议,被问到最多的问题是:“IEC101还能用,为什么还要搞IEC104?”
核心差异有三个。
第一,传输介质不同。101走串口(RS-232/RS-485),速率一般9600bps或19200bps,而104走以太网,百兆千兆随便跑。这个速率差异直接决定了数据的吞吐能力,在数据量大的场站,101传一轮全数据可能要几分钟,104几乎秒级完成。
第二,传输确认机制不同。101的确认机制依赖于链路层的“确认帧”,而104直接依赖TCP的ACK机制加上应用层的S帧/U帧。TCP层的ACK保证了字节流不丢不重,应用层的序号机制保证了数据帧的有序组织和丢失检测,两层加起来让可靠性大幅提升。
第三,支持的数据量级不同。101受限于串口速率,信息体地址和ASDU的发送频率都有瓶颈。而104在TCP支持下可以连续快速发送大量报文,而且支持多个TCP连接同时访问同一个设备,这在双通道冗余、主子站并行通信的场景下极其重要。
3. 报文结构拆解:每一个字节都别放过
3.1 APCI六字节与帧长计算
IEC104报文的基本结构是:APCI(6字节)+ ASDU(可变长度),整体长度在报文的前两个字节里标注。
第一个字节固定是0x68,表示“本帧是IEC104报文”,这是协议层的启动字符。第二个字节是帧体长度,指从第三个字节开始到报文末尾的总字节数。所以一帧完整的IEC104报文,总长度 = 2 + 长度字节的值。
APCI的6个字节分为两部分:
- 第1字节:启动字符0x68
- 第2字节:APDU长度
- 第3~6字节:控制域,包含帧类型和序号信息
用Wireshark抓包,你会看到类似这样的十六进制数据:
code复制68 24 02 00 00 00 64 01 06 00 01 00 00 00 00 14
我来逐字节拆解。
- 0x68:启动字符
- 0x24(36进制):整个APDU长度是36字节
- 0x02 0x00:I帧的发送序号N(S)=1
- 0x00 0x00:I帧的接收序号N(R)=0
- 0x64(类型标识100):表示“总召唤命令”
- 0x01:传送原因=1(周期/循环)
- 0x06:公共地址低字节
- 0x00:公共地址高字节
- 后面是信息对象地址和具体数据
3.2 控制域详情:序号机制怎么工作
控制域第3~6字节,是IEC104里最容易搞混的部分。
对于I帧,低字节最低位(bit0)必须为0,bit1~bit15是发送序号N(S),高字16位是接收序号N(R)。举个例子,控制域是02 00 0A 00,二进制展开后,第一个字的bit0是0,bit1~bit15值为1,说明N(S)=1;第二个字的bit0~bit15值为10,说明N(R)=10。
对于S帧,控制域第一个字的bit0必须为1,bit1为0,bit2~bit15保留为0,第二个字是接收序号N(R)。S帧的十六进制一般是01 XX XX XX。
对于U帧,控制域第一个字的bit0=1,bit1=1,bit2~bit7表示控制功能,bit8~bit15保留为0。常见的U帧:
- STARTDT激活:
07 00 00 00 - STARTDT确认:
0B 00 00 00 - STOPDT激活:
13 00 00 00 - STOPDT确认:
23 00 00 00 - TESTFR激活:
43 00 00 00 - TESTFR确认:
83 00 00 00
这些固定值建议直接背下来,调试的时候一眼就能判断出处于哪个环节。
3.3 ASDU字段详解:类型标识、传送原因、公共地址
ASDU是真正承载业务数据的部分,结构包括:
-
数据单元标识符(固定部分):
- 类型标识(1字节):决定后续数据是什么类型、结构如何
- 可变结构限定词(1字节):指示信息对象地址的个数和排列方式
- 传送原因(2字节):指示这条报文是自发上送、请求应答还是激活确认
- 公共地址(2字节):指示数据属于哪个厂站或装置
-
信息对象(可变部分):
- 信息对象地址(3字节):每个遥测点、遥信点、遥控点的唯一编号
- 信息元素集:具体的数据值
- 品质描述符:数据的有效性、越限、取代、刷新状态
类型标识常用值:
- 1:单点遥信
- 3:双点遥信
- 9:单点遥信带品质描述
- 11:双点遥信带品质描述
- 13:短浮点数(遥测)
- 30:带品质描述的短浮点数(最常用的遥测类型)
- 45:单点遥控命令
- 46:双点遥控命令
- 100:总召唤命令
- 103:时钟同步命令
传送原因常用值:
- 1:周期/循环
- 2:背景扫描
- 3:突发(自发)
- 4:初始化
- 5:请求或被请求
- 6:激活
- 7:激活确认
- 8:停止激活
- 9:停止激活确认
- 10:激活终止
- 20:响应站总召唤
3.4 信息对象地址:点位映射的命脉
信息对象地址(IOA)是IEC104中最需要跟现场点位表对照着看的东西。一个地址对应一个具体的遥测点或遥信点,地址范围从1到16777215(3字节)。
在工程实践中,很多设计院和集成商习惯把信息对象地址按区间规划:
- 1~1000:遥信
- 1001~2000:遥测
- 2001~3000:遥控
- 3001~4000:遥调
但这个不是协议规定的,纯粹是行业习惯。真正的映射关系完全取决于厂站的点位表。你接一个新项目时,第一件事就是拿协议文档和点位表对照,把每个IOA对应的含义标注清楚。
我吃过一次亏,某项目点位表里遥测是从4001开始的,我没细看,按默认的1001开始解析,结果上送的数据全部错位,看起来电压变成了电流,折腾了一个下午才发现是IOA偏移的问题。所以拿到点位表后,先花十分钟把IOA区间梳理清楚,比什么都重要。
4. 从建链到收数:完整通信流程实操
4.1 建链过程:U帧先行,确认后收数
IEC104的通信建立不是TCP通了就算完,还需要应用层的“启动”握手。完整的建链流程如下:
- 客户端(厂站或子站)向服务器(调度端)发起TCP连接,目标端口默认2404
- TCP握手成功后,客户端发送STARTDT激活帧(0x68 0x04 0x07 0x00 0x00 0x00)
- 服务器响应STARTDT确认帧(0x68 0x04 0x0B 0x00 0x00 0x00)
- 此时通信状态变为“可传输数据”,双方可以开始互发I帧
注意,在STARTDT激活并被确认之前,双方是不能发送I帧的。有些厂家的协议栈实现不规范,TCP一建立就急吼吼地发I帧,导致对端直接忽略。这属于实现层面最常见的坑。
4.2 总召唤与时钟同步:上电后的必做动作
主站和厂站建立通信后,主站一般会下发两条关键指令:
总召唤命令(类型100,传送原因6,激活):
code复制68 0E 02 00 00 00 64 01 06 00 00 00 00 00 00 00 00 14
- 类型标识:100
- 可变结构:0x01(单个信息对象)
- 传送原因:0x0006(激活)
- 公共地址:0x0000
- 信息对象地址:0x000000
- 召唤限定词:0x14(总召唤)
厂站收到总召唤后,先回一帧“激活确认”(类型100,传送原因7),然后开始上送所有遥信、遥测的当前值,上送完成后发一帧“激活终止”(类型100,传送原因10)。
时钟同步命令(类型103):
code复制68 14 04 00 02 00 67 01 06 00 00 00 00 00 E3 08 1D 05 14 17 0B
这条命令把主站时间发给厂站,厂站接收到后校准自身RTC。时钟同步通常也是上电后立即执行,保证事件记录SOE的时间戳准确。
4.3 数据上送:遥测遥信的实时流转
连接稳定、总召完成后,厂站就进入正常的数据上送状态。
遥测数据一般走类型13或类型30的报文,每帧可以带多个信息对象。比如一帧带10个遥测点,每个点占4字节浮点数加1字节品质描述符,总共5字节一个点,帧长度可以算得很清楚。
这里要特别注意品质描述符(QDS)的位定义:
- bit0:是否被取代(0正常,1取代)
- bit1:是否越限
- bit2:是否刷新(0正常,1刷新)
- bit3:是否无效(0有效,1无效)
在调试时,如果发现数据解析出来是“合理”的乱值,比如电压突然变成0或者一个巨大无比的数,先去查QDS的bit3,大概率是设备还没完成初始化,数据被标记为无效。
4.4 遥控命令:下行链路的细节
双点遥控命令(类型46,传送原因6,激活)的报文结构:
code复制68 0E 02 00 04 00 2E 01 06 00 01 00 00 00 01 00 00 00
- 类型标识:46(双点遥控)
- 传送原因:6(激活)
- 信息对象地址:0x000001
- 双点信息:0x01(合闸)或0x02(分闸)
- 选择/执行限定词:0x00(执行)或0x80(选择)
- 命令状态:0x00
这里解释一下“选择/执行”机制。在电力遥控里,为了防止误操作,很多场景采用“预置-执行”两步操作:先下发“选择”命令(限定词0x80),厂站校验点号和命令合理后,返回“选择确认”,主站再下发“执行”命令(限定词0x00),厂站执行并返回“执行确认”。整个过程就是常说的“返校”。
4.5 网络抓包实战:用Wireshark看完整交互
我在现场调试时,Wireshark加一个IEC104解析插件就是最强工具。在Wireshark里启用IEC60870-5-104的解析器后,每个帧都会被自动解析为完整的协议字段树,可以直接看到类型标识、传送原因、公共地址、信息对象地址。
抓包分析的步骤:
- 打开Wireshark,选择网卡
- 设置过滤条件:
tcp.port == 2404 - 触发厂站重启或主站发起总召唤
- 观察TCP三次握手、STARTDT激活/确认、总召唤激活/确认/终止的完整时序
如果发现只有TCP握手,没有STARTDT交互,多半是厂站侧协议栈没有启动或者被防火墙拦截。如果STARTDT确认之后一直没有数据上来,就要检查主站有没有下发总召唤命令。
5. IEC104通信中的常见问题与排查技巧
5.1 连接频繁断开,看t0/t1/t2/t3定时器
IEC104协议规定了几个关键定时器参数:
- t0:建立TCP连接的超时时间(默认30秒)
- t1:发送确认超时时间(默认15秒)
- t2:接收确认超时时间(默认10秒)
- t3:测试帧发送周期(默认20秒)
如果在调试中发现连接建立了又断、断了又建,大概率是t1/t2/t3配置不匹配。比如主站侧t3设置成20秒,厂站侧t3设置成60秒,主站会周期性发送TESTFR激活帧,厂站如果响应不及时或者根本不响应,主站就会判定链路故障断开连接。
解决方法是:两侧的定时器参数保持默认值,如果非要修改,必须在主站和厂站两侧同时修改,并确保t1 > t2,否则会导致确认超时。
5.2 序号对不上:I帧丢失导致通信卡死
IEC104的I帧序号N(S)是0到32767循环递增的。如果通信过程中某一帧丢失(尽管TCP保证字节流不丢,但应用层可能因为解析异常丢弃帧),接收方收到的N(S)不连续,就会导致后续所有I帧都被接收方忽略,通信卡死。
遇到这种情况:
- 重新建立STARTDT会话(发STOPDT再发STARTDT或直接断开重连)
- 检查协议栈实现是否正确处理了S帧确认
- 确认接收序号N(R)是否在合理范围内递增
大部分IEC104协议栈都实现了自动重发机制,但如果你自己在实现协议栈,一定要处理好“收到重复帧”和“收到乱序帧”这两个边界条件,否则稳定运行几天后突然卡死的故障很难排查。
5.3 解析出来的数据不对:先查字节序和品质位
IEC104协议中,多字节字段默认使用大端字节序。比如公共地址0x0001在报文里表现为01 00(低字节在前,注意这里协议标准里公共地址是低字节在前的小端约定),而信息对象地址是3字节,按照低字节在前的规则排列。
所以在做报文解析时,一定要先搞清楚字段是几字节、用的是大端还是小端。不同厂家的协议栈实现有可能在这个细节上不一致,导致同样的报文在不同解析器里得到不同结果。
另外,品质描述符QDS的bit3是无效位,如果数据被标记为无效,不管数值段解析出来什么,都不能直接当作有效工程值使用。我见过不少新人拿着无效数据算了半天功率,最后发现是设备还没初始化完成。
5.4 公共地址不匹配:沉默的调度端
公共地址(Common Address)是IEC104报文里标识厂站/装置身份的字段。主站侧配置了厂站公共地址为0x0001,但厂站侧发的报文公共地址是0x0002,这时候主站会直接丢弃这些报文。
这个故障最坑的地方在于:TCP连接正常、STARTDT正常、厂站侧也显示“通信正常”,但主站界面上一片死寂,没有任何数据刷新。排查思路是:
- 抓包确认厂站发出的报文公共地址字段
- 比对主站数据库里的厂站公共地址配置
- 重点检查有些厂家的配置界面里,公共地址是从1开始还是从0开始,这是个经典的差一错误
5.5 数据不刷新:检查品质描述符和召唤周期
还有一种常见情况:数据一直在上送,但主站画面上数值不刷新。这时抓包看数据帧,如果数据帧里的品质描述符QDS一直显示“刷新”状态(bit2=1),说明数据源没有产生新的有效采样值,需要检查厂站侧的采集程序。
如果数据帧里品质描述符正常,但主站不刷新,那就得检查主站侧的点表配置,确认信息对象地址IOA是否和点位表一致。另外有些主站软件有数据变化阈值,变化量小于阈值的值不会刷新,这种时候需要查看数据是否真的发生了足够大的变化。
5.6 双链路冗余下的切换问题
大型场站通常配置双通道冗余,两条TCP连接同时建立,一主一备。IEC104要求两条连接上都要进行STARTDT激活,业务数据只在主链路上传输,当主链路断了,备链路要快速接管。
实际调试中遇到的问题是:主链路断开后,备链路虽然TCP仍然连着,但厂站侧可能已经等待超时,需要主站重新发STARTDT才能恢复数据传输。解决方法是厂站侧协议栈要监听TCP连接的断开事件,一旦检测到连接断开,立即清理该连接上的应用层状态,保证备用连接能够直接接管而无需重新建链。
我在一个风电项目上处理过这类问题,当时双链路切换要十几秒,调度端直接判定场站通信异常。后来在协议栈里增加了TCP断线检测和连接状态自动清理,切换时间压缩到了1秒以内,才算满足了调度要求。
6. 开发调试工具与模拟器选型
6.1 开源协议栈与库的选择
如果你要开发IEC104主站或厂站程序,不建议完全从零写协议栈。成熟的开源方案能帮你省下大量时间。
- lib60870:目前最活跃的开源IEC60870-5-101/104协议栈,C语言实现,支持跨平台,接口清晰,文档齐全。我个人的几个项目都是基于lib60870二次开发的。
- QtIEC104:基于Qt C++的IEC104实现,如果你用Qt做上位机界面开发,集成起来很顺手。
- j60870:Java版本的IEC104协议栈,适合做后端服务和数据中台。
选型建议:如果你做嵌入式设备端,用lib60870;如果做PC端的监控软件,用QtIEC104或者直接在lib60870基础上封装一层网络服务。
6.2 模拟器与在线调试技巧
调试IEC104时,有一款好用的模拟器能事半功倍。我常用的调试思路是:
- 先用模拟器模拟厂站,验证主站端的报文解析正确
- 再用模拟器模拟主站,下发总召唤、遥控命令,验证厂站端的数据上送和命令响应
目前比较常用的免费模拟器包括:
- IEC104 Slave Simulator:可以模拟厂站端,配置遥测遥信点表,上送数据
- IEC104 Master Simulator:模拟主站端,发起总召唤、遥控操作,查看厂站响应
- Wireshark + IEC104解析插件:作为独立的抓包分析工具,任何时候都建议开着
调试过程中的一个关键实操经验:先用模拟器把整个流程跑通,再接真实设备。很多现场故障其实都是两端协议栈兼容性问题,模拟器可以帮你快速定位是发送端的问题还是接收端的问题。
6.3 嵌入式平台的IEC104移植要点
最近涉及RK3506这类工业级MPU的项目不少,在这些平台上移植IEC104需要注意几个细节:
第一,确认编译器的字节序配置。x86平台默认小端,ARM平台可以配置大端或小端,IEC104的多字节字段有自己特定的字节序要求,必须保证协议栈和平台字节序一致。
第二,注意TCP栈的重连机制。嵌入式Linux环境下网络可能不稳定,网线拔插、交换机重启都会导致TCP连接断开。协议栈需要实现自动重连,并处理好重连后的序号重置。
第三,存储资源规划。嵌入式设备的RAM有限,但IEC104报文的接收缓冲区至少要能容纳最大APDU(253字节)的若干倍,建议预留至少4KB的接收缓冲区和2KB的发送缓冲区。
第四,确认操作系统的TCP keepalive参数。IEC104应用层有自己的t3测试帧机制,但如果底层TCP连接半开(比如对端断电但网线没断),t3测试帧也得不到响应。这时候操作系统层面的TCP keepalive能帮你更快发现死连接,Linux下可以通过setsockopt配置keepalive时间。
7. 工程现场的经验之谈
7.1 联调前必须确认的五个配置项
到了现场再排查协议问题是非常痛苦的,因为网络环境复杂、设备种类多、能接触到的日志有限。我建议联调前先在办公室里把以下五点确认清楚:
- IP地址和端口:确认厂站侧装置IP、主站侧服务器IP、监听端口是否都为2404,网段是否可通。
- 公共地址:主站数据库里配置的公共地址必须和厂站侧装置一致。
- 点表映射:遥测、遥信、遥控的IOA区间和点位数量,主站和厂站要逐条核对。
- 定时器参数:t0/t1/t2/t3两侧保持一致,如果项目特殊要求修改,必须双方确认。
- 数据格式:遥测是短浮点(类型30)还是标度化值(类型13),主站解析格式要匹配。
我在一个光伏项目上,就是因为遥测类型配错了,主站把短浮点当整数解析,250V变成了一个天文数字,查了很久才发现是类型标识不匹配。
7.2 抓包工具的使用习惯
现场调试IEC104,Wireshark抓包是最直接的排查手段。我的习惯是:
- 用笔记本的网口接到交换机的镜像端口,或者直接在装置和主站之间串一个集线器/交换机做端口镜像
- 抓包的同时,把主站和厂站的操作时间点记录下来,方便对照报文时间戳定位问题
- 抓到关键报文后,用“导出特定分组”功能保存成独立文件,发给协议栈厂商分析
还有个小技巧:Wireshark的IEC104解析器会自动把序号、类型标识、传送原因、公共地址、信息对象地址解析成可读字段,但如果你需要检查原始字节,记得在Packet Details里展开最底层的“Data”字段,逐字节核对。
7.3 文档与配置管理
IEC104协议本身是标准化的,但每个项目都有自己特有的点表、公共地址分配、数据类型配置。这些配置信息必须规范化管理,我习惯在项目目录里放一份“通信配置表”,包含以下内容:
- 厂站名称、调度编号、公共地址
- 装置IP、端口、主备关系
- 遥信点表(IOA、点号、描述)
- 遥测点表(IOA、点号、描述、单位、变换系数)
- 遥控点表(IOA、点号、描述、操作类型)
- 品质描述符的异常处理策略(无效数据是丢弃还是置0)
这份配置表既是联调测试的依据,也是后期运维排查的重要文档。项目交接时,把协议文档、配置表、点表、程序源码一起交给运维,能省下后面无数的沟通成本。
7.4 最后的调试心得
IEC104做久了,最大的体会是:这协议本身不复杂,复杂的是工程现场的环境。网络问题、配置问题、点表问题、时序问题,每一种都能让通信异常,但每一种也都有迹可循。
遇到问题,先别急着改代码。花十分钟抓个包,对照报文看交互流程:TCP是否正常、STARTDT有没有握手成功、总召唤有没有执行、数据帧的序号连不连续、品质位有没有置位。90%的问题都能在抓包里看出端倪。
做电力通信调试是一项细致活,但只要养成“先抓包、再分析、后动手”的习惯,你也能在复杂的现场环境中游刃有余。希望这篇文章能帮你少走一些弯路,少熬几个通宵。
