OS_CPU_C.C

来源:互联网 发布:如何解除电脑网络限制 编辑:程序博客网 时间:2024/05/16 11:53
µC/OS-Ⅱ的移植实例要求用户编写六个简单的C函数:OSTaskStkInit()OSTaskCreateHook()OSTaskDelHook()OSTaskSwHook()OSTaskStatHook()OSTimeTickHook()唯一必要的函数是OSTaskStkInit(),其它五个函数必须得声明但没必要包含代码。
OSTaskStkInt()OSTaskCreate()和OSTaskCreateExt()通过调用OSTaskStkInt()来初始化任务的堆栈结构,因此,堆栈看起来就像刚发生过中断并将所有的寄存器保存到堆栈中的情形一样。图8.3显示了OSTaskStkInt()放到正被建立的任务堆栈中的东西。注意,在这里我假定了堆栈是从上往下长的。下面的讨论同样适用于从下往上长的堆栈。在用户建立任务的时候,用户会传递任务的地址,pdata指针,任务的堆栈栈顶和任务的优先级给OSTaskCreate()和OSTaskCreateExt()。虽然OSTaskCreateExt()还要求有其它的参数,但这些参数在讨论OSTaskStkInt()的时候是无关紧要的。为了正确初始化堆栈结构,OSTaskStkInt()只要求刚才提到的前三个参数和一个附加的选项,这个选项只能在OSTaskCreateExt()中得到。

回顾一下,在µC/OS-Ⅱ中,无限循环的任务看起来就像其它的C函数一样。当任务开始被µC/OS-Ⅱ执行时,任务就会收到一个参数,好像它被其它的任务调用一样。

 

void MyTask (void *pdata)

{

    /* 对'pdata'做某些操作 */

    for (;;) {

        /* 任务代码                      */

    }

}

 

如果我想从其它的函数中调用MyTask()C编译器就会先将调用MyTask()的函数的返回地址保存到堆栈中,再将参数保存到堆栈中。实际上有些编译器会将pdata参数传至一个或多个寄存器中。在后面我会讨论这类情况。假定pdata会被编译器保存到堆栈中,OSTaskStkInit()就会简单的模仿编译器的这种动作,将pdata保存到堆栈中[F8.3(1)]。但是结果表明,与C函数调用不一样,调用者的返回地址是未知的。用户所拥有的是任务的开始地址,而不是调用该函数(任务)的函数的返回地址!事实上用户不必太在意这点,因为任务并不希望返回到其它函数中。

这时,用户需要将寄存器保存到堆栈中,当处理器发现并开始执行中断的时候,它会自动地完成该过程的。一些处理器会将所有的寄存器存入堆栈,而其它一些处理器只将部分寄存器存入堆栈。一般而言,处理器至少得将程序计数器的值(中断返回地址)和处理器的状态字存入堆栈[F8.3(2)]。很明显,处理器是按一定的顺序将寄存器存入堆栈的,而用户在将寄存器存入堆栈的时候也就必须依照这一顺序。

接着,用户需要将剩下的处理器寄存器保存到堆栈中[F8.3(3)]。保存的命令依赖于用户的处理器是否允许用户保存它们。有些处理器用一个或多个指令就可以马上将许多寄存器都保存起来。用户必须用特定的指令来完成这一过程。例如,Intel 80x86使用PUSHA 指令将8个寄存器保存到堆栈中。对Motorola 68HC11处理器而言,在中断响应期间,所有的寄存器都会按一定顺序自动的保存到堆栈中,所以在用户将寄存器存入堆栈的时候,也必须依照这一顺序。

现在是时候讨论这个问题了:如果用户的C编译器将pdata参数传递到寄存器中而不是堆栈中该作些什么?用户需要从编译器的文档中找到pdata储存在哪个寄存器中。pdata的内容就会随着这个寄存器的储存被放置在堆栈中。


一旦用户初始化了堆栈,OSTaskStkInit()就需要返回堆栈指针所指的地址[F8.3(4)]。OSTaskCreate()和OSTaskCreateExt()会获得该地址并将它保存到任务控制块(OS_TCB)中。处理器文档会告诉用户堆栈指针会指向下一个堆栈空闲位置,还是会指向最后存入数据的堆栈单元位置。例如,对Intel 80x86处理器而言,堆栈指针会指向最后存入数据的堆栈单元位置,而对Motorola 68HC11处理器而言,堆栈指针会指向下一个空闲的位置。



0 0