μC/OS-II的内核结构
程序清单 L3.17 通知μC/OS-Ⅱ,脱离了中断服务
voidOSIntExit(void)
{
OS_ENTER_CRITICAL();(1)
if((--OSIntNesting|OSLockNesting)==0){(2)
OSIntExitY=OSUnMapTbl[OSRdyGrp];(3)
OSPrioHighRdy=(INT8U)((OSIntExitY3)+
OSUnMapTbl[OSRdyTbl[OSIntExitY]]);
if(OSPrioHighRdy!=OSPrioCur){
OSTCBHighRdy=OSTCBPrioTbl[OSPrioHighRdy];
OSCtxSwCtr++;
OSIntCtxSw();(4)
}
}
OS_EXIT_CRITICAL();
}
OSIntExit()看起来非常像OSSched()。但有三点不同。第一点,OSIntExit()使中断
嵌套层数减1[L3.17(2)]而调度函数OSSched()的调度条件是:中断嵌套层数计数器和锁定
嵌套计数器(OSLockNesting)二者都必须是零。第二个不同点是,OSRdyTbl[]所需的检索
值Y是保存在全程变量OSIntExitY中的[L3.17(3)]。这是为了避免在任务栈中安排局部变
量。这个变量在哪儿和中断任务切换函数OSIntCtxSw()有关,(见9.04.03节,中断任务
切换函数)。最后一点,如果需要做任务切换,OSIntExit()将调用OSIntCtxSw()[L3.17
(4)]而不是调用OS_TASK_SW(),正像在OSSched()函数中那样。
调用中断切换函数OSIntCtxSw()而不调用任务切换函数 OS_TASK_SW(),有两个原因,
首先是,如程序清单中L3.5(1)和图F3.6(1)所示,一半的工作,即CPU寄存器入栈的工作
已经做完了。第二个原因是,在中断服务子程序中调用OSIntExit()时,将返回地址推入
了堆栈[L3.15(4)和F3.6(2)]。OSIntExit()中的进入临界段函数OS_ENTER_CRITICAL()或
许将CPU的状态字也推入了堆栈L3.7(1)和F3.6(3)。这取决于中断是怎么被关掉的(见第8
章移植μC/OS-Ⅱ)。最后,调用OSIntCtxSw()时的返回地址又被推入了堆栈[L3.17(4)和
F3.1(4)],除了栈中不相关的部分,当任务挂起时,栈结构应该与μC/OS-Ⅱ所规定的完全
一致。OSIntCtxSw()只需要对栈指针做简单的调整,如图F3.6(5)所示。换句话说,调整
栈结构要保证所有挂起任务的栈结构看起来是一样的。

图3.6中断中的任务切换函数OSIntCtxSw()调整栈结构
有的微处理器,像Motorola68HC11中断发生时CPU寄存器是自动入栈的,且要想允许
中断嵌套的话,在中断服务子程序中要重新开中断,这可以视作一个优点。确实,如果用
户中断服务子程序执行得非常快,用户不需要通知任务自身进入了中断服务,只要不在中
断服务期间开中断,也不需要调用OSIntEnter()或OSIntNesting加1。程序清单L3。18
中的示意代码表示这种情况。一个任务和这个中断服务子程序通讯的唯一方法是通过全程
变量。
程序清单 L3.18Motorola68HC11中的中断服务子程序
M68HC11_ISR:/* 快中断服务程序,必须禁止中断*/
所有寄存器被CPU自动保存;
执行用户代码以响应中断;
执行中断返回指令;
3.10 时钟节拍
μC/OS需要用户提供周期性信号源,用于实现时间延时和确认超时。节拍率应在每秒
10次到100次之间,或者说10到100Hz。时钟节拍率越高,系统的额外负荷就越重。时钟
节拍的实际频率取决于用户应用程序的精度。时钟节拍源可以是专门的硬件定时器,也可
以是来自50/60Hz交流电源的信号。
用户必须在多任务系统启动以后再开启时钟节拍器,也就是在调用OSStart()之后。
换句话说,在调用OSStart()之后做的第一件事是初始化定时器中断。通常,容易犯的错
误是将允许时钟节拍器中断放在系统初始化函数OSInit()之后,在调启动多任务系统启动
函数OSStart()之前,如程序清单L3.19所示。
程序清单L3.19启动时钟就节拍器的不正确做法.
voidmain(void)
{
.
.
OSInit();/* 初始化uC/OS-II*/
.
.
/* 应用程序初始化代码 ...*/
/*... 通过调用OSTaskCreate()创建至少一个任务 */
.
.
允许时钟节拍(TICKER)中断;/* 千万不要在这里允许时钟节拍中断!!! */
.
.
OSStart();/* 开始多任务调度 */
}
这里潜在地危险是,时钟节拍中断有可能在μC/OS-Ⅱ启动第一个任务之前发生,此时μC/OS-Ⅱ是处在一种不确定的状态之中,用户应用程序有可能会崩溃。
μC/OS-Ⅱ中的时钟节拍服务是通过在中断服务子程序中调用OSTimeTick()实现的。
时钟节拍中断服从所有前面章节中描述的规则。时钟节拍中断服务子程序的示意代码如程序清单L3.20所示。这段代码必须用汇编语言编写,因为在C语言里不能直接处理CPU的寄存器。
程序清单L3.20时钟节拍中断服务子程序的示意代码
voidOSTickISR(void)
{
保存处理器寄存器的值;
调用OSIntEnter()或是将OSIntNesting加1;
调用OSTimeTick();
调用OSIntExit();
恢复处理器寄存器的值;
执行中断返回指令;
}
时钟节拍函数OSTimeTick()的代码如程序清单3.21所示。OSTimtick()以调用可由用户定义的时钟节拍外连函数
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)
