本文设计并实现了基于时间触发的调度器,它通过传递消息的方式完成多任务的切换,可以满足实时、简单、可预测性等工程要求。这种设计还使得系统易于开发和维护,应用于车载音响系统中取得了很好的效果。 嵌入式系统中,通常采用两种本质上不同的调度方式:事件触发和时间触发。事件触发方式往往使用多级中断实现,其发生时间具有随机性;而时间触发方式则不同,它是通过一个全局时钟进行驱动的,系统的行为不仅在功能上确定,而且在时间上也是确定的。调度器的设计主要包括3个方面:消息队列、定时器和周期性任务调度。在调度器的实现中,将定时器的设置分离出来,并且定义不依赖于编译器的数据类型,通过修改这一部分可以轻松地将该调度器移植到多种硬件平台上使用。 一、消息队列的设计 消息队列MsgQue[]和定时队列TmrQue[]是调度器的核心数据结构。为了减少时钟中断中对它们的处理时间,还设置了2个队列——就绪索引队列RdIdx[]和定时索引队列TmrIdx[]。这4个队列都由静态数组实现。消息队列存放应用程序发送的单次消息和延时处理的消息。定时队列TmrQue[]和定时索引队列TmrIdx[]一一对应。其中,定时队列中存放定时消息的延时时间;而相对应的TmrIdx[]项则指向定时消息在消息队列中的位置。 二、定时器的设计 调度器必须先设定一个默认的时间片,这并不是件简单的事。时间片过长会导致系统对交互行为的响应表现欠佳;时间片太短又会明显地增大调度器处理耗时,而留给任务运行的时间却很短。根据V850处理器在车载音响上的实际需要,选择4 ms作为时间片。在定时器的中断服务程序中,扫描定时队列TmrQue口。如果有延时到期的任务,则将其从定时队列中删除并放在就绪索引队列RdIdx[]中去。对定时器相关的操作涉及具体的平台,在不同平台上移植调度器时需要修改这一部分。 三、周期性任务的处理方法 该系统周期长度必须是4 ms的整数倍。在每次时钟中断以后执行下面的函数,通过将要周期性执行的任务放入函数数组TskPatt[]()中就可以执行周期为8 ms、16 ms、32 ms、64 ms等周期性任务。 四、任务的调度 调度器的算法使用FCFS算法,就绪索引队列RdIdx[]按顺序存储要处理的消息的索引。消息MSG9的延时时间刚到,它的索引被插入到当前消息索引的后面,它就可以在下一次调度中得到处理。任务调度由wucExecTsk(void)函数来完成。它取出MsgQue[RdIdx[0]]对应的消息,以该消息的目的模块ID为索引,使用存放各个模块人口函数的函数数组TskTb1[](),就可以将该消息分发到相应的处理模块。因为该调度器是合作式的,所以每个任务处理函数都必须显示地调用退出任务的函数,否则该任务会永远的执行下去。
|