嵌入式系统应用程序方案之一――基于事件驱动的应用程序框架

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

嵌入式系统应用程序方案之一嵌入式系统应用程序方案之一——基于事件驱动的应用程序框架英创信息技术有限公司2005年10月本文介绍以英创公司嵌入式PC模块为平台,以事件驱动为特色的一种通用的嵌入式系统应用程序方案,该方案满足大多数中、低端嵌入式系统需求,可广泛应用于智能测控设备、POS终端产品、工业自动化、网络通讯管理等领域。采用英创嵌入式网络模块的客户,更是可以此为基础,直接进入应用功能的软件规划及实现,从而大大节省应用程序的开发时间,同时保证应用程序的高稳定性。本应用程序方案的核心是通过对一个简单的任务命令队列进行操作,来实现各个不同的应用程序功能。图1是本方案的典型流程框图。图1事件驱动的应用程序流程框图技术支持:028-85136173.系统流程概述在图1中表示了3种不同的流程,它们是程序代码流程、任务命令(也称为事件)流程、以及数据的流程,以下对这三种流程做一简要介绍。程序流程应用程序启动后,首先进行必要的程序初始化配置,便进入系统核心代码,核心程序将依次读取系统任务队列中的事件代码,并根据代码内容转入相应的程序功能模块。不同的程序功能模块对应着不同的任务,即图中所标注的任务1、任务2、任务n等等,这些任务代码的特点之一是通过内部的状态机机制来避免程序阻塞,使得程序能快速返回系统任务调度单元,从而实现任务间的切换。任务划分的原则一般是按照应用功能或层次来划分,如任务1对原始数据进行处理,任务2对处理的结果数据进行网络传送,任务3对数据进行文件备份。为了提高系统对事件的响应速度,每个任务不宜设计得过长,就大多数嵌入式系统应用来看,可以把任务的执行时间控制在100ms之内,对需要更长执行时间的功能,可以通过内部设置状态机的方式来化解。命令流程系统命令,通常也称为系统事件,可由系统中多个单元产生,这些单元可以是系统的定时中断程序,与应用相关的硬件中断程序以及各个任务功能程序模块,它们根据自身的运行状况,生成必要的事件并把这些事件推入系统任务队列。进入系统任务队列的事件是完全异步的,它们按照时间顺序排列,统一由系统核心代码读取,并启动相应的任务模块对该事件进行处理,这就是所谓的事件驱动机制。在程序设计中采用事件驱动的一个直接的好处是降低了各任务间的耦合性,提高了代码的可靠性及可维护性。命令通常可定义成枚举变量,另可考虑命令参数段,可存放若干参数或字符串。系统任务队列是一个典型的FIFO数据结构,系统为中断程序和普通的任务模块提供了发送事件的API函数。定时任务发生器是一段加载到系统定时中断中的代码,在DOS系统中一般可提秒级以上的定时事件,更小时间间隔的事件,可通过系统的其他定时器中断实现,对于一般的嵌入式应用,最小定时事件不宜小于5ms,否则会无为增加CPU的开销,降低系统性能。在命令定义中,一般会定义IDLE或NOP命令,在IDLE任务中可以放常规的数据处理,也可以放检查是否有键盘、是否有网络数据来等等,并可形成必要的事件发送到系统任务队列,以启动相应的处理。数据流程技术支持:028-85136173嵌入式系统应用程序方案之一各个任务模块的主要功能之一就是对各级应用数据进行必要的加工,并形成新的数据。典型的数据加工可以是:对串口来的数据进行帧格式分析,提取相关数据,即通常的通讯规约分析;对AD采集的原始数据进行某种统计处理,提取特征数据;读取数字输入状态,进行必要处理;读取网络报文,进行必要的应用层规约解析应用数据存文件,文件数据处理等等由于每个任务的执行机会具有一定的不确定性,因此需要对数据开设一定的缓冲区,对一般的应用来说,数据处理通常都是顺序进行的,所以数据缓冲区的结构通常采用FIFO数据结构,缓冲区的数据单元即可是简单的字节、字,也可以是复合的数据结构。在英创提供的程序中,串口的数据缓冲区就是采用的FIFO数据结构,数据单元为一个字节,FIFO结构的数据缓冲区也称为环型buffer。可以由一个任务作数据处理,另一个任务作数据传送,对多任务共享的单一数据单元,可通过设置信号灯的方法来确保数据单元的完整性,对多个数据单元,同样可考虑采用FIFO数据结构。对数据响应时间有严格要求的应用,也可以用一个任务实现数据采集处理和网络通讯全过程。以下具体介绍实现上述方案的主要代码。建议用户在阅读本文之前,已对英创嵌入式模块的功能测试程序有了基本了解。技术支持:028-85136173.主要程序代码分析主控流程与应用任务#includestdio.h//包含所需的C运行库#includedos.h#include“etr_tcp.h”//英创TCP/IP库#include“cmdrive.h”//事件驱动API定义intSysInit();//系统初始化函数定义voidSysExit();//系统退出处理intmain(){inti1,len,State,ExitFlag;//局部变量CMDCmdCode;//系统命令枚举变量charCmdPar[20];//系统命令所带参数i1=SysInit();//首先进行初始化for(ExitFlag=0;;)//系统主循环{ReloadWDT();//加载watchdogState=NET_Running();//网络链路管理CmdCode=CmdQueue.GetCmd(CmdPar);//从系统任务队列读取命令switch(CmdCode){caseNOP://进行常规处理,如检查键盘、网络、串口等NetPackagePro();//做必要的网络低层处理//若网络接收到数据,则启动相应任务进行处理If(NetHasData())CmdQueue.PushCmd(TASK1);break;caseTASK1:i1=Task1.Do();//也可以是普通C函数break;caseTASK2:i1=Task2.Do();if(i1)CmdQueue.PushCmd(TASK2);//发送命令,以继续任务处理break;caseTASK3:i1=Task3.Do();break;default:ExitFlag=1;//非法命令,退出}技术支持:028-85136173(ExitFlag)break;}SysExit();return0;}系统初始化程序SysInit(),首先是对系统提供的资源进行初始化,如网络初始化、串口初始化、LCD显示初始化等等,然后是对应用定义的功能对象进行初始化,最后是安装中断服务程序,启动定时任务发生器。相应地,SysExit()函数则主要是卸载中断,释放在初始化中分配的动态buffer。在主循环中的NOP处理,是以网络通讯为例,客户在实际应用程序设计中可以安排其他需要的处理,如处理键盘、处理串口数据等等。对应用级任务,建议采用C++的类来实现,每个类对象应至少有2个公共函数:Init()和Do()函数,主控程序可以通过Do()函数的返回值来判断处理已完成或未完成,若未完成,可发命令再启动本函数进行后续处理,在上面的程序中任务TASK2的处理就是这样做的。用C++的类对象来实现应用功能,可通过私有变量来定义处理的状态,在进行交互式的通讯处理时,如操作串口设备,FTP文件上传等,特别有用,一旦需要处理程序等待对端响应,程序就返回系统控制进行其他处理,等下次再进入该任务模块时,程序可根据当前状态继续相应的处理,这就是所谓的状态机机制。下面是应用任务的类定义:#defineST00#defineST11#defineST22#defineST33classAppTASK{intState;//私有的状态变量intDoST0();//各个分步处理intDoST1();intDoST2();intDoST3();public:intInit();//对包括State在内的变量进行初始化intDo();//任务处理函数};技术支持:028-85136173()中实现具体的状态转移:intAppTASK::Do(){inti1;i1=1;//返回值=1:处理未完成;=0:处理完成switch(State){caseST0:DoST0();State=ST1;//前进到下一状态break;caseST1:DoST1();State=ST2;//前进到下一状态break;caseST2:DoST2();State=ST3;//前进到下一状态break;caseST3:DoST3();State=ST0;//返回初始状态I1=0;//处理完成!break;}returni1;}技术支持:028-85136173嵌入式系统应用程序方案之一整个程序方案中,核心的代码是实现系统的事件驱动功能,被定义成一个C++类如下:#if!defined(_CMDRIVE_H)#define_CMDRIVE_H#ifdef__cplusplus#define__CPPARGS...#else#define__CPPARGS#endif#includedos.henumCMD{NOP,TASK1,TASK2,TASK3,EXIT};//可以根据应用定义更多的命令#defineMaxCmdStack400//定义系统任务队列的长度#definePARLEN14//每个命令所带参数的长度classTaskQueue{staticunsignedintPutIdx;//通过2个index的操作,使CmdBuf[]成为staticunsignedintGetIdx;//逻辑上的环型buffer,即FIFO数据结构staticCMDCmdBuf[MaxCmdStack];staticcharCmdPar[MaxCmdStack][PARLEN];staticstructtimeOldTime;staticstructdateOldDate;staticunsignedintTickCount;//定时计数staticunsignedintTickSize;//确定最小的定时间隔,可变,初值为0staticvoidinterruptINT1C_Handler(__CPPARGS);//通过INT1C实现定时任务发生器staticintISR_PushCmd(CMDNewCmd,char*pPar=NULL);//中断程序中使用public:TaskQueue();~TaskQueue();CMDGetCmd(char*pPar=NULL);//读取当前队列中的命令intPushCmd(CMDNewCmd,char*pPar=NULL);//填入新的命令到系统任务队列voidStartQueue();//启动定时任务发生器voidStopQueue();//关闭定时任务发生器};externclassTaskQueueCmdQueue;//在cmdrive.cpp中定义的类变量实例#endif技术支持:028-85136173函数,用于实现任务队列和定时任务发生:CMDTaskQueue::GetCmd(char*pPar)//从FIFO读取命令{CMDCmdCode;if(GetIdx!=PutIdx){disable();CmdCode=(CMD)CmdBuf[GetIdx];if(pPar!=NULL)memcpy(pPar,CmdPar[GetIdx],PARLEN);GetIdx=(GetIdx+1)%MaxCmdStack;enable();return

1 / 10
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功