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);
}