uCOSii中断处理过程详解Word下载.docx
- 文档编号:16569416
- 上传时间:2022-11-24
- 格式:DOCX
- 页数:14
- 大小:208.07KB
uCOSii中断处理过程详解Word下载.docx
《uCOSii中断处理过程详解Word下载.docx》由会员分享,可在线阅读,更多相关《uCOSii中断处理过程详解Word下载.docx(14页珍藏版)》请在冰豆网上搜索。
typedefunsignedintOS_STK;
//堆栈入口宽度为16位
(一)void
OSIntEnter(void)的理解
uCOS_II.H中定义:
#ifdef
OS_GLOBALS
#define
OS_EXT
#else
OS_EXT
extern
#endif
//定义全局宏OS_EXT
#ifndef
TRUE
TRUE
1
#endif
OS_EXT
BOOLEAN
OSRunning;
//定义外部BOOLEAN类型全局变量,用来指示
//核是否在运行
INT8U
OSIntNesting;
//定义外部8位无符号整型数全局变量,用来表
//示中断嵌套层数
OS_CORE.C中的OSIntEnter()函数原型:
void
OSIntEnter(void)
{
if(OSRunning==TRUE)//如果内核正在运行则进入if
if(OSIntNesting<
255)//如果嵌套层数小于255,则可以继//续
OSIntNesting++;
//嵌套层数加1
}
(二)在中断服务子程序中加if(OSIntNesting==1){…}的原因
typedefstructos_tcb{
OS_STK
*OSTCBStkPtr;
//声明指向任务堆栈栈顶的16位指针
………………
}OS_TCB;
//定义名为OS_TCB的结构体数据类型,即任务控制块的数据结构
OS_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-->
②
③
④
然而在实际的移植过程中,需要调整的指针偏移量是与编译器相关的,如果想要避免调整,显然一个简单的方法就是在调用OSIntExit之前先把堆栈指针保存下来,以后调度该用户任务时,直接从此恢复堆栈指针,而不再管实际的堆栈内容了(因为下面的内容相对于调度程序来说已经没有用处了)
(三)voidOSIntExit(void)的理解
OS_CPU.H中的宏定义:
typedefunsignedshortOS_CPU_SR;
//定义OS_CPU_SR为16位的CPU状态寄存器
#if
OS_CRITICAL_METHOD==1
#define
OS_ENTER_CRITICAL()
asm
CLI//OS_ENTER_CRITICAL()即为将处理器标志
//寄存器的中断标志为清0,不允许中断
OS_EXIT_CRITICAL()
STI//OS_ENTER_CRITICAL()即为将处理器标志
//寄存器的中断标志为置1,允许中断
//此一整段代码定义为开关中断的方式一
#if
OS_CRITICAL_METHOD==2
asm{PUSHF;
CLI}//将当前任务的CPU的标志寄存器入
//然后再将中断标志位清0
POPF
//将先前压栈的标志寄存器的值出栈,恢复
//到先前的状态,如果先前允许中断则现在
//仍允许,先前不允许现在仍不允许
//此一整段代码定义为开关中断的方式二
OS_CRITICAL_METHOD==3
(cpu_sr=OSCPUSaveSR())//保存CPU的状态寄存器到
//变量cpu_sr中,cpu_sr
//为OS_CPU_SR型变量
(OSCPURestoreSR(cpu_sr))//从cpu_sr中恢复状态寄存
//器
//此一整段代码定义为开关中断的方式三,
//此段代码只是示意代码,OSCPUSaveSR()及
//OSCPURestoreSR(cpu_sr)具体什么函数由
//用户编译器所提供的函数决定.
//以上宏定义非常重要,在使用不同处理器时要使用相应处理器的开关中断指令,在代码移//植时很有用
OSLockNesting;
//8位无符号全局整数,表示锁定嵌套计数器
OSIntExit(void)
#ifOS_CRITICAL_METHOD==3
OS_CPU_SR
cpu_sr;
//采用开关中断方式三
if(OSRunning==TRUE)//如果内核正在运行,则进入if
OS_ENTER_CRITICAL();
//进入临界段,关中断
if(OSIntNesting>
0)//判断最外层中断任务是否已完成
OSIntNesting--;
//由于此层中断任务已完成,中断嵌套计数器减//一
if((OSIntNesting==0)&
(OSLockNesting==0))
//OSIntNesting==0表示程序的最外层中断任务以完成,OSLockNesting==0
//表示是否存在任务锁定,整句代码的意思是如果全部中断处理完了且没有其他
//任务锁定任务调度则执行下列任务调度代码
OSIntExitY
=OSUnMapTbl[OSRdyGrp];
//1
OSPrioHighRdy=(INT8U)((OSIntExitY<
<
3)+OSUnMapTbl[OSRdyTbl[OSIntExitY]]);
//2
if(OSPrioHighRdy!
=OSPrioCur)
//3
OSTCBHighRdy
=OSTCBPrioTbl[OSPrioHighRdy];
OSCtxSwCtr++;
OSIntCtxSw();
OS_EXIT_CRITICAL();
//开中断
要理解1,2,3处的代码含义.首先要理解任务是如何调度的,所以先讲一下任务调度的核心算法:
a.数据结构:
1.就绪表:
就绪表包含两个变量,他们分别是OSRdyGrp(在uCOS_II.H中为OS_EXT
OSRdyGrp;
即8位无符号整型的全局变量)和OSRdyTb1[](在uCOS_II.H中为OS_EXT
OSRdyTbl[OS_RDY_TBL_SIZE];
)
先分析OS_EXTINT8U
OSRdyTbl[OS_RDY_TBL_SIZE];
是怎么回事
#defineOS_LOWEST_PRIO
12//在OS_CFG.H中
这个宏定义了任务所能具有的最低优先级,那么此处共有从0到12共13个优先级,用户在代码移植时可以修改它,自定义所需要的优先级个数,但max(OS_LOWEST_PRIO)==63
OS_RDY_TBL_SIZE
((OS_LOWEST_PRIO)/8+1)//在uCOS_II.中
OS_RDY_TBL_SIZE用于确定数组OSRdyTbl[]的大小,如果OS_LOWEST_PRIO==63,则上述宏实际上为#define
8,由于每个数组元素为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时,OSRdyGrp的第4位置1,
当OSRdyTbl[5]中的任何一位是1时,OSRdyGrp的第5位置1,
当OSRdyTbl[6]中的任何一位是1时,OSRdyGrp的第6位置1,
当OSRdyTbl[7]中的任何一位是1时,OSRdyGrp的第7位置1,
如果置1表示有任务进入就绪态,那么上面的表可以理解为:
OSRdyGrp的第N位(0<
=N<
=7)为1,那么在OSRdyTb1[N]中至少有一位是1,也就是说在OSRdyTb1[N]对应的任务中至少有一个任务处于就绪态
该表在OS_CORE.C中定义如下:
INT8U
const
OSMapTbl[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
//8位无符号整型常量数组
3.表(数组)OSUnMapTb1[]:
用于求出一个8位整型数最低位为1的位置
该数组在OS_CORE.C中定义如下:
OSUnMapTbl[]={
0,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
/*0x00to0x0F*/
4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
/*0x10to0x1F*/
5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
/*0x20to0x2F*/
/*0x30to0x3F*/
6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
/*0x40to0x4F*/
/*0x50to0x5F*/
/*0x60to0x6F*/
/*0x70to0x7F*/
7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
/*0x80to0x8F*/
/*0x90to0x9F*/
/*0xA0to0xAF*/
/*0xB0to0xBF*/
/*0xC0to0xCF*/
/*0xD0to0xDF*/
/*0xE0to0xEF*/
4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
/*0xF0to0xFF*/
};
理解:
我把问题转化为:
“一个无符号的8位整数,如何确定最低位为1的位的位置?
”
即对于任意一个8位整型数,比如4,考虑它的二进制位中所有为1的位,确定最低位为1的位置(相对第0位的偏移),一般来讲首先想到的方法是移位的方法.如:
pos=0;
//pos用于统计相对于第0位的偏移
while(!
(num&
0x01))//与00000001按位于,如果最低位为1,退出循环,即找到最低位//为1的位
num=num>
>
1;
//将二进制数右移一位
pos++;
//进行一次移位,则pos加一
最后得到的pos就是所有位中为1的最低位的偏移量,但这样计算需要时间,尽管最多右移7次。
为了节省时间,使用的方法是“空间换时间”的办法,即把8位无符号数,所有可能的情况的都列了出来,共有256个数字,把每个数字的最低为1位的位置都预先计算好。
比如4对应二进制数为100,
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- uCOSii 中断 处理 过程 详解