移植μC/OS-Ⅱ
μC/OS-Ⅱ要求用户提供一个时钟资源来实现时间的延时和期满功能。时钟节拍应该每秒钟发生10-100次。 为了完成该任务, 可以使用硬件时钟, 也可以从交流电中获得50/60Hz的时钟频率。
用户必须在开始多任务调度后(即调用OSStart()后)允许时钟节拍中断。换句话说,就是用户应该在OSStart()运行后,μC/OS-Ⅱ启动运行的第一个任务中初始化节拍中断。通常所犯的错误是在调用OSInit()和OSStart()之间允许时钟节拍中断(如程序清单L8.4所示)。
程序清单 L8.4 在不正确的位置启动时钟节拍中断
voidmain(void)
{
.
.
OSInit();/* 初始化 ? μC/OS-II*/
.
.
/* 应用程序初始化代码 ...*/
/*... 调用OSTaskCreate()建立至少一个任务 */
.
.
允许时钟节拍中断;/* 千万不要在这里允许!!! */
.
.
OSStart();/* 开始多任务调度 */
}
有可能在μC/OS-Ⅱ开始执行第一个任务前时钟节拍中断就发生了。在这种情况下,μC/OS-Ⅱ的运行状态不确定,用户的应用程序也可能会崩溃。
时钟节拍ISR的原型如程序清单L8.5所示。这些代码必须写在汇编语言中,因为用户不能直接从C语言中访问CPU寄存器。如果用户的处理器可以通过单条指令来增加OSIntNesting,那么用户就没必要调用 OSIntEnter()了。增加OSIntNesting要比通过函数调用和返回快得多。OSIntEnter()只增加OSIntNesting,并且作为临界段代码中受到保护。
程序清单 L8.5 时钟节拍ISR的原型
voidOSTickISR(void)
{
保存处理器寄存器;
调用OSIntEnter()或者直接将 OSIntNesting加1;
调用OSTimeTick();
调用OSIntExit();
恢复处理器寄存器;
执行中断返回指令;
}
8.05OS_CPU_C.C
μC/OS-Ⅱ的移植实例要求用户编写六个简单的C函数:
OSTaskStkInit()
OSTaskCreateHook()
OSTaskDelHook()
OSTaskSwHook()
OSTaskStatHook()
OSTimeTickHook()
唯一必要的函数是OSTaskStkInit(),其它五个函数必须得声明但没必要包含代码。
8.05.01OSTaskStkInt()
OSTaskCreate()和OSTaskCreateExt()通过调用OSTaskStkInt()来初始化任务的堆栈结构,因此,堆栈看起来就像刚发生过中断并将所有的寄存器保存到堆栈中的情形一样。图8.3显示了OSTaskStkInt()放到正被建立的任务堆栈中的东西。注意,在这里我假定了堆栈是从上往下长的。下面的讨论同样适用于从下往上长的堆栈。
在用户建立任务的时候,用户会传递任务的地址,pdata指针,任务的堆栈栈顶和任务的优先级给OSTaskCreate()和OSTaskCreateExt()。虽然OSTaskCreateExt()还要求有其它的参数,但这些参数在讨论OSTaskStkInt()的时候是无关紧要的。为了正确初始化堆栈结构,OSTaskStkInt()只要求刚才提到的前三个参数和一个附加的选项,这个选项只能在OSTaskCreateExt()中得到。
图 8.3 堆栈初始化(pdata通过堆栈传递)
回顾一下,在μC/OS-Ⅱ中,无限循环的任务看起来就像其它的C函数一样。当任务开始被μC/OS-Ⅱ执行时,任务就会收到一个参数,好像它被其它的任务调用一样。
voidMyTask(void*pdata)
{
/* 对'pdata'做某些操作 */
for(;;){
/* 任务代码 */
}
}
如果我想从其它的函数中调用MyTask(),C编译器就会先将调用MyTask()的函数的返回地址保存到堆栈中,再将参数保存到堆栈中。实际上有些编译器会将pdata参数传至一个或多个寄存器中。在后面我会讨论这类情况。假定pdata会被编译器保存到堆栈中,OSTaskStkInit()就会简单的模仿编译器的这种动作,将pdata保存到堆栈中[F8.3(1)]。但是结果表明,与C函数调用不一样,调用者的返回地址是未知的。用户所拥有的是任务的开始地址,而不是调用该函数(任务)的函数的返回地址!事实上用户不必太在意这点,因为任务并不希望返回到其它函数中。
这时,用户需要将寄存器保存到堆栈中,当处理器发现并开始执行中断的时候,它会自动地完成该过程的。一些处理器会将所有的寄存器存入堆栈,而其它一些处理器只将部分寄存器存入堆栈。一般而言,处理器至少得将程序计数器的值(中断返回地址)和处理器的状态字存入堆栈[F8.3(2)]。很明显,处理器是按一定的顺序将寄存器存入堆栈的,而用户在将寄存器存入堆栈的时候也就必须依照这一顺序。
接着,用户需要将剩下的处理器寄存器保存到堆栈中[F8.3(3)]。保存的命令依赖于用户的处理器是否允许用户保存它们。 有些处理器用一个或多个指令就可以马上将许多寄存器都保存起来。用户必须用特定的指令来完成这一过程。例如,Intel80x86使用PUSHA指令将8个寄存器保存到堆栈中。对Motorola68HC11处理器而言,在中断响应期间,所有的寄存器都会按一定顺序
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)
