本帖最后由 forgot 于 2023-2-16 14:31 编辑
都知道移植过uC/OS-II操作系统之后,在单片机的一些串口等中断服务程序中需要加入OSIntEnter();和OSIntExit();两个函数,并且这两个函数一定是成对出现的,在进入的时候调用OSIntEnter();,出来之前调用一次OSIntExit();这是为什么呢? 首先了解一下uC/OS-II的中断处理过程,由于uC/OS-II 采用的是可剥夺型实时多任务内核。可剥夺型的实时内核在任何时候都运行就绪了的最高优先级的任务。所以当运行系统接收到中断请求之后,系统就会按照CPU中断向量运行对应的中断服务子程序,当子程序运行完之后,如果有优先级更高的任务已经就绪,程序就会优先级更高的任务去运行;UCOSII之所以这样做,就是为了提高系统的实时性。 中断嵌套:
uC/OS-II的中断处理过程:
首先而为了保证系统调度器不会再中断服务子程序中进行任务的调度切换,所以在进入的时候通过OSIntEnter();将Interrupt nesting level(中断嵌套级别)这个OSIntNesting全局变量进行++来记录当前中断嵌套的层数,即OSIntNesting++;嵌套多达255层的中断。当OSIntNesting大于0的时候,系统是不会进行任务调度的。而在退出中断服务之前进行OSIntNesting--;当判断到OSIntNesting等于0的时候,如果OSLockNesting 也为0,会判断是否有更高级别的优先级任务已经就绪,如果有的,会切换到该任务进行运行,否则会切换到中断之前的任务继续运行。也就是在中断中使用OSIntEnter();与OSIntExit();的意义。 void OSIntEnter (void)
{
if (OSRunning == OS_TRUE) {
if (OSIntNesting < 255u) {
OSIntNesting++; /* Increment ISR nesting level */
}
}
}
void OSIntExit (void)
{
#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr = 0u;
#endif
if (OSRunning == OS_TRUE) {
OS_ENTER_CRITICAL();
if (OSIntNesting > 0u) { /* Prevent OSIntNesting from wrapping */
OSIntNesting--;
}
if (OSIntNesting == 0u) { /* Reschedule only if all ISRs complete ... */
if (OSLockNesting == 0u) { /* ... and not locked. */
OS_SchedNew();
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
if (OSPrioHighRdy != OSPrioCur) { /* No Ctx Sw if current task is highest rdy */
#if OS_TASK_PROFILE_EN > 0u
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();
}
}
对于OSIntNesting变量来说,在程序进入main();的时候通过OSInit();中的OS_InitMisc();函数将OSIntNesting进行了清零,所以,在每次OSIntEnter();和OSIntExit();也都是成对出现,完成一次完整的嵌套标记与解除。其实进入中断的时候如果不调用OSIntEnter();直接通过OSIntNesting++;也是可以完成的。 static void OS_InitMisc (void)
{
#if OS_TIME_GET_SET_EN > 0u
OSTime = 0uL; /* Clear the 32-bit system clock */
#endif
OSIntNesting = 0u; /* Clear the interrupt nesting counter */
OSLockNesting = 0u; /* Clear the scheduling lock counter */
OSTaskCtr = 0u; /* Clear the number of tasks */
OSRunning = OS_FALSE; /* Indicate that multitasking not started */
OSCtxSwCtr = 0u; /* Clear the context switch counter */
OSIdleCtr = 0uL; /* Clear the 32-bit idle counter */
#if OS_TASK_STAT_EN > 0u
OSIdleCtrRun = 0uL;
OSIdleCtrMax = 0uL;
OSStatRdy = OS_FALSE; /* Statistic task is not ready */
#endif
#ifdef OS_SAFETY_CRITICAL_IEC61508
OSSafetyCriticalStartFlag = OS_FALSE; /* Still allow creation of objects */
#endif
}
对于是否每次进入中断都要调用这两个函数实际上也不一定,如果进入中断时间很短,并且没有做与任务相关的一些操作,如只是进行了IO控制之后立即退出,也可以不进行OSIntEnter();和OSIntExit();的操作,因为没有必要。
|