C#解析DL/T645电力数据

DL/T 645协议详细解析

DL/T 645是我国电力行业的标准,主要适用于电表与计算机之间的通讯。

帧格式

帧起始符 68H

标识一帧信息的开始,其值为 68H=01101000B

地址域 A0~A5

地址域由 6 个字节构成,每字节 2 位 BCD 码,地址长度可达12位十进制数。每块表具有唯一的通信地址,且与物理层信道无关。当使用的地址码长度不足 6 字节时,高位用“0”补足。通信地址999999999999H为广播地址,只针对特殊命令有效,如广播校时和广播冻结等。广播命令不要求从站应答。地址域支持缩位寻址,即从若干低位起,剩余高位补AAH作为通配符进行读表操作,从站应答帧的地址域返回实际通信地址。地址域传输时低字节在前,高字节在后

控制码 C

数据域长度 L

L 为数据域的字节数。读数据时 L≤200,写数据时 L≤50,L=0 表示无数据域。

数据域 DATA

数据域包括数据标识、密码、操作者代码、数据、帧序号等,其结构随控制码的功能而改变。传输时发送方按字节进行加 33H 处理,接收方按字节进行减 33H 处理。

校验码 CS

从第一个帧起始符开始到校验码之前的所有各字节的模 256 的和,即各字节二进制算术和,不计超过 256 的溢出值。

结束符 16H

645常用控制码与返回

控制码 含义 正常返回 异常返回
11 读数据 91 D1
1A 电表清零 9A DA
12 读后续数据 B2 D2
17 更改通讯速率 97 D7
16 冻结 96 D6
1B 事件清零(默认事件总清0) 9B DB
14 写数据 94 D4
1C 拉合闸 9C DC

示例解析:

当前指令是查询表地址777123000000的(当前)组合有功总电能

FEFEFEFE6877712300000068110433333333AD16

前置:fefefefe

起始符:68

地址域:777123000000

起始符:68

控制码:11

长度:04

数据域:33333333

校验码:ad

结束符:16

电表返回:

FEFEFEFE6877712300000068910833333333343333330D16

前置:fefefefe

起始符:68

地址域:777123000000

起始符:68

控制码返回:91 正常

长度:08

数据域:3333333334333333 其中数据表示为33333333 当前组合有功电能 值为 43333333 结果为:0.01

校验码:ad

结束符:16

.net简单封装一下解析

下面是主要的代码了

/// <summary>
/// 数据解析
/// </summary>
/// <param name="infos"></param>
public static Dlt645Analysis DL645Analysis(Span<byte> infos)
{
    Dlt645Analysis analysis = new Dlt645Analysis();
    Span<byte> data;
    //去除FE
    if (infos[0] == 254)
    {
        int codeIndexInfos = 1;
        data = infos.Slice(1);
        while (infos[codeIndexInfos] == 254)
        {
            data = data.Slice(1);
            codeIndexInfos++;
        }
    }
    else
    {
        data = infos;
    }
    string address = "";
    //解析地址域
    Span<byte> addressbyte = data.Slice(1, 6);
    foreach (var item in addressbyte)
    {
        address += item.ToString("x2");
    }
    analysis.Address = address;
    string type = data[8].ToString("x2").ToUpper();
    bool suncess = type switch
    {
        //读数据
        "91" => AnalysisRead(analysis, data, true),       
        _ => false
    };
    return analysis;
}
 

 

private void button1_Click(object sender, EventArgs e)
 {
     List<byte> list = new List<byte>();
     for (int i = 0; i < txt645.Text.Length; i = i + 2)
     {
         var value = txt645.Text.Substring(i, 2);
         list.Add((byte)(Convert.ToInt32(value, 16)));
     }
     var resultData = DL645Agreement.DL645Analysis(list.ToArray());
     if (!resultData.Sucess)
     {
         txtIsSucess.Text = "返回失败";
         return;
     }
     string infoType = resultData.Data.Substring(0, 8).ToUpper();//数据标识
     string infoData = resultData.Data.Substring(8);//数据值
     txtIsSucess.Text = "返回成功";
     txtLabel.Text = infoType;
     int length = Convert.ToInt32(txtLength.Text);
     int intLength = Convert.ToInt32(txtInt.Text);
     string[] spandata = new string[infoData.Length / 2];
     for (int i = 0, index = 0; i < infoData.Length; i = i + 2, index++)
     {
         spandata[index] = infoData.Substring(i, 2);
     }
     spandata = spandata.Reverse().ToArray();
     //数量
     int count = spandata.Length / (length / 2);
     string[] realinfo = new string[count];
     for (int i = 0; i < count; i++)
     {
         string value = "";
         for (int j = (length / 2) * i; j < (length / 2) * (i + 1); j++)
         {
             value += (Convert.ToInt32(spandata[j], 16) - 51).ToString("X2").PadLeft(2, '0');
         }
         if (length != intLength)
         {
             value = value.Insert(intLength, ".");
         }
         realinfo[i] = value;
     }
     txtAddress.Text = resultData.Address;
     txtData.Text = string.Join(",", realinfo);
 }
posted @ 2024-07-09 16:28  落幕无痕  阅读(40)  评论(0编辑  收藏  举报