1、一. UCOSII 的中断过程简介 系统接收到中断请求后,如果 CPU 处于开中断状态,系统就会中止正在运行的当前任务,而按中断向量的指向去运行中断服务子程序,当中断服务子程序运行完成后,系统会根据具体情况返回到被中止的任务继续运行,或转向另一个中断优先级别更高的就绪任务。 由于 UCOS II 是可剥夺型的内核,所以中断服务程序结束后,系统会根据实际情况进行一次任务调度,如果有优先级更高的任务,就去执行优先级更高的任务,而不一定要返回被中断了的任务。 二UCOSII 的中断过程的示意图 三具体中断过程 1中断到来,如果被 CPU 识别,CPU 将查中断向量表,根据中断向量表,获得中断服务子程
2、序的入口地址。 2将 CPU 寄存器的内容压入当前任务的任务堆栈中(依处理器的而定,也可能压入被压入被中断了的任务堆栈中。 3通知操作系统将进入中断服务子程序。即:调用 OSIntEnter()或 OSIntNesting 直接 加 1。 4If(OSIntNesting=1) OSTCBCur-OSTCBStrPtr=SP; /如果是第一层中断,则将堆栈指针保存到被中断任务的任务控制块中 5清中断源,否则在开中断后, 这类中断将反复的打入,导致系统崩贵 6执行用户 ISR 7中断服务完成后, 调用 OSIntExit()如果没有高优先级的任务被中断服务子程序激活而进入就绪态,那么就执行被中断
3、了的任务 ,且只占用很短的时间 8恢复所有 CPU 寄存器的值 9执行中断返回指令 四相关代码 与编译器相关的数据类型: typedef unsigned char BOOLEAN; typedef unsigned char INT8U; typedef unsigned int OS_STK; /堆栈入口宽度为 16 位 (一) void OSIntEnter (void)的理解 uCOS_II.H 中定义: #ifdef OS_GLOBALS #define OS_EXT #else #define OS_EXT extern #endif /定义全局宏 OS_EXT #ifndef T
4、RUE #define TRUE 1 #endif OS_EXT BOOLEAN OSRunning; /定义外部 BOOLEAN 类型全局变量,用来指示 /核是否在运行 OS_EXT INT8U OSIntNesting;/定义外部 8 位无符号整型数全局变量 ,用来表 /示中断嵌套层数 OS_CORE.C 中的 OSIntEnter()函数原型: void OSIntEnter (void) if (OSRunning = TRUE) /如果内核正在运行则进入 if if (OSIntNesting OSTCBStkPtr = SP; / 如果是第一层中断, 则将被中断任务 /的堆栈指针保
5、存在被中断任务的任务 /任务控制块中 关于 uCOS-II 的中断服务程序( ISR)中必须加“OSIntNesting = 1”的原因 =避免调整堆栈指针.出现这个问题的根源是当低优先级的任务被中断,当中断完成后由于有高优先级的任务就绪,则必须调度高优先级的任务,原来的低优先级任务继续被中断着,但是此时的低优先级任务的堆栈已经被破坏,已不能被调度程序直接调度了,要想被调度而必须调整堆栈指针。如下图所示的场景: 问题分析:要想理解加上上面两句的原因,不妨假设有下面场景出现:void MyTask(void).该任务在执行过程中被中断打断,下面是它的服务子程序 void MyISR(void)保
6、存现场(PUSHA)OSIntEnter();/ 此时的堆栈指针是正确的,再往下就不对了,应该在此处保存用户任务堆栈指针OSIntExit(); 恢复现场(POPA)中断返回 OSIntExit(),大体如下:OSIntExit()OS_ENTER_CRITICAL();if( OSIntNesting=0 OS_EXIT_CRITICAL(); 综上所述,任务调用链如下:MyTask MyISR OSIntExit OS_ENTER_CRITICAL(); OSIntCtxSw(); 然而在实际的移植过程中,需要调整的指针偏移量是与编译器相关的,如果想要避免调整,显然一个简单的方法就是在调用
7、 OSIntExit 之前先把堆栈指针保存下来,以后调度该用户任务时,直接从此恢复堆栈指针,而不再管实际的堆栈内容了(因为下面的内容相对于调度程序来说已经没有用处了) (三) void OSIntExit (void)的理解 OS_CPU.H 中的宏定义: typedef unsigned short OS_CPU_SR; /定义 OS_CPU_SR 为 16 位的 CPU 状态寄存器 #if OS_CRITICAL_METHOD = 1 #define OS_ENTER_CRITICAL() asm CLI / OS_ENTER_CRITICAL()即为将处理器标志 /寄存器的中断标志为清
8、0,不允许中断 #define OS_EXIT_CRITICAL() asm STI / OS_ENTER_CRITICAL()即为将处理器标志 /寄存器的中断标志为置 1,允许中断 #endif /此一整段代码定义为开关中断的方式一 #if OS_CRITICAL_METHOD = 2 #define OS_ENTER_CRITICAL() asm PUSHF; CLI /将当前任务的 CPU 的标志寄存器入 /然后再将中断标志位清 0 #define OS_EXIT_CRITICAL() asm POPF /将先前压栈的标志寄存器的值出栈 ,恢复 /到先前的状态 ,如果先前允许中断则现在 /仍允许,先前不允许现在仍不允许 #endif /此一整段代码定义为开关中断的方式二 #if OS_CRITICAL_METHOD = 3 #define OS_ENTER_CRITICAL() (cpu_sr = OSCPUSaveSR() /保存 CPU 的状态寄存器到 /变量 cpu_sr 中,cpu_sr