通讯规约编程入门

首先照例是一段废话:

从进公司到现在,经历着,也成长着……从一开始写25160驱动(现在想来,这实际上是加强版面试性质的任务),到后来的规约编程,再到现在的核心程序升级开发,这些无不让我感到兴奋!每当回首这些时光,我都会感到莫名的喜悦和骄傲。虽说是25160引我入行的,但是,归约编程对于我来说,一定是令我感觉最亲切,也最有感情的。今天在整理本本的时候,偶然发现了一个札记,我突然觉得它是不应该仅仅待在我的本本里的,于是发上来,与后人共勉。

注:本文源于多篇网络文章及bbs言论,除了南京DISA小凡(2005-6-23 )之外的其他作者或出处不详,我仅作了剪辑、编辑和少量修改。

/***********************************我就是传说中霸气的分割线**************************************/

通讯规约编程入门:从解剖一只麻雀开始


我发现最快入门的方法就是所谓的“解剖一只麻雀”。
找一个典型的Polling(问答式)小规约,比如说一个直流屏规约,有规约,有源代码。先读懂规约本身。然后参照规约分析源代码。
源代码的分析应该先从数据结构着手。从变量的命名、注释了解这些变量的大概含义。习惯良好的程序应该有清楚的注释及简洁的说明。对于新手不可能要求百分之百了解这些变量的含义,能了解百分之五六十就相当不错了。即使是对这个程序员习惯比较熟悉的高手至多也只能了解百分之八九十。对于不理解的变量只能在程序中观察其用法及功能。
大致了解了数据结构后就可以分析程序了。
程序的分析要先宏观后微观。
所谓的宏观就是要了解程序的结构,流程,调用关系。
对于一个规约程序,其基本功能大致包括:初始化,报文组装及发送,报文接收,报文解析及数据入库。
微观就是对每一个功能模块进行分析。如:
报文组装先是判断发送什么报文。按功能可分为:召唤遥测、召唤遥信、校时等等;按机制可分为:循环查询报文、定时查询报文、插入报文等等。决定发送什么报文后就是按照规约规定的帧格式对这个报文的组装。组装完成就可以发送。
报文的发送一般是在中断程序里完成的,一般规约程序里只要调用一个填写发送缓冲区的函数就行了。
报文的接收说起来相对比较复杂。
从串口收到一个一个二进制字节按顺序填入一个环形接收缓冲区,这部分功能应该是在接收中断里完成的。在对其进行报文解析分析之前它是没有意义的,我称其为数据流。而规约程序的功能就是要从这个数据流中拾取出完整的规约报文并将其填入处理缓冲区。注意:这儿提到了两个缓冲区:接收缓冲区和处理缓冲区。一个好的程序应该将这两个缓冲区分开。既要高效率,又不能丢帧,这其中有很多技巧,很多细节要注意。拾取的过程包括:寻找同步头;计算帧长;复制进处理缓冲区;校验帧的完整性等等。这些过程在此就不细讲了,回头有空再向朋友们介绍。另外说一句:对于所有不同的规约,这部分功能基本上是一样的,无非就是同步头不同,帧长位置不同,校验方式不同等。我为此专门做了一个通用模块,通过组态,可适应目前大部分的规约报文。这样在编制不同规约程序的时候可以省去不少工作量。
收到一个完整的规约报文之后就可以对其进行解析。按照报文类型调用不同的处理函数,如遥测、遥信等处理函数。这些函数的功能就是从接收的报文中提取感兴趣的数据,该处理的处理,该入库的入库。

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
经典的电力系统通讯规约 //内部函数 void InitDNP3(BYTE ChanNo); void DNP3FrameProcess(void); void DNP3TimeControl(void); //解桢函数 BYTE DNP3CRCVerify( int BitLength,BYTE *DNP3ReceiveP ); void DNP3UnlockFrame(void); void DNP3DataLnkCon(void); //链路层控制 void Ft3Check(void); //解含有UserData的Ft3帧, 把UserData存入应用缓冲区 void DltoApp(void); //将DL层校验过的数据存入APP缓冲区 void AppRead(void); //读 void AppWrite(void); //写 void TimeWrite(void); //校时 void IINWrite(void); //写IIN标志位 void UnsolMessage(void); //产生主动上报的信息 void ClassMessage(void); //树类上报标志 void AppTimeMeasure(void); //通道延时测量 void ClassDefination(void); //类数据重定义 void AppFreez(void); //执行冻结 void AppControl(void); void UnsolAble(void); void UnsolDisable(void); void DnpClockToTime(struct CLOCK *lTimer,BYTE * Timebuf); //转换为DNP时间 void DnpTimeToClock(BYTE * Timebuf,struct CLOCK *lTimer); void AppYkSelect(void); //遥控选择 void AppYkOperate(void); //遥控执行 void DirectOperYk(void); //直接遥控执行 void GYKSelect(BYTE LNode,BYTE LAction); void GYKOperate(BYTE byNodeNum,BYTE lFun,BYTE lAct); void NewToOld(void); WORD GetOldId(BYTE i); //组桢函数 void DNP3Framing(void); void DNP3CRCGenerator( int BitLength, int StartBitPos, BYTE *TransData ); void AppFrame(void); //应用层组桢函数 void TransFrame(BYTE Lcase); //传输层组桢函数 void DlFrame(void); //链路层组桢函数 void Ft3FrameUserDate(BYTE LS); //组一帧FT3帧 void Ft3FrameCon(void); //组链路层命令桢 void AppSendUnsol(void); //如有突发信息上送,优先上送 void AppSendConfirm(void); //如有CONFIRM信息则上送 void AppRespone(void); //应用层响应帧 void DNP3AddIndication(void); //添加内部信息字IIN void FrameOneObject(BYTE AppFrameType,unsigned short iArray); void FrameOneInfo(unsigned short iDataStart,unsigned short iDataStop); unsigned short GetTotalDataN(BYTE bObjNum);//获取数据个数 void GetTimeDate(void); //获取当前时间 void DNP3GetYx(unsigned short i,BYTE); //静态遥信 void GetYxChange(WORD i); //变化遥信包括SOE void DNP3GetYc(unsigned short i); //静态遥测 void GetYcChange(WORD i); //变化遥测 void GetCounter(WORD i); //计数 void GetFrozenCounter(WORD i); //冻结计数 void DNP3GetAo(BYTE i); //AO数据 WORD GetAo(BYTE i); void AppControlRespone(void); void TimeRespone(void); //响应延时时间 void YkSelectRespone(void); void YkOperateRespone(void); void OperateAoRe(void);

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值