uCOSii中断处理过程详解(一)
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
一. UCOSII的中断过程简介
系统接收到中断请求后,如果CPU处于开中断状态,系统就会中止正在运行的当前任务,而按中断向量的指向去运行中断服务子程序,当中断服务子程序运行完成后,系统会根据具体情况返回到被中止的任务继续运行,或转向另一个中断优先级别更高的就绪任务。
由于UCOS II是可剥夺型的内核,所以中断服务程序结束后,系统会根据实际情况进行一次任务调度,如果有优先级更高的任务,就去执行优先级更高的任务,而不一定要返回被中断了的任务。
二.UCOSII的中断过程的示意图
三.具体中断过程
1.中断到来,如果被CPU识别,CPU将查中断向量表,根据中断向量表,获得中断服务子程序的入口地址。
2.将CPU寄存器的内容压入当前任务的任务堆栈中(依处理器的而定,也可能压入被压入被中断了的任务堆栈中。
3.通知操作系统将进入中断服务子程序。即:调用OSIntEnter()或OSIntNesting直接
加1。
4.If(OSIntNesting==1){OSTCBCur->OSTCBStrPtr=SP;} //如果是第一层中断,则将堆栈指针保存到被中断任务的任务控制块中
5.清中断源,否则在开中断后,这类中断将反复的打入,导致系统崩贵
6.执行用户ISR
7.中断服务完成后,调用OSIntExit().如果没有高优先级的任务被中断服务子程序激活而进入就绪态,那么就执行被中断了的任务,且只占用很短的时间.
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 TRUE
#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 < 255) //如果嵌套层数小于255,则可以继//续{
OSIntNesting++; //嵌套层数加1
}
}
}
(二)在中断服务子程序中加if ( OSIntNesting == 1){…}的原因
uCOS_II.H中定义:
typedef struct os_tcb {
OS_STK *OSTCBStkPtr;//声明指向任务堆栈栈顶的16位指针………………
} OS_TCB;//定义名为OS_TCB的结构体数据类型,即任务控制块的数据结构
OS_EXT OS_TCB *OSTCBCur;//声明一个指向任务控制块的全局指针变量
//用于指向当前任务的任务控制块
中断服务程序中添加的代码:
if ( OSIntNesting == 1)
{
OSTCBCur->OSTCBStkPtr = SP; // 如果是第一层中断,则将被中断任务
//的堆栈指针保存在被中断任务的任务
//任务控制块
中
}
关于uCOS-II的中断服务程序(ISR)中必须加“OSIntNesting == 1”的原因==避免调整堆栈指针.
出现这个问题的根源是当低优先级的任务被中断,当中断完成后由于有高优先级的任务就绪,则必须调度高优先级的任务,原来的低优先级任务继续被中断着,但是此时的低优先级任务的堆栈已经被破坏,已不能被调度程序直接调度了,要想被调度而必须调整堆栈指针。如下图所示的场景:
问题分析:
要想理解加上上面两句的原因,不妨假设有下面场景出现:
void MyTask(void)
{
...
}
该任务在执行过程中被中断打断,下面是它的服务子程序
void MyISR(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(); ④