4. ASDU结构解析:类型标识、可变结构限定词、传送原因、公共地址、信息对象地址、时标
好,咱们今天来啃一块硬骨头——ASDU结构。说实话,我刚接触IEC104的时候,看着这一串串的字节,头都是大的。但后来我发现,只要把ASDU拆成几个关键字段来理解,这事儿就简单多了。
ASDU,全称是Application Service Data Unit,应用服务数据单元。你可以把它想象成一个快递包裹。包裹外面贴着快递单,里面装着你要寄的东西。ASDU也一样,它由数据单元标识和信息体两部分组成。
数据单元标识就是快递单,它告诉接收方:这是什么类型的包裹?里面装了几件东西?为什么要寄?寄给谁?而信息体就是包裹里的实物,也就是具体的遥测值、遥信状态、遥控命令等。
核心记忆点:ASDU = 数据单元标识(头部) + 信息体(数据本体)
下面我带你逐个拆解数据单元标识里的六个关键字段。嗯,这六个字段,你搞懂了,ASDU就通了八成。
4.1 类型标识(Type Identifier)
类型标识,占1个字节。它告诉接收方:这个ASDU里装的是什么类型的数据。
我个人习惯把类型标识分成几大类来记:
- 遥测类(M_ME_xxx): 比如归一化值M_ME_NA_1(09H)、标度化值M_ME_NB_1(0BH)、浮点数M_ME_TF_1(0DH)。我在储能站项目里,电池簇的电压、电流、温度,大部分都用浮点数类型,精度高,省心。
- 遥信类(M_SP_xxx): 比如单点遥信M_SP_NA_1(01H)、双点遥信M_DP_NA_1(03H)。开关的分合闸状态,用双点遥信更安全。
- 遥控类(C_SC_xxx): 比如单点遥控C_SC_NA_1(2DH)、双点遥控C_DP_NA_1(2EH)。下发指令时,类型标识必须和站端配置一致,否则会报错。
- 参数类(P_ME_xxx): 比如设置参数P_ME_NA_1(64H)。
我曾经在调试一个储能PCS时,主站下发遥控命令,类型标识写的是单点遥控,但站端配置的是双点遥控。结果呢?PCS死活不动作。排查了半天,最后发现是类型标识对不上。你说冤不冤?
小技巧: 类型标识的十六进制值,建议你背下常用的几个。调试时用抓包软件一看,就知道报文是干啥的,效率翻倍。
4.2 可变结构限定词(Variable Structure Qualifier, VSQ)
VSQ,占1个字节。它描述的是信息体的结构。说白了,就是告诉你:这个ASDU里,信息体是单个的还是连续的?一共有几个?
VSQ的格式是这样的:
- Bit 7(最高位): SQ位。SQ=0表示信息体地址不连续(离散),每个信息体都带独立的地址;SQ=1表示信息体地址连续,只需要第一个信息体的地址,后面的自动递增。
- Bit 6~0(低7位): 信息体的数目N。取值范围1~127。注意,0是无效的,至少得有1个。
你想想看,如果我要上传100个电池单体电压,用SQ=1的方式,只需要发一个起始地址,后面99个地址自动加1。报文长度能省不少。但如果这些电压点地址不连续,那就只能用SQ=0,每个点都带独立地址。
实战经验: 在储能站里,电池管理系统(BMS)上报电池簇数据时,我建议优先使用连续地址(SQ=1)。因为电池单体地址通常是顺序排列的,用连续方式能显著减少报文长度,降低网络负载。
4.3 传送原因(Cause of Transmission, COT)
传送原因,占2个字节(IEC104中扩展为2字节)。它解释了这个ASDU为什么会被发送。
常见的传送原因有:
| 原因值 | 含义 | 说明 |
|---|---|---|
| 1 | 周期(Cyclic) | 定时上送的遥测数据 |
| 2 | 背景扫描(Background) | 低优先级扫描数据 |
| 3 | 突发(Spontaneous) | 遥信变位、越限告警等 |
| 5 | 请求(Request) | 响应主站的召唤命令 |
| 6 | 激活(Activation) | 遥控、设点命令的激活 |
| 7 | 激活确认(Activation Confirmation) | 站端确认收到激活命令 |
| 8 | 停止激活(Deactivation) | 取消遥控或设点命令 |
| 9 | 停止激活确认(Deactivation Confirmation) | 站端确认取消成功 |
| 10 | 激活终止(Activation Termination) | 遥控或设点执行结束 |
| 20 | 站召唤(Station Interrogation) | 全站数据总召 |
| 21 | 组召唤(Group Interrogation) | 特定组的数据召唤 |
举个例子,储能站里电池温度越限了,站端会主动上送一个传送原因为3(突发)的ASDU。主站收到后,就知道这是告警事件,需要立即处理。
注意: 传送原因的第8位(Bit 7)是P/N位,0表示肯定确认,1表示否定确认。比如遥控命令被拒绝时,传送原因会是0x87(原因7 + 否定位)。这个细节很容易被忽略,但调试时特别有用。
4.4 公共地址(Common Address)
公共地址,占2个字节。它标识了这个ASDU属于哪个站或哪个装置。
在IEC104中,公共地址通常用来区分不同的变电站、不同的储能单元或不同的保护装置。比如一个储能站有4台PCS,每台PCS的公共地址可以设为1、2、3、4。主站通过公共地址就知道数据来自哪台设备。
公共地址的范围是1~65535。0通常保留不用。我个人习惯把公共地址和设备编号对应起来,这样看报文就能直接定位设备,省去查表的麻烦。
建议: 公共地址的分配一定要提前规划好,形成文档。我在一个项目里见过,两个设备配了相同的公共地址,结果主站收到的数据乱套了。排查起来那叫一个痛苦。
4.5 信息对象地址(Information Object Address, IOA)
信息对象地址,占3个字节。它标识了具体的数据点。比如第1个电池单体电压、第2个电池单体电压、第1个开关状态等。
IOA的分配通常由工程实施方根据点表来规划。常见的做法是:
- 遥测地址范围: 比如4001H~4FFFH
- 遥信地址范围: 比如5001H~5FFFH
- 遥控地址范围: 比如6001H~6FFFH
- 设点地址范围: 比如7001H~7FFFH
当然,这只是举例,实际项目中可以根据需要灵活划分。关键是地址不能重复,一个IOA只能对应一个数据点。
我记得有一次,现场调试时发现某个遥测值一直显示为0。抓包一看,IOA写的是4001H,但点表里4001H对应的是另一个信号。原来是配置表搞错了。所以说,IOA的分配和核对,是调试前必须做好的功课。
4.6 时标(Time Stamp)
时标,就是数据产生的时间。IEC104支持多种时标格式:
- CP56Time2a(7字节): 最常用,包含毫秒、分钟、小时、日、月、年,还有星期几。精度到毫秒。
- CP24Time2a(3字节): 只有毫秒和分钟,精度较低。
- CP32Time2a(4字节): 只有毫秒,用于相对时间。
在储能站里,我强烈建议使用CP56Time2a。为什么?因为储能系统的数据需要精确的时间戳来分析故障顺序。比如电池过温告警和PCS跳闸,如果时间戳不准,你就没法判断是先有过温还是先跳闸,故障根因分析就无从谈起。
CP56Time2a的结构是这样的:
| 字节偏移 | 内容 | 范围 |
|---|---|---|
| 0~1 | 毫秒(低字节在前) | 0~59999 |
| 2 | 分钟 | 0~59 |
| 3 | 小时(Bit 6~0) + 星期几(Bit 7~5) | 小时0~23,星期1~7 |
| 4 | 日 | 1~31 |
| 5 | 月 | 1~12 |
| 6 | 年(相对于2000年) | 0~99(表示2000~2099) |
注意: 时标的字节顺序是小端模式(低字节在前)。比如毫秒值1000(0x03E8),在报文里是E8 03。很多新手在这里栽过跟头,解析时一定要留意。
知识体系结构图
下面我用一张SVG图来总结ASDU的结构,方便你整体把握:
这张图把ASDU的骨架画出来了。你对照着看,是不是清晰多了?数据单元标识里的六个字段,加上信息体里的数据,就组成了一个完整的ASDU。
好了,ASDU的结构就讲到这里。这六个字段,你记住了吗?类型标识告诉你是啥数据,可变结构限定词告诉你数据怎么排列,传送原因告诉你为啥发,公共地址告诉你是谁发的,信息对象地址告诉你具体哪个点,时标告诉你啥时候发生的。六者合一,就是一个完整的数据描述。
下次你抓包看到一串十六进制数,试着按这个结构去拆解,很快就能上手。我在现场调试时,就是这么一步步练出来的。
公众号:蓝海资料掘金营,微信deep3321