新闻中心

EEPW首页 > 嵌入式系统 > 设计应用 > μC/OS-II的内核结构

μC/OS-II的内核结构

作者: 时间:2016-10-08 来源:网络 收藏

上述两步完成以后,用户可以开始服务于叫中断的设备了[L3.15(3)]。这一段完全取决于应用。μC/OS-Ⅱ允许中断嵌套,因为μC/OS-Ⅱ跟踪嵌套层数OSIntNesting。然而,为允许中断嵌套,在多数情况下,用户应在开中断之前先清中断源。

调用脱离中断函数OSIntExit()[L3.15(4)]标志着中断服务子程序的终结,OSIntExit()将中断嵌套层数计数器减1。当嵌套计数器减到零时,所有中断,包括嵌套的中断就都完成了,此时μC/OS-Ⅱ要判定有没有优先级较高的任务被中断服务子程序(或任一嵌套的中断)唤醒了。如果有优先级高的任务进入了就绪态,μC/OS-Ⅱ就返回到那个高优先级的任务,OSIntExit()返回到调用点[L3.15(5)]。保存的寄存器的值是在这时恢复的,然后是执行中断返回指令[L3.16(6)]。注意,如果调度被禁止了(OSIntNesting>0),μC/OS-Ⅱ将被返回到被中断了的任务。

以上描述的详细解释如图F3.5所示。中断来到了[F3.5(1)]但还不能被被CPU识别,也许是因为中断被μC/OS-Ⅱ或用户应用程序关了,或者是因为CPU还没执行完当前指令。一旦CPU响应了这个中断[F3.5(2)],CPU的中断向量(至少大多数微处理器是如此)跳转到中断服务子程序[F3.5(3)]。如上所述,中断服务子程序保存CPU寄存器(也叫做CPUcontext)[F3.5(4)],一旦做完,用户中断服务子程序通知μC/OS-Ⅱ进入中断服务子程序了,办法是调用OSIntEnter()或者给SIntNesting直接加1[F3.5(5)]。然后用户中断服务代码开始执行[F3.5(6)]。用户中断服务中做的事要尽可能地少,要把大部分工作留给任务去做。中断服务子程序通知某任务去做事的手段是调用以下函数之一:OSMboxPost(),OSQPost(),OSQPostFront(),OSSemPost()。中断发生并由上述函数发出消息时,接收消息的任务可能是,也可能不是挂起在邮箱、队列或信号量上的任务。用户中断服务完成以后,要调用OSIntExit()[F3.5(7)]。从时序图上可以看出,对被中断了的任务说来,如果没有高优先级的任务被中断服务子程序激活而进入就绪态,OSIntExit()只占用很短的运行

时间。进而,在这种情况下,CPU寄存器只是简单地恢复[F3.5(8)]并执行中断返回指令

[F3.5(9)]。如果中断服务子程序使一个高优先级的任务进入了就绪态,则OSIntExit()将占用

较长的运行时间,因为这时要做任务切换[F3.5(10)]。新任务的寄存器内容要恢复并执行中

断返回指令[F3.5(12)]。

图 3.5 中断服务

进入中断函数 OSIntEnter()的代码如程序清单 L3.16 所示,从中断服务中退出函数

OSIntExit()的代码如程序清单 L3.17 所示。如前所述,OSIntEnter()所做的事是非常少的。

程序清单 L3.16 通知μC/OS-Ⅱ,中断服务子程序开始了.

voidOSIntEnter(void)

{

OS_ENTER_CRITICAL();

OSIntNesting++;

OS_EXIT_CRITICAL();

}

恢复所有CPU寄存器; (5)

程序清单 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

中的示意代码表示这种情况。一个任务和这个中断服务子程序通讯的唯一方法是通过全程

变量。



关键词:

评论


相关推荐

技术专区

关闭