热度 24
2014-4-3 15:35
2897 次阅读|
0 个评论
前天在做实验时,想在ucos ii 系统下触发一下外部中断玩玩,可没想到,按常归的中断要求编写完中断服务例程后,程序竟然跑飞了,触发按键中断后,我调试了一下,程序在一个默认的异常服务死循环里出不来了,我就郁闷了,想了之后,以为当OS 控制系统后在不同优先级任务间切换,不能再响应来自外部事件触发的中断呢,所以程序崩溃了呢,后来才发现,这是一个多么可笑的想法啊,呵呵,现在终于弄明白了,写点心得记录下来,以便完全理解。 看了ucos ii对中断的要求后才发现错哪了,任务调度之所以分为任务级任务调度和中断级任务调度,就是因为这个原因,学那么长时间了,竟然还不知道中断级任务调度是怎么调用了,悲剧啊,思而不学则殆,学而不思则惘,唉,把状态改了,以作警示,很明显,任务级任务调度是在任务间切换时调用的,具体什么时候调用呢?当一个任务有延时时,就会调用以便让一个更高优先级的任务进入就绪状态。而中断级任务调度呢,当然是在中断时调用以便让……这么简单的道理,怎么想不到呢?好像从来没想过这个问题……。 查资料后发现了这两个函数:OSIntEnter()和OSIntExit(),这两个函数是用来干啥呢?看源码吧! void OSIntEnter (void) { if (OSRunning == TRUE) { if (OSIntNesting 255) { OSIntNesting++; /* Increment ISR nesting level */ } } } 这个函数的源码真简单啊,不就是让一个变量加1吗?再来看一下注释: Description: This function is used to notify uC/OS-II that you are about to service an interrupt * service routine (ISR). This allows uC/OS-II to keep track of interrupt nesting and thus * only perform rescheduling at the last nested ISR. * . * Arguments : none * * Returns : none * * Notes : 1) This function should be called with interrupts already disabled * 2) Your ISR can directly increment OSIntNesting without calling this function because * OSIntNesting has been declared 'global'. * 3) You MUST still call OSIntExit() even though you increment OSIntNesting directly. * 4) You MUST invoke OSIntEnter() and OSIntExit() in pair. In other words, for every call * to OSIntEnter() at the beginning of the ISR you MUST have a call to OSIntExit() at the * end of the ISR. * 5) You are allowed to nest interrupts up to 255 levels deep. * 6) I removed the OS_ENTER_CRITICAL() and OS_EXIT_CRITICAL() around the increment because * OSIntEnter() is always called with interrupts disabled. 解释如下: 这个函数用来通知OS我们正准备进入中断服务例程,这允许OS保持中断嵌套的路径(次数), 以便于仅在最后一次嵌套的中断退出时才执行任务调度。 1.这个函数应当在关闭中断的情况下调用,为啥?涉及到全局变量的操作了吧,也就是在调用前后加下它哥俩:OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()。 2.可以直接增加OSIntNesting,而不必调用这个函数,因为这个变量是全局的! 3.一定要调用OSIntExit()这个函数,即使你直接增加OSIntNesting这个变量。也就是说,上面两个函数是哥俩,一定要成对使用,但是由于大哥本质上只是增加了中断嵌套次数,可以不用大哥,但一定得用小弟,为啥?下面再细说! 后央三句自己看吧,挺简单的! 再看老二函数源码: void OSIntExit (void) { #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */ OS_CPU_SR cpu_sr; #endif if (OSRunning == TRUE) { OS_ENTER_CRITICAL(); if (OSIntNesting 0) { /* Prevent OSIntNesting from wrapping */ OSIntNesting--; } if ((OSIntNesting == 0) (OSLockNesting == 0)) { /* Reschedule only if all ISRs complete ... */ OSIntExitY = OSUnMapTbl ; /* ... and not locked. */ OSPrioHighRdy = (INT8U)((OSIntExitY 3) + OSUnMapTbl ]); if (OSPrioHighRdy != OSPrioCur) { /* No Ctx Sw if current task is highest rdy */ OSTCBHighRdy = OSTCBPrioTbl ; OSCtxSwCtr++; /* Keep track of the number of ctx switches */ OSIntCtxSw(); /* Perform interrupt level ctx switch */ } } OS_EXIT_CRITICAL(); } } 源码不多,也不少,不过关键的需要理解的就那一行:OSIntCtxSw(),这是啥?中断级任务调度函数啊,终于出来了,看它的注释吧: ********************************************************************************************************* * EXIT ISR * * Description: This function is used to notify uC/OS-II that you have completed serviving an ISR. When * the last nested ISR has completed, uC/OS-II will call the scheduler to determine whether * a new, high-priority task, is ready to run. * * Arguments : none * * Returns : none * * Notes : 1) You MUST invoke OSIntEnter() and OSIntExit() in pair. In other words, for every call * to OSIntEnter() at the beginning of the ISR you MUST have a call to OSIntExit() at the * end of the ISR. * 2) Rescheduling is prevented when the scheduler is locked (see OS_SchedLock()) 翻译如下:这个函数用来通知OS我们已经完成了中断服务程充,当最后一次被嵌套的中断也完成时,OS将调用scheduler来决定是否有一个新的,更高优先级的任务,已经主绪。(当然没有更高的时就恢复被中断的任务) 总结:我遇到情况的主要原因大概是,当按普通方法写中断服务例程时,没有通知操作系统,触发中断时当前执行任务被中断,然后退出中断服务例程时,系统找不到原先被中断的任务,不知道该干啥,所以就进入了默认异常处理程序,死在里面出不来了,呵呵,不知道这样理解对不对,呵呵!