协议:645规约学习(一)

前言

最近工作接触到关于电表之类的方面,公司这主要使用645规约、689规约、modbus协议等...因为对这些没有接触过,这边通过抄表实例来熟悉一下。


抄表原理

概述

抄表原理其实说白了就是抄读电能表的测量参数,比如电能、电压、电流、实时功率等...而用单板抄表其实就是读电能表种相应寄存器中的值。智能电表目前主流协议有:

DLT645 - 国标各家通用
MODBUS - 各家有自己协议
【645规约是面向对象的,最近几年国网开始推广689规约,这种规约是面向对象,是相对645的一种升级版,689规约后续会跟进学习,这边简单的先来。】

这里拿DLT645为例,MODBUS很简单一条指令可以读连续的地址空间,收发一次抄到所有数据,而 645就得一条一条读。

645规约

这里主要需要配置串口时按照协议要求配置,因为对串口没啥研究,这边就放一篇文章作为参考:http://www.cnblogs.com/VergilYang/p/8902264.html

另外,在协议中最重要的其实就是帧协议了,至于控制码之类的,因为只是抄表实例,所以控制码仅仅是读数据...



上面就是645规约对于传输帧的一个整体定义,会有点乱,下面我们可以试着组一条完整报文加深理解:

帧发送
  • 帧起始符就是68H,那地址域怎么确定,一般表的铭牌上会写地址,如果串口上只挂了这一个设备,可以广播一般为全9或者全A,这样我们就能得到
    68 AA AA AA AA AA AA 68
  • 接下来就是控制码,我们这边是抄表操作,因此控制码就是00010001
  • 数据得看各家的寄存器地址,查出来为B6 11,但是发送的时候要加33H,而且高位在右低位在左,即44 E9,可以得到
    68 AA AA AA AA AA AA 68 11 02 44 E9
  • 最后是校验码,ADD8可以写一个专门计算校验的函数,这里算出来是FC,所以完整的报文就是:68 AA AA AA AA AA AA 68 11 02 44 E9 FC 16
帧反馈
  • 这时电表回一条68 AA AA AA AA AA AA 68 91 04 44 E9 33 55 06 16 可以看出返回了电压数据是 33 55,前后颠倒再减33H求得2200,电表这位精度是0.1,那么就是220.0V

代码实现

/*---- 代码技巧 ----*/
#if 0/1    //  块注释符(/*...*/)是不可以嵌套使用的。
(#else)  //  可以使用 #if 0 ... #endif 来实现注释,且可以实现嵌套
#endif     //  可通过修改 0/1来屏蔽相关代码,实现调试
  
/*---- 定义一个帧结构体 ----*/
typedef struct DLT645_CmdFrame
{
    u32 BaudRate;
    u8 TxBuf[256];
    u8 RxBuf[256];
    u8 add[6];          //地址域
    u8 len;             //数据长度
    u8 cmd;             //控制码
    u8 data[2];         //数据域
     
}DLT645_CmdFrame;

/*******************************************************************************
* Function Name  : EMFrame_Packager
* Description    : 封装645帧
* Author         :沭osTT
* Notice         : 添加帧头长度校验码
*******************************************************************************/
void EMFrame_Packager(DLT645_CmdFrame *frame,u8 cmd,u8 datalen,u8 data[])
{
    frame->TxBuf[8] = cmd;   //控制码
    frame->TxBuf[9] = datalen;   //数据域长度
    memcpy(&frame->TxBuf[10],data,datalen);  //数据域
    frame->TxBuf[10+datalen] = CalcSum(frame->TxBuf,10+datalen);//ADD8校验码
    frame->TxBuf[11+datalen] = 0x16;//结束码
}
/*******************************************************************************
* Function Name  : EMFrame_UnPackager
* Description    : 解析645帧
* Author         :沭osTT
* Notice         : 
*******************************************************************************/
u8 EMFrame_UnPackager(u8 *buf,u16 cnt)
{
    u16 add8;
    add8 = CalcSum(buf,cnt-2);
     
    if((buf[0] != 0x68)||(buf[7] != 0x68))
    {
        return 1;//帧头错误
    }
    else if(buf[8] != 0x01)
    {
        return 2;//控制码错误
    }
    else if((buf[9] + 12) != cnt)
    {
        return 3;//长度错误
    }
    else if(buf[cnt-2] != add8)
    {
        return 4;//ADD8错误
    }
    else
    {
        return 0;
    }
}
/*******************************************************************************
* Function Name  : DataConvert
* Description    : 解析645数据转换
* Author         :沭osTT
* Notice         :
*******************************************************************************/
u32 DataConvert(u8 *buf)
{
    u8 cnt;
    u32 temp;
    cnt = buf[9]-2;  //数据个数 - 指令码(2字节) = 数据字节个数
    temp=0;
    while(cnt)
    {
        temp *=100;
        temp=temp+(((buf[11+cnt]-0x33)>>4)*10)|((buf[11+cnt]-0x33)&0x0F);
        cnt--;
    }
    return temp;
}

Ref:
https://www.cnblogs.com/VergilYang/p/8902612.html
https://www.cnblogs.com/codecamel/p/4882341.html

你可能感兴趣的:(协议:645规约学习(一))