1 引言
当前,嵌入式开发领域对产品的要求越来越多.如通信速率,稳定性,产品功能,可扩展性,可移植性,适应性等。为了适应这些要求,作者对低版本的μC/OS-II做了一些改进。并选择一款性价比高的微处理器LPC2210作为其运行的硬件平台。本文论述的高级继电器保护装置除可以动态地实现模拟量和开关量的数据采集外,还可以作为web终端通过远程主机对终端进行控制或访问。
2 μC/OS-II其内核结构
宏观的讲,μC/OS-Ⅱ大致分成内核结构、任务管理、时间管理、任务之间的通信与同步和CPU的移植等5个部分。由于嵌入式多任务应用功能软件系统是应用设计的范畴,所以并不包含在内核中。内核保留给上层应用的接口有3个,分别是软保护、任务间的通信ITC、和设备服务DSR。一个μC/OS-II内核现状的结构图如图1所示。
图1 μC/OS-Ⅱ内核现状结构简图
3 μC/OS-Ⅱ关键算法逻辑
μC/OS-II采用的是可剥夺型内核,它总是执行就绪条件下优先级最高的任务。系统通过两种方法进行任务调度:一是时钟节拍或其它硬件中断到来后,系统会调用函数执行切换任务功能;二是任务主动进入挂起态或等待态,这时系统通过发软中断命令或依靠处理器执行陷阱指令来完成任务切换,中断服务程序或陷阱处理程序的向量地址必须指向函数OSCtxSw()。任务的优先级唯一地标识了任务,即使两个任务的重要性是相同的,任务间也必须有优先级上的差异,这就意味着高优先级的任务被处理完成之后,必须进入等待态或者挂起态,否则低优先级的任务永远也不可能执行,从而严重暴露出μC/OS-Ⅱ的缺点,甚至造成系统瘫痪。在产品的开发中也不难发现其内核算法存在的一些问题,如内核具体代码方面的、体系结构方面的、以及移植作者方面的问题,其中最显著的就是硬实时性和设备驱动框架问题。
3.1硬保护算法的改进
在μC/OS-II操作系统中,临界区、硬保护和软保护是几个紧密联系的概念,而硬保护算法又与开关中断、堆栈和局部变量相联系。从保护的角度考虑,系统的代码可以划分为三种运行环境,即任务环境、中断环境和设备环境。当代码运行于这三种环境中时,需要的保护有很大的区别。下面将对临界区及其保护措施中的部分概念作出定义。
定义1:和中断环境相关的系统保护称为硬保护(HP,Hard Protect)。
定义2:和设备环境相关的系统保护称为设备保护(DP , Device Protect)。
定义3:纯粹任务之间的保护称为软保护(SP,Soft Protect)。
区别使用不同的保护机制对提高系统的中断能力和稳定性是非常重要的。当系统中大部分功能是与硬件设备进行数据交流时应尽量用软保护SP和设备保护DP代替硬保护HP,也是提高系统实时反应能力的重要手段。硬保护的方法有三种,在三种硬保护算法的实现方法中。第一种方法只是单纯的开关中断,因此最简单;但在嵌套调用时通常会出现内层的开中断代码干扰外层保护的逻辑。第二种方法借助堆栈功能很好地解决了第一种方法的嵌套问题,但堆栈指针无法确定。第三种方法是在每个硬保护代码的函数中定义一个局部变量,进入保护前保存状态,退出保护时恢复状态。当OS_CRITICAL_METHOD==3时,实现代码如下:
Void functionx()
{
#if OS_CRITICAL_METHOD==3
OS_CPU_SR cpu_sr;
#endif
⋯⋯
OS_ENTER_CRITICAL();
⋯⋯ //需要硬保护的临界区代码
OS_EXIT_CRITICAL();
}
3.2调度器算法的改进
众所周知,μC/OS-II在设计时强调实时性。它采用单一的基于优先级的抢先式调度算法,有效地保证了实时性的要求。其另外一个特点是任务切换带来的时延窗口很小。在任务的逻辑状态中,只有就绪态中优先级最高的任务才可以被真正运行。μC/OS-II任务级的调度器是通过函数OSSched()实现的,0ssched()基本上分布在μC/OS-II的各种ITC功能块中。调度器函数的伪代码如下:
{
(1)如果锁定任务切换(配合软保护),则直接退出。
(2)计算当前优先级任务。
(3)如果当前任务就是最高优先级任务,则直接退出。
(4)将最高优先级任务编号(OSPrioHighRdy)赋给当前任务编号(OSPrioCur)。
(5)读出最高优先级任务的控制块数据指针到OSTCBHighRdy指针。
(6)保存当前任务的环境。保存当前任务的sP到OS_TCB结构中的堆栈指针。
(7)读出最高优先级任务OSTCBHighRdy及其中的SP,设置堆栈,恢复所改任务的环境,并读出堆栈中保存的PC(程序计数器,任务当前代码位置)设置好处理器的PC器存器,任务即可开始执行。
在任务数据结构0S_TCB描述中只能见到等待、休眠和就绪三个标记值。每个任务具有一个任务控制块OS_TCB,任务控制块负责记录任务执行的环境,包括任务的优先级、堆栈指针和相关事件控制块指针等。内核将系统中处于就绪态的任务在就绪表中进行标注,通过就绪表中的两个变量OSRdyGrp和OSRdyTbl[]可快速查找系统中就绪的任务。让任务进入等待、就绪等状态等标记任务状态描述值的功能是分散在其它模块中完成的,在此需要修OS_TCB中的OSTCBStat字段。如用ITC中的信号量把任务设置到等待态或者把相关任务设置为就绪态等。
为了提高μC/OS-II适应性,在保证其实时性的前提下,对μC/OS-II的任务状态图的等待或挂起态分离为阻塞和等待态,以便实现优先级与时间片结合式调度。从而可以从体系结构上避免μC/OS-II存在的不足。如缺乏时间片调度、低优先级的任务很难得到执行、不支持同优先级任务的调度、优先级反转等问题。改进的任务状态转换图2。
图2改进的任务状态转换图
3.3任务就绪算法的改进
改进的μC/OS-II可以管理多达255个任务甚至更多,并且提供功能齐全的实时操作服务。实际上,就绪任务表是一个位矩阵。OSRdyTb1矩阵中位的值为0或1,表示对应的prio任务是否就绪。prio的数据位分为两部分,Y表示纵坐标,x表示横坐标,和矩阵中的一位对应。OSRdyGrp是纵坐标上就绪任务组的纪录,只要该组中任何一位代表的任务就绪(非零),Os_RdyGrp纵坐标的对应位就标记为就绪。任务就绪算法和查询就绪算法如下:
(1)任务就绪算法:根据任务优先级数使任务进入就绪状态
OSRdyGrp 1=OSMapTbl[prio》》3]; //用Y映射出纵坐标位
OSRdyTb1[prio》》3] 1=OSMapTb1[prio&0x07]; //用X映射出横坐标位
(2)查询就绪算法:通过此算法。μC/OS-II可以找出进入就绪态的优先级最高的任务。
y = OSUnMapTbl[OSRdyGrp]; //直接对应出纵坐标
x = OSUnMapTbl[OSRdyTbl[y]]; //直接对应出横坐标
prio=(y《《3)+x; //算出优先级
由于老版本的μC/OS-II最多只能管理64个任务.分别对应优先级0~63,其中0为最高优先级,63为最低级,系统保留了4个最高优先级的任务和4个最低优先级的任务.实际上用户可以使用的任务数仅有56个。就绪任务表其实是一个8x8的位矩阵,而且这个矩阵可以简化为横纵两个数组,同时保持了常数运算。对于要求用μC/OS-II管理更多任务的情况,如要管理255个任务,该算法仍然具有意义。改进前和改进后的任务就绪表如图3。
图3改进前和改进后的任务就绪表
此时。最低优先级OS_LOWEST_PRIO的定义值可以大于63,但不能大于254。当μC/OS-II初始化的时候。最低优先级OS_LOWEST_PRIO总是被赋给空闲任务idle task。就绪表(readv list)和事件等待表(event wait lists)由一个16x16的矩阵代替。从理论上讲.这也是最低优先级OS_LOWEST_PRIO的定义值不能大于254的原因。
3.4软保护算法
纯粹任务之间的保护称为软保护(SP,Soft Protect)。在μC/OS-II中,软保护包括OSSchedLock和OSSchedUnLock两个函数,用于保护纯任务间全局变量的访问。基本思路是借助硬保护递增(解锁时递减)标记变量OSLockNesting,并在任务调度器中判断此标记变量,以此锁住任务调度器。
4 改进的μC/OS-II在LPC2210上的移植
移植μC/OS-II到LPC2210上,需编写与处理器相关的几个文件:OS_CPU.H、OS_CPU_A.S、OS_CPU_C.C。除了编写这三个文件之外,还必须编写目标板的初始化启动代码,这是运行任何其它软件的基础。μC/OS-II要求所有*.c文件都要包含头文件includes.h,这样使得用户项目中的每个*.c文件不用考虑它实际上需要那些头文件。使用includes.h的缺点是可能会包含一些不相关的头文件,也可能会增加每个文件的编泽时间,但却增强了代码的可移植性。本移植不使用软中断SWI做底层接口,在OS_CPU.H中定义#define OS_CRITICAL_METHOD 3,即采用第三种方式实现开/关中断。具体用法已在前面作了介绍。
5 结束语
本文针对μC/OS-II的关键算法在分析的基础上进行了改进,并将其应用到了基于ARM7的RISC微处理器LPC2210上。通过实际的调试和在高级继电器保护装置中的应用,表明改进方案是可行的。在不损害实时性的前提下,增强了μC/OS-Ⅱ对需求的适应性、执行效率和对任务的管理能力。
本文创新点:(1)通过对μC/OS-Ⅱ的体系结构和关键算法的分析,指出了其在应用中存在的不足和改进的方法。(2)增强了μC/OS-II对需求的适应性、执行效率和对任务的管理能力。(3)对EasyARM2200开发板提供的例程做了改进并将其移植到了自己的开发板上,为应用功能的扩展打下了基础。
相关文章