μC/OS-II,一种多任务实时操作系统(RTOS)。这里所谓的多任务,并非是“多进程”,实际是一种“伪多任务”,CPU一次只能运行一个任务,因为任务之间大多相互独立,可以快速切换,所以认为在一定时间内任务是“并发运行的”,也就是多任务。
μC/OS-II采用占先式内核,任务基于优先级设定,优先级是任务的标识,一个优先级只能对应一个任务( μC/OS-III中一个优先级可以对应多个任务)。所谓占先式内核,意味着已经准备就绪的高优先级任务可以抢占正在运行的低优先级任务的CPU使用权。优先级号越小任务的优先级别越高,如优先级为1的任务,级别高于优先级为2的任务。这里的“抢占CPU使用权”也就是发生任务切换,并不是说高优先级任务可以“鲁莽地、随意地”打断正在运行的低优先级任务,而是通过系统的任务调度实现的。发生任务切换主要是以下两种情况:
a)正在运行的任务被挂起suspend()或进入等待状态(延时等待或等待事件发生)。
b)发生中断,在中断结束后系统进行任务调度。
任务切换的过程,CPU将当前运行任务的数据压入任务自身的堆栈,将即将要运行的任务的数据从堆栈中取出。(类似于发生了一次中断,因此任务切换一般通过软中断或陷进中断实现)。值得一提的是,任务具有“独立性”,系统给每个任务都分配了堆栈(大小可自行设定),也就说任务一旦被创建,便有了自己的专属堆栈。
关于移植:
一个任务切换的过程,需要保存用到的所有寄存器。但μC/OS-II是用C语言写的,而C语言不能直接操纵寄存器,只有汇编语言才能直接操纵寄存器。因此,在任务切换过程中必须想办法从C语言中调用汇编语言,以通过汇编语言来操纵寄存器。不同的编译器对从C语言调用汇编这个方面有不同的规定和实现:
1,有的编译器允许直接在C语言中内嵌汇编的,如code warriors。
2,有的编译器不允许在C语言中内嵌汇编,但允许直接从C语言中调用汇编子程序(当然,被调用的汇编子程序是放在汇编文件中的)。如CCS。
3,有的编译器既不允许在C语言中内嵌汇编,也不允许在从C语言中调用汇编子程序,但可以实现软中断,所用可以用软中断的方式进入汇编子程序,再在汇编子程序中操纵寄存器。
需要移植的主要是三个与CPU相关的文件:
1)OS_CPU.H 文件
2) OS_CPU_A.ASM 文件
a)OSStartHighRdy(); 运行优先级最高的就绪任务函数
b)OSCtxSW( ); 任务级的任务切换函数
c)OSIntCtxSW(); 中断级的任务切换函数
d)OSTickISR(); 时钟节拍中断服务函数
3) OS_CPU_C.C 文件
OSTaskStkInit( ); 任务堆栈初始化函数
对于1)OS_CPU.H文件,主要是 定义数据类型、定义OS_STK数据类型、定义堆栈生长方向、定义开关中断、定义函数OS_TASK_SW( )指向函数OSCtxSw()、声明汇编文件2)中的几个函数。关于定义开关中断,μC/OS-II给了三种开关中断的方法,需要我们根据上述编译器对汇编的规定补全三种方法的代码。
对于2)OS_CPU_A.ASM文件,此部分的移植需要一定的汇编语言基础,尤其要熟悉所要移植到的处理器的汇编语言。下面是μC/OS-II移植到msp430的源码中汇编文件中几个函数的编写所要做的事,思路是通用的。
a).OSStartHighRdy() MUST:
; a) Call OSTaskSwHook() then,
; b) Set OSRunning to TRUE,
; c) Switch to the highest priority task.
b).OSCtxSw() MUST:
; a) Save the current task's registers onto the current task stack
; b) Save the SP into the current task's OS_TCB
; c) Call OSTaskSwHook()
; d) Copy OSPrioHighRdy to OSPrioCur
; e) Copy OSTCBHighRdy to OSTCBCur
; f) Load the SP with OSTCBHighRdy->OSTCBStkPtr
; g) Restore all the registers from the high priority task stack
; h) Perform a return from interrupt
c).OSIntCtxSw() MUST:
; a) Call OSTaskSwHook()
; b) Copy OSPrioHighRdy to OSPrioCur
; c) Copy OSTCBHighRdy to OSTCBCur
; d) Load the SP with OSTCBHighRdy->OSTCBStkPtr
; e) Restore all the registers from the high priority task stack
; f) Perform a return from interrupt
d).OSTickISR() MUST:
a) Save all the CPU registers
b) Call OSIntEnter() or OSIntNesting ++
c) Call OSTimeTick()
d) Call OSIntExit
e) Restore the CPU registers
f) Perform a return from interrupt
对于3) OS_CPU_C.C文件,唯一必须移植的是任务堆栈初始化函数OSTaskStkInit(),通过调用此函数来初始化任务的堆栈结构,调用后堆栈看起来就像刚发生过中断并将所有的寄存器保存到堆栈中的情形一样。一旦用户初始化了堆栈,OSTaskStkInit()就需要返回堆栈指针所指的地址。
关于移植后应用程序APP的编写,任务、信号量、邮箱等的创建与使用都可在μC/OS-II源码中相应的C文件里找到函数原型。 |