一种事件驱动型嵌入式软件框架设计

2017-04-25 06:04周春华
单片机与嵌入式系统应用 2017年4期
关键词:嵌入式软件链表任务调度

周春华

(解放军理工大学 野战工程学院,南京 210007)

一种事件驱动型嵌入式软件框架设计

周春华

(解放军理工大学 野战工程学院,南京 210007)

提出了一种事件驱动型嵌入式软件设计框架,抽象并实现了嵌入式软件程序中包括基于优先级的任务调度、基于消息队列的任务间通信、发行-订阅服务、共享资源访问和系统定时器服务等在内的公共功能,简化了嵌入式软件的应用程序设计。

嵌入式软件;事件驱动;软件框架

引 言

嵌入式软件程序通常采用面向过程方式开发,然而随着芯片成本的降低和需求的日益提高,嵌入式软件程序规模越来越来大,这种开发方式越来越难以驾驭日渐复杂的嵌入式软件程序,软件工程中的面向对象设计思想和应用程序框架设计理念开始逐渐成为嵌入式软件开发的重要方向。

本文提出了一种事件驱动型嵌入式软件框架,该框架抽象并实现了嵌入式软件程序的大量公共服务任务,包括基于优先级的任务调度、基于消息队列的任务间通信、发行-订阅模式、共享资源访问模式和系统定时服务等。在基于框架的程序设计中,嵌入式软件框架控制系统的运行,用户任务仅以被框架回调的方式运行,不仅简化了程序开发,而且使程序设计更加安全,不易出错。

1 事件驱动型嵌入式软件框架

事件驱动型嵌入式软件框架的工作原理如图1所示,框架包括一个消息循环、一个任务就绪表、一个基于优先级的任务调度器和一个消息队列。

图1 事件驱动型框架原理框图

中断到任务的通信,或是任务间的通信都通过消息队列进行。当中断或任务要向其他任务发送通知信息时,它会向消息队列发送一条消息,并同时在任务就绪表中将目标任务激活,这个消息包含了目标任务的 ID、消息码以及其他附加的消息内容。

任务调度器会不断检查任务就绪表,并查找其中优先级最高的任务(任务ID越小,优先级越高),当找到一个被激活的优先级最高的任务时,任务调度器会根据其ID检查消息队列发送给该任务的消息。因为任务是在消息发送的同时被激活的,因此这个时候队列中一定存在发给该任务的消息。任务调度器找出这个消息后分发给相应任务的消息处理函数进行处理。当队列为空时,任务就绪表中也必然仅仅剩下一个空闲任务(空闲任务始终激活),这时任务调度器会调用空闲任务的处理函数进行一些系统空闲处理(通常将空闲函数设为空,即什么也不做)。

在事件驱动型系统开发中,用户应用系统被划分为一个个独立的任务,每个任务都具有一个唯一的ID号来标识它们的优先级和任务自身。每个任务都具有一个消息处理函数,这个消息处理函数在系统初始化时被注册到框架,这样当框架查找到存在发送给该任务的消息时,会回调任务的消息处理函数进行消息处理。

2 基于优先级的任务调度算法

基于优先级的任务调度算法可以采用参考文献[1]中描述的算法,该算法中的任务就绪表如图2所示。

图2 任务就绪表

任务就绪表包括一个字节的优先级分组变量taskpriogroup和一个优先级变量数组taskprio[N],N最大为8,即数组taskprio[N]最多可包含8个字节。

taskprio[N]中的每一个位都表示一个任务的就绪状态,位的位置与任务ID的映射关系见图2,这样8个字节的taskprio[N]最多可以表达共 64个任务 ID(1~64)的就绪状态。当某一个任务被激活时,对应其 ID的位被置为1,当任务未激活时,对应的位被置为 0。

taskprio[0]中的任意一个位被置为1时,taskpriogroup的0位被置1,否则该位被清零;taskprio[1]中的任意一个位被置为1时,taskpriogroup的1位被置为1,否则该位被清零,以此类推。

这种算法的优势在于它的任务查找算法(在当前任务就绪表中查找被激活的优先级最高的任务)执行时间短而且具有确定的执行时间,算法细节可参见参考文献[1]。

图 2 中的就绪表最多可以管理 64 个任务,对于一般的嵌入式软件来说已经足够了。也可以通过扩充优先级分组变量 taskpriogroup和优先级变量数组 taskprio[N]来扩大框架管理的任务数。

3 主任务循环

不同于一般面向过程的嵌入式程序设计,事件驱动型系统的主任务循环由框架控制(如图3所示),框架会不断地在任务就绪表中查找最高优先级的任务,若无任务被激活,则框架会执行空闲处理函数,之后继续在就绪表中查找最高优先级的任务,周而复始;若在就绪表中查找到被激活的任务,则框架会去消息队列查找发给被激活的最高优先级任务的消息,并回调该任务的消息处理函数进行消息处理。从这里可以看到,当使用嵌入式软件框架进行编程时,应用程序设计者不必关注整个大循环的实现,大循环和任务的调度由框架控制,程序员所有的工作就是设计好消息处理函数,程序设计工作被简单化了。

图3 主任务循环流程图

4 消息队列与消息结构

图4 消息链表

