您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 管理学资料 > uCOSii中断处理过程详解(一)
一.UCOSII的中断过程简介系统接收到中断请求后,如果CPU处于开中断状态,系统就会中止正在运行的当前任务,而按中断向量的指向去运行中断服务子程序,当中断服务子程序运行完成后,系统会根据具体情况返回到被中止的任务继续运行,或转向另一个中断优先级别更高的就绪任务。由于UCOSII是可剥夺型的内核,所以中断服务程序结束后,系统会根据实际情况进行一次任务调度,如果有优先级更高的任务,就去执行优先级更高的任务,而不一定要返回被中断了的任务。二.UCOSII的中断过程的示意图三.具体中断过程1.中断到来,如果被CPU识别,CPU将查中断向量表,根据中断向量表,获得中断服务子程序的入口地址。2.将CPU寄存器的内容压入当前任务的任务堆栈中(依处理器的而定,也可能压入被压入被中断了的任务堆栈中。3.通知操作系统将进入中断服务子程序。即:调用OSIntEnter()或OSIntNesting直接加1。4.If(OSIntNesting==1){OSTCBCur-OSTCBStrPtr=SP;}//如果是第一层中断,则将堆栈指针保存到被中断任务的任务控制块中5.清中断源,否则在开中断后,这类中断将反复的打入,导致系统崩贵6.执行用户ISR7.中断服务完成后,调用OSIntExit().如果没有高优先级的任务被中断服务子程序激活而进入就绪态,那么就执行被中断了的任务,且只占用很短的时间.8.恢复所有CPU寄存器的值.9.执行中断返回指令.四.相关代码与编译器相关的数据类型:typedefunsignedcharBOOLEAN;typedefunsignedcharINT8U;typedefunsignedintOS_STK;//堆栈入口宽度为16位(一)voidOSIntEnter(void)的理解uCOS_II.H中定义:#ifdefOS_GLOBALS#defineOS_EXT#else#defineOS_EXTextern#endif//定义全局宏OS_EXT#ifndefTRUE#defineTRUE1#endifOS_EXTBOOLEANOSRunning;//定义外部BOOLEAN类型全局变量,用来指示//核是否在运行OS_EXTINT8UOSIntNesting;//定义外部8位无符号整型数全局变量,用来表//示中断嵌套层数OS_CORE.C中的OSIntEnter()函数原型:voidOSIntEnter(void){if(OSRunning==TRUE)//如果内核正在运行则进入if{if(OSIntNesting255)//如果嵌套层数小于255,则可以继//续{OSIntNesting++;//嵌套层数加1}}}(二)在中断服务子程序中加if(OSIntNesting==1){…}的原因uCOS_II.H中定义:typedefstructos_tcb{OS_STK*OSTCBStkPtr;//声明指向任务堆栈栈顶的16位指针………………}OS_TCB;//定义名为OS_TCB的结构体数据类型,即任务控制块的数据结构OS_EXTOS_TCB*OSTCBCur;//声明一个指向任务控制块的全局指针变量//用于指向当前任务的任务控制块中断服务程序中添加的代码:if(OSIntNesting==1){OSTCBCur-OSTCBStkPtr=SP;//如果是第一层中断,则将被中断任务//的堆栈指针保存在被中断任务的任务//任务控制块中}关于uCOS-II的中断服务程序(ISR)中必须加“OSIntNesting==1”的原因==避免调整堆栈指针.出现这个问题的根源是当低优先级的任务被中断,当中断完成后由于有高优先级的任务就绪,则必须调度高优先级的任务,原来的低优先级任务继续被中断着,但是此时的低优先级任务的堆栈已经被破坏,已不能被调度程序直接调度了,要想被调度而必须调整堆栈指针。如下图所示的场景:问题分析:要想理解加上上面两句的原因,不妨假设有下面场景出现:voidMyTask(void){...}该任务在执行过程中被中断打断,下面是它的服务子程序voidMyISR(void){保存现场(PUSHA)OSIntEnter();//此时的堆栈指针是正确的,再往下就不对了,应该在此处保存用户任务堆栈指针OSIntExit();恢复现场(POPA)中断返回}OSIntExit(),大体如下:OSIntExit(){OS_ENTER_CRITICAL();if(OSIntNesting==0&&OSLockNesting==0){找到目前系统中就绪表中优先级最的任务如果不是当前任务,则调度它执行OSIntCtxSw();}OS_EXIT_CRITICAL();}综上所述,任务调用链如下:MyTask--MyISR--①OSIntExit--②OS_ENTER_CRITICAL();③OSIntCtxSw();④然而在实际的移植过程中,需要调整的指针偏移量是与编译器相关的,如果想要避免调整,显然一个简单的方法就是在调用OSIntExit之前先把堆栈指针保存下来,以后调度该用户任务时,直接从此恢复堆栈指针,而不再管实际的堆栈内容了(因为下面的内容相对于调度程序来说已经没有用处了)(三)voidOSIntExit(void)的理解OS_CPU.H中的宏定义:typedefunsignedshortOS_CPU_SR;//定义OS_CPU_SR为16位的CPU状态寄存器#ifOS_CRITICAL_METHOD==1#defineOS_ENTER_CRITICAL()asmCLI//OS_ENTER_CRITICAL()即为将处理器标志//寄存器的中断标志为清0,不允许中断#defineOS_EXIT_CRITICAL()asmSTI//OS_ENTER_CRITICAL()即为将处理器标志//寄存器的中断标志为置1,允许中断#endif//此一整段代码定义为开关中断的方式一#ifOS_CRITICAL_METHOD==2#defineOS_ENTER_CRITICAL()asm{PUSHF;CLI}//将当前任务的CPU的标志寄存器入//然后再将中断标志位清0#defineOS_EXIT_CRITICAL()asmPOPF//将先前压栈的标志寄存器的值出栈,恢复//到先前的状态,如果先前允许中断则现在//仍允许,先前不允许现在仍不允许#endif//此一整段代码定义为开关中断的方式二#ifOS_CRITICAL_METHOD==3#defineOS_ENTER_CRITICAL()(cpu_sr=OSCPUSaveSR())//保存CPU的状态寄存器到//变量cpu_sr中,cpu_sr//为OS_CPU_SR型变量#defineOS_EXIT_CRITICAL()(OSCPURestoreSR(cpu_sr))//从cpu_sr中恢复状态寄存//器#endif//此一整段代码定义为开关中断的方式三,//此段代码只是示意代码,OSCPUSaveSR()及//OSCPURestoreSR(cpu_sr)具体什么函数由//用户编译器所提供的函数决定.//以上宏定义非常重要,在使用不同处理器时要使用相应处理器的开关中断指令,在代码移//植时很有用uCOS_II.H中定义:OS_EXTINT8UOSLockNesting;//8位无符号全局整数,表示锁定嵌套计数器voidOSIntExit(void){#ifOS_CRITICAL_METHOD==3OS_CPU_SRcpu_sr;#endif//采用开关中断方式三if(OSRunning==TRUE)//如果内核正在运行,则进入if{OS_ENTER_CRITICAL();//进入临界段,关中断if(OSIntNesting0)//判断最外层中断任务是否已完成{OSIntNesting--;//由于此层中断任务已完成,中断嵌套计数器减//一}if((OSIntNesting==0)&&(OSLockNesting==0))//OSIntNesting==0表示程序的最外层中断任务以完成,OSLockNesting==0//表示是否存在任务锁定,整句代码的意思是如果全部中断处理完了且没有其他//任务锁定任务调度则执行下列任务调度代码{OSIntExitY=OSUnMapTbl[OSRdyGrp];//1OSPrioHighRdy=(INT8U)((OSIntExitY3)+OSUnMapTbl[OSRdyTbl[OSIntExitY]]);//2if(OSPrioHighRdy!=OSPrioCur)//3{OSTCBHighRdy=OSTCBPrioTbl[OSPrioHighRdy];OSCtxSwCtr++;OSIntCtxSw();}}OS_EXIT_CRITICAL();//开中断}}要理解1,2,3处的代码含义.首先要理解任务是如何调度的,所以先讲一下任务调度的核心算法:a.数据结构:1.就绪表:就绪表包含两个变量,他们分别是OSRdyGrp(在uCOS_II.H中为OS_EXTINT8UOSRdyGrp;即8位无符号整型的全局变量)和OSRdyTb1[](在uCOS_II.H中为OS_EXTINT8UOSRdyTbl[OS_RDY_TBL_SIZE];)先分析OS_EXTINT8UOSRdyTbl[OS_RDY_TBL_SIZE];是怎么回事#defineOS_LOWEST_PRIO12//在OS_CFG.H中这个宏定义了任务所能具有的最低优先级,那么此处共有从0到12共13个优先级,用户在代码移植时可以修改它,自定义所需要的优先级个数,但max(OS_LOWEST_PRIO)==63#defineOS_RDY_TBL_SIZE((OS_LOWEST_PRIO)/8+1)//在uCOS_II.中OS_RDY_TBL_SIZE用于确定数组OSRdyTbl[]的大小,如果OS_LOWEST_PRIO==63,则上述宏实际上为#defineOS_RDY_TBL_SIZE8,由于每个数组元素为8位,如果每一位表示一个优先级,则共有8*8=64个优先级现在回到就绪表,操作系统将优先级分为8组,优先级从0到7分为第一组,对应于OSRdyGrp的第0位,从8到15分为第二组,对应于OSRdyGrp的第1位,以此类推,64个优先级就有下面的对应关系(OSRdyTb1[]每组元素的每一位代表一个优先级):OSRdyTb1[0]--------------优先级从0到7--------------OSRdyGrp第0位OSRdyTb1[1]--------------优先级从8到15-------------OSRdyGrp第1位OSRdyTb1[2]--------------优先级从16到23-------------OSRdyGrp第2位OSRdyTb1[3]--------------优先级从24到31-------------OSRdyGrp第3位OSRdyTb1[4]--------------优先级从32到39-------------OSRdyGrp第4位OSRdyTb1[5]--------------优先级从40到47-------------OSRdyGrp第5位OSRdyTb1[6]--------------优先级从48到55-------------OSRdyGrp第6位OSRdyTb1[7]--------------优先级从55到63-------------OSRdyGrp第7位现在再做如下对应:当OSRdyTbl[0]中的任何一位是1时,OSRdyGrp的第0位置1,当OSRdyTbl[1]中的任何一位是1时,OSRdyGrp的第1位置1,当OSRdyTbl[2]中的任何一位是1时,OSRdyGrp的第2位置1,当OSRdyTbl[3]中的任何一位是1时,OSRdyGrp的第3位置1,当OSRdyTbl[4]中的任何一位是1时,OSRdy
本文标题:uCOSii中断处理过程详解(一)
链接地址:https://www.777doc.com/doc-4921105 .html