2.2 内核的移植
内核的移植也就是使实时内核能够在某个微处理器或微控制器上正常运行。移植工作包括以下几个内容:
(1)在OS_CPU.H中用#define定义三个宏,声明C96中能够识别的数据类型和堆栈的增长方向。
(2)在OS_CPU.C中用C语言重新编写以下几个函数:OSTaskStkInit、OSStartHighRdy、OSTaskCreateHook、OSTaskSwHook、OSTaskDelHook、OSTaskStatHook、OSTimeTickHook。
(3)在OS_CPU.ASM中编写几个汇编语言函数LoadCtx()、OSCtxSw()、OSIntCtxSw()、OSTickISR()。
2.3 实时内核在应用中应注意的问题
一个实时系统的软件由实时操作系统加上应用程序构成。应用程序与操作系统的接口通过系统调用来实现。用80C196KB作为系统的MCU,只能用内部RAM作为TCB和所有系统存储器(含各种控制表)以及各个任务的工作和数据单元。因此一定要注意以下几点:
(1)为各个任务分配各自的堆栈区,该堆栈区既作为任务的工作单元,也作为任务控制块的保护单元。
(2)系统的任务控制块只存放各任务的堆栈指针,而任务的状态均存放于任务堆栈中。在一个任务退出运行时,通过中断把它的状态进栈,然后把它的堆栈指针保存于系统的TCB中;再根据优先级取出优先级最高的已就绪任务的堆栈指针SP映象值送入SP中;最后执行中断返回指令转去执行新任务。
(3)各任务的数据和工作单元尽量用堆栈实现,这样可以允许各任务使用同一个子程序。使用堆栈实现参数传递并作为工作单元,而不使用绝对地址的RAM,可实现可重入子程序。该子程序既可为各个任务所调用,也可以实现递归调用。
2.4 应用μC/OS-II实时内核的主要部分
(1)任务的分配
实时系统中的任务有别于前后台系统中的子程序模块,任务是处理机按程序处理数据的过程,是个动态的概念。一般一个任务对应于一段独立的主程序,它可能调用各种子程序,并使用各种系统资源如中断、外设等,以完成某种选定的功能,且允许多个任务并行。根据该系统的性能指标和技术要求,可对系统进行如下的任务划分:按键中断、LCD显示、串行通信、打印与报警、信道巡检A/D采样与数据处理、系统信息显示、系统工作参数测量、电源切换与充电管理共八个任务。
(2)任务的调度
μC/OS-II的任务调度是按优先级进行的,根据各任务的实时性要求及重要程度,分别置它们的优先级为4、9、8、7、6、11、10、5。其中0、1、2、3、OS_LOWEST_PRIO-3、OS_LOWEST_PRIO-2、OS_LOWEST_PRIO-1、OS_LOWEST_PRIO这几个优先级保留以被系统使用。优先级号越低,任务的优先级越高。这样程序之间的通信可以通过按键中断置标志来实现,其中按键中断的优先级最高。当其它任务运行时,按键中断将使得系统服务转向运行按键中断处理子程序ISR。当中断处理子程序运行完后,转向判断就绪状态任务的优先级别。如果发现有比中断前任务优先级更高的任务,则转向执行该任务。先判断其运行标志,如果是‘非’,则又等待。再重复上述过程。如果在执行完ISR后发现没有比中断前任务优先级更高的,则转向中断前的子程序继续运行。该系统的软件处理没有采用优先级转换的方法,而是采用状态置位判断的方法,这样可以减少程序的复杂性。
(3)任务间的通信
任务间通信最简便的方法是使用共享数据结构。虽然共享数据区法简化了任务间的信息交换,但是必须保证每个任务在处理共享数据时的排它性,以避免竞争和数据的破坏。通常与共享资源打交道时,使之满足互斥条件最一般的方法有以下几种:
·关中断;
·使用测试并置位;
·禁止任务切换;
·利用信号量。
在本系统中采用了前两种。关中断是一种最简单快捷的方式,也是在中断服务子程序中处理共享数据结构的唯一方法。要注意的是:关中断的时间要尽量短,以免影响操作系统的中断处理。其应用模式如下:
void Function(void)
{
OS_ENTER_CRITICAL();
…… /*在此处理共享数据*/
OS_EXIT_CRITICAL();
}
测试并置位方式需要有一个全局变量,约定好先测试该变量;如果是约定的数值,则执行该任务,否则不执行该任务。这种方法称测试并置位(TEST-AND-SET),或TAS。其应用程序如下:
Disable interrupts /*关中断*/
If ('Access Variable' is 0){ /*若资源不可用,标志为0*/
Set variable to 1; /*置资源不可用,标志为1*/
Reenable interrupts; /*重开中断*/
Access the resource; /*处理该资源*/
Disable interrupts; /*关中断*/
Set the 'Access Variable' back to 0;/*清资源不可使用,标志为0*/
Reenable interrupts; /*重新开中断*/
}else { /*否则*/
Reenable interrupts; /*开中断*/
/*资源不可使用,以后再试*/
}
(4)时钟节拍