为了便于消息的插入、删除与查找操作,消息队列采用单向链表实现,消息队列结构如图4所示。通常情况下,单向链表仅维护一个队列头指针就可以了,其他元素都可以通过遍历得到,图中的链表与通常的单向链表相比,消息队列多维护了一个尾指针,目的是减少在队列中插入新元素的时间。

消息帧结构如图5所示,消息帧内容必须包括指向下一个消息节点的指针,目标任务ID和一个消息码,附属内容是可选的。

图5 消息帧结构

这里的目标任务ID是一个多字节数组,长度与优先级变量数组taskprio的长度相同,其中的每一个位表示一个任务ID,这样做的目的是支持嵌入式软件设计中的发行-订阅模式,也就是面向对象中的观察者模式[2],即多个任务可以向某个任务订阅消息,这个任务需要向多个订阅其消息服务的多个任务同时发送消息,此时,消息的发送不是单点的,而是群发的。

5 共享资源访问

共享资源的访问控制是嵌入式软件设计中的常见问题,例如一个串口正在进行通信时,另外的任务可能也会需要使用串口,就出现了资源的共享问题。在操作系统支持的抢占式多任务环境下,这个问题通常通过互斥型信号量来解决,在非抢占式多任务情况下,通常有以下几种策略:

① 在顶层任务规划时,确保不同任务对资源的使用时间错开,不会发生资源竞争的情况,这种设计虽然很好,但有时很难做到。

② 在调用资源时,允许资源返回忙状态。当任务发现当前要使用的资源为忙状态时,它等待一段时间再重试,这种设计的缺点是不像前述的互斥型信号量一样用一个统一的方法解决问题,每个调用任务都需要编写超时等待函数,工作量比较大。

③ 共享资源内嵌一个缓存机制。这正是本框架采取的方法,框架维护一个消息缓存队列,当共享资源正在处理一个消息,而另外一个消息不期而至时,共享资源可以将这个后到的消息放入缓存队列,待当前任务处理完毕后,再将这个缓存的消息转移到主消息队列,一旦被转移到主消息队列,这个消息就会被调度器检查到并再次交给资源任务进行处理。

6 系统定时服务

嵌入式系统中会有大量的定时需求,从毫秒级、秒级、甚至到分钟级不等,操作系统通常会有一个时基为应用程序提供定时服务,这个时基的周期通常为10~100 ms。本文的嵌入式软件框架也提供了一个定时服务,当用户程序需要使用定时服务时,只需要调用框架提供的定时服务订阅函数接口,通知框架定时的时间长度、单次还是周期定时以及定时时间到时框架发给任务的定时消息的消息码。订阅完成后框架就会按照指定的时间间隔和发送模式(单次还是周期)定时给任务发送消息。

框架的这个功能比通常的操作系统做得更好,通常的操作系统会提供一个固定的时基,当任务需要更大的时基时,需要自己维护一个累加变量以累计时间。而框架可以直接提供任务所需要的任意长度的时间,进一步简化用户程序的设计。框架内部为任务维护了虚拟定时器[3],当任务向框架订阅定时服务时,框架会为其维护一个虚拟定时器,这个虚拟定时器的时钟源来自于系统的固定硬件定时器,在虚拟定时器的内部会为任务维护时钟累加变量,这样框架仅在到达用户指定的任务时间间隔时,才会向任务发送通知消息。

结 语

本文详细描述了嵌入式软件框架设计中的任务调度优先级算法以及任务通信队列、发行-订阅模式、共享资源的延迟访问和系统定时服务等的实现方案,根据本文方案所设计的嵌入式软件框架在多个工业产品中获得应用,取得了良好的应用效果,采用框架进行程序设计不仅简化了程序员的编程工作,而且使编程更加安全。

[1] Jean J,Labrosse.Micro C/OS-II,TheReal-TimeKernel,Second Editio[M].邵贝贝,译.北京:北京航空航天大学出版社,2003.

[2] 秦晓波.设计模式之禅[M].北京:机械工业出版社,2015.

[3] 李云.专业嵌入式软件开发[M].北京:电子工业出版社,2012.

周春华(博士),主要研究方向为机电工程。

Event-driven Programming Frame Design for Embedded System

Zhou Chunhua

(Field engineering college,PLA Univ. of Sci&Tech,Nanjing 210007,China)

A kind of event-driven programming frame for embedded systems is proposed in this paper.The public functions in embedded software are abstracted and realized,which includes task schedule based on priority,communications based on message queue,publish-subscribe service,access of share-resources and timer services.So the application programming of embedded software is simplified.

embedded software;event-driven;software frame

TP336

A

士然

2016-11-17)

猜你喜欢
嵌入式软件链表任务调度
基于人工智能的模块化嵌入式软件开发研究
基于二进制链表的粗糙集属性约简
基于改进NSGA-Ⅱ算法的协同制造任务调度研究
跟麦咭学编程
基于时间负载均衡蚁群算法的云任务调度优化
基于链表多分支路径树的云存储数据完整性验证机制
全景相机遥控器嵌入式软件V1.0 相关操作分析
云计算环境中任务调度策略
云计算中基于进化算法的任务调度策略
基于Eclipse的航天嵌入式软件集成开发环境设计与实现