在嵌入式开发里,RTOS(实时操作系统)几乎是中高端项目的标配。而uC/OS-II可以说是国内工程师最熟悉的一款RTOS了,很多人的第一个嵌入式操作系统项目就是用它做的。虽然现在FreeRTOS用的人更多,但uC/OS-II的设计思路非常经典,搞懂了它再学其他RTOS都很快。
uC/OS-II是Micrium公司出的一款抢占式实时内核,核心功能就是任务管理。跟裸机编程那种while(1)大循环不一样,用RTOS可以把程序分成多个独立的任务,每个任务都觉得自己独占CPU,内核负责在合适的时机切换任务。这样程序结构清晰多了,实时性也有保证。
任务是uC/OS-II里最基本的概念。每个任务都有自己的栈空间、优先级、任务控制块。优先级是uC/OS-II调度的依据,优先级数值越小优先级越高,高优先级的任务就绪了可以立刻抢过低优先级任务的CPU使用权——这就是抢占式调度的意思。uC/OS-II(经典版本)最多支持64个任务,每个任务优先级必须唯一,不能有同优先级。
任务调度的核心是就绪表和调度算法。uC/OS-II用了一个很巧妙的位图方式来管理就绪任务,找最高优先级就绪任务的时间是固定的,不管系统里有多少任务都是O(1)的复杂度。具体做法是用一个8位的就绪组寄存器和一个8x8的就绪表,每一位对应一个优先级是否就绪,通过查表法快速定位最高优先级。
移植uC/OS-II到一个新的MCU上,主要改三个文件:OS_CPU.H、OS_CPU_A.ASM、OS_CPU_C.C。OS_CPU.H里定义和CPU相关的类型和宏,比如栈的生长方向、关中断开中断的宏。OS_CPU_A.ASM是汇编文件,实现任务切换、OSStartHighRdy启动最高优先级任务、时钟节拍中断这些跟CPU架构强相关的代码。OS_CPU_C.C里主要是OSTaskStkInit任务栈初始化函数,以及一些hook函数。
用uC/OS-II写程序要特别注意几个地方。第一,中断服务函数要快,进去关中断前调用OSIntEnter,出来后调用OSIntExit,这样中断级任务调度才能正常工作。第二,高优先级任务别一直占着CPU,要适当地调用OSTimeDly之类的函数让出CPU,不然低优先级任务永远得不到执行。第三,共享资源要用互斥信号量或关中断保护,防止多任务同时访问出问题。