今天发现自己的程序里本来想用临界代码段保护的,本来是这一对
1 { 2 ... 3 OS_ENTER_CRITICAL();, 4 .... 5 OS_EXIT_CRITICAL(); 6 }
但是发现由于当时疏忽写成了OSIntEnter();和OSIntExit();这一对函数和上面完全不是一个概念,这对是在进入中断服务函数ISR中后,要调用的,其实也就是将中断嵌套层数加1,并且告知OS我已经进中断了,要做好中断前任务的保存工作,完成中断服务前调用OSIntExit()告知OS我要退出中断了,减一次中断嵌套层数,并且要查看是否需要调度任务。
对于可剥夺型的UCOSII内核来说,中断服务子程序运行结束前,需要进行一次任务调度。正因为有了这次调度,在中断结束时,系统才能去运行另外一个任务,而不是一定要返回被中断的任务。当然,这个被运行的任务一定是优先级别最高的就绪任务。UCOSII之所以这样做,就是为了提高系统的实时性。
那么,什么时候要用到这对函数?在中断服务函数中使用这对函数,乃是为了在中断结束后可进行任务调度,使得系统更加“实时”。假如中断服务函数里没有进行任何的与任务有关操作,而且时间比较短,是没必要使用这对函数的。譬如,我们使用定时器模拟串口发送,中断服务函数里只是进行IO口的翻转,这个时候加入OSIntExit()简直是不可忍受的,因为开销太大,大大地影响模拟串口的波特率。
OSIntEnter()用来通知内核:现在已经进入中断服务程序,禁止调度;OSIntExit()用来通知内核:中断服务已结束,可以进行调度。因此,在这两个函数之间就是调度禁区,因此它们要成对使用。下面列出这对函数的代码:
1 void OSIntEnter (void) 2 { 3 if (OSRunning == OS_TRUE) { 4 if (OSIntNesting < 255u) { 5 OSIntNesting++; /* Increment ISR nesting level */ 6 } 7 } 8 } 9 10 void OSIntExit (void) 11 { 12 #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ 13 OS_CPU_SR cpu_sr = 0u; 14 #endif 15 16 17 18 if (OSRunning == OS_TRUE) { 19 OS_ENTER_CRITICAL(); 20 if (OSIntNesting > 0u) { /* Prevent OSIntNesting from wrapping */ 21 OSIntNesting--; 22 } 23 if (OSIntNesting == 0u) { /* Reschedule only if all ISRs complete ... */ 24 if (OSLockNesting == 0u) { /* ... and not locked. */ 25 OS_SchedNew(); 26 OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy]; 27 if (OSPrioHighRdy != OSPrioCur) { /* No Ctx Sw if current task is highest rdy */ 28 #if OS_TASK_PROFILE_EN > 0u 29 OSTCBHighRdy->OSTCBCtxSwCtr++; /* Inc. # of context switches to this task */ 30 #endif 31 OSCtxSwCtr++; /* Keep track of the number of ctx switches */ 32 OSIntCtxSw(); /* Perform interrupt level ctx switch */ 33 } 34 } 35 } 36 OS_EXIT_CRITICAL(); 37 } 38 }
在ucosii中,通常用一个任务来完成异步事件的处理工作,而在中断服务程序中只是通过向任务发送消息的方法去激活这个任务。