UC/OS-II基础知识之中断
1.中断
任务在运行过程中,应内部或者外部异步事件的请求终止当前任务而去处理异步时间所要求的任务的过程叫做中断,应中断请求而运行的程序叫做中断服务子程序,中断服务子程序的入口地址叫做中断向量。UC/OS-II系统响应中断的过程是:系统接收到中断请求时,如果这时CPU处于中断允许状态,即中断时开放的,系统就会终止正在运行的当前任务,而按照中断向量的指向转而去运行服务子程序。需要特别注意的是对于可剥夺形的UC/OS-II内核来说,中断子程序运行结束之后,系统将会根据情况进行一次任务调度去运行优先级别最高的就绪任务,并不一定接着运行被中断的任务。同时中断是可以嵌套的,即高优先级别的中断源的中断请求可以中断低优先级别的中断服务程序的运行。为了记录中断嵌套的层数,UC/OS-II定义了一个全局变量OSIntNesting,UC/OS-II的中断响应过程入下图所示
在编写中断服务程序时,需要用到两个重要的函数OSIntEnter()和OSIntExt()
函数OSIntEnter()的作用就是把全局变量OSIntNesting加1,从而用它来记录中断嵌套的层数。函数原型如下
void OSIntEnter (void)
{
if (OSRunning == OS_TRUE) {
if (OSIntNesting < 255u) {
OSIntNesting++; /* Increment ISR nesting level */
}
}
}
OSIntEnter()的调用通常发生在中断服务程序保护了被中断任务的断点之后运行用户中断服务代码之前。
另一个函数是OSIntExt(),在改函数中会将变量OSIntNesting减1,OSIntExt()的源码如下
void OSIntExit (void)
{
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr = 0;
#endif
if (OSRunning == OS_TRUE) {
OS_ENTER_CRITICAL();
if (OSIntNesting > 0) { /* Prevent OSIntNesting from wrapping */
OSIntNesting--;
}
if (OSIntNesting == 0) { /* Reschedule only if all ISRs complete ... */
if (OSLockNesting == 0) { /* ... and not locked. */
OS_SchedNew();
if (OSPrioHighRdy != OSPrioCur) { /* No Ctx Sw if current task is highest rdy */
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
#if OS_TASK_PROFILE_EN > 0
OSTCBHighRdy->OSTCBCtxSwCtr++; /* Inc. # of context switches to this task */
#endif
OSCtxSwCtr++; /* Keep track of the number of ctx switches */
OSIntCtxSw(); /* Perform interrupt level ctx switch */
}
}
}
OS_EXIT_CRITICAL();
}
}
该函数的流程图入下所示
中断服务子程序的流程图入下图所示
2.中断级任务切换
与任务级切换类似。完成中断级任务切换需要调用通过调用OSIntCtxSw()来完成。其代码如下所示
void OSIntCtxSw()
{
DWORD n = 0;
if(!(SS_SP->Exit)) {
n = SuspendThread(SS_SP->Handle);
}
OSTaskSwHook();
OSTrace( OBJ_SW, PT_SW_INT, OSTCBHighRdy, 0, OSPrioCur,OSPrioHighRdy,0 );
OSTCBCur = OSTCBHighRdy;
OSPrioCur = OSPrioHighRdy;
SS_SP = (OS_EMU_STK*) OSTCBHighRdy->OSTCBStkPtr;
ResumeThread(SS_SP->Handle);
}