uCOSii中断处理过程详解(一)

合集下载

第3章 μCOS-II的中断和时钟

第3章 μCOS-II的中断和时钟

cpu_sr = get_processor_psw();
disable_interrupts(); /* 处理临界代码*/ set_processor_psw(cpu_sr);
}
3.2 uC/OS-II的时钟
• 任何操作系统都要提供一个周期性的信号源,以供系统处理诸如 延时、超时等与时间有关的事件,这个周期性的信号源叫做时钟。 • 与大多数计算机系统一样,用硬件定时器产生一个周期为毫秒级 的周期性中断来实现系统时钟。最小的时钟单位就是两次中断之 间间隔的时间,这个最小时钟单位叫做时钟节拍。 • 硬件定时器以时钟节拍为周期定时的产生中断,该中断的中断服 务程序叫做OSTickISR(),中断服务程序通过调用函数 OSTimeTick()来完成系统在每个时钟节拍时需要做的工作。
为记录中断嵌套的层数 , μ C/OS-II内核定义 了一个全局变量 OSIntNesting。
NO
}
OSIntNesting++; } }
NO
任务是被中断的任务?
返回中断服务程序
if(OSIntNesting > 0){
NO 获得任务TCB的指针
OSIntNesting--;
执行中断级任务切换
这个函数在中断嵌套层数 计数器为0、调度器未被锁 定且从任务就绪表中查找 到的最高级就绪任务又不 是被中断的任务的条件下 将要进行任务切换,否则 就返回被中断的任务程序
C/OS节拍率最好选在10→100次/秒。 必须在多任务系统启动OSStart()以后,再开启时钟节拍器。

13
3.2.1 时钟节拍中断服务子程序
程序清单 : 时钟节拍中断服务子程序的示意代码
void OSTickISR(void) { 保存CPU寄存器; 调用OSIntEnter(); if(OSIntNesting == 1) { OSTCBCur -> OSTCBStkPtr = SP; } 调用OSTimeTick(); 清除中断; 开中断; 调用OSIntExit(); 恢复CPU寄存器; 执行中断返回指令; } // 记录中断嵌套层数

uCOS中断处理过程详解

uCOS中断处理过程详解

再看3处代码:在uCOS_II.H中有如下定义:OS_EXT OS_TCB *OSTCBPrioTbl[OS_LOWEST_PRIO + 1];//定义指向任务控制块的指针数//组,且每个优先级在同一时刻只对应一个任务OS_EXT INT8U OSPrioCur;//用于保存目前任务的优先级OS_EXT INT32U OSCtxSwCtr;//32位无符号全局整型变量,作为任务切换计数器OS_EXT OS_TCB *OSTCBHighRdy;//指向最高优先级任务任务控制块的指针if (OSPrioHighRdy != OSPrioCur)//就绪态任务中的最高优先级已不是目前任务的优先级,则进行中断级的任务//切换{OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];//将最高优先级任务控制块指针指向当前优先级最高的任务的任务控制块OSCtxSwCtr++;//任务切换计数器加1OSIntCtxSw();//调用中断级任务切换函数}此段代码体现出了可剥夺型实时操作系统内核的特点.OSIntCtxSw()在80x86上的移植代码,此代码在OS_CPU_A.ASM中,代码如下:_OSIntCtxSw PROC FAR;CALL FAR PTR _OSTaskSwHook ; 调用OSTaskSwHook()函数,此函数在;OS_CPU_C.C中只是个空函数,留给用户;在代码移植时自定义;MOV AX, SEG _OSTCBCur ;由于发生了段转移,恢复刚才(当前任务)数MOV DS, AX;据段;MOV AX, WORD PTR DS:_OSTCBHighRdy+2 ;AH=_OSTCBHighRdy+3;AL=_OSTCBHighRdy+2MOV DX, WORD PTR DS:_OSTCBHighRdy ;DH=_OSTCBHighRdy+1;DL=_OSTCBHighRdyMOV WORD PTR DS:_OSTCBCur+2, AX ;_OSTCBCur+3=AH;_OSTCBCur+2=ALMOV WORD PTR DS:_OSTCBCur, DX ;_OSTCBCur+1=DH;_OSTCBCur=DL;OSTCBCur=OSTCBHighRdyMOV AL, BYTE PTR DS:_OSPrioHighRdy ;MOV BYTE PTR DS:_OSPrioCur, AL;OSPrioCur= OSPrioHighRdy ;LES BX, DWORD PTR DS:_OSTCBHighRdy ;取址指令MOV SS, ES:[BX+2] ;MOV SP, ES:[BX] ;;SS:SP=OSTCBHighRdy->OSTCBStkPtrPOP DS ;DS出栈POP ES ;ES出栈POPA ;CPU其余寄存器出栈;IRET ; 中断返回;_OSIntCtxSw ENDP以上汇编代码在移植时根据处理器不同要作修改四.在ISR中通知任务做事的理解(以OSSemPost()为例)在理解OSSemPost(),先要理解事件,如下是事件的数据结构:typedef struct {INT8U OSEventType;//事件类型,这里是OS_EVENT_TYPE_SEM即信号量INT8U OSEventGrp; //等待任务所在的组INT16U OSEventCnt; //当事件是信号量时,使用此计数器void *OSEventPtr; //信号量时不使用INT8U OSEventTbl[OS_EVENT_TBL_SIZE];//等待任务列表} OS_EVENT;其中OSEventGrp与OSEventTbl[]构成等待事件的任务列表,前面所讲的OSRdyGrp与OSRdyTbl[]具有同样的功能,划分也一模一样.在ISR中调用函数OSSemPost(),给任务发信息,此函数在OS_SEM.C中:INT8U OSSemPost (OS_EVENT *pevent){#if OS_CRITICAL_METHOD == 3OS_CPU_SR cpu_sr;#endif //定义开关中断类型#if OS_ARG_CHK_EN > 0//如果启用了函数参数检查功能则进行参数检查if (pevent == (OS_EVENT *)0) {return (OS_ERR_PEVENT_NULL);//检查是否有事件发生,如果没有则报错}if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {return (OS_ERR_EVENT_TYPE);//检查当前事件是不是信号量,不是则出错}#endifOS_ENTER_CRITICAL();//关中断if (pevent->OSEventGrp != 0x00) { //如果等待事件发生的任务列表不为空,//即有任务处于等待状态,则进入if OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM);//使对应事件的任务从等待变为就绪OS_EXIT_CRITICAL();//开中断OS_Sched(); //进行任务调度return (OS_NO_ERR);}if (pevent->OSEventCnt < 65535) { //如果等待事件发生的任务列表为空,且信号量计数//器的值小于65535,则信号量计数器加1,否则不执//行if,而报信号量益出pevent->OSEventCnt++;OS_EXIT_CRITICAL();return (OS_NO_ERR);}OS_EXIT_CRITICAL();return (OS_SEM_OVF);}附:uCOS_II 大致的启动过程:main(){......OSInit();......OSTaskCreate();//此函数在OS_TASK.C中,用于创建任务,调用了三个重要的系统函数//它们是OSTaskInit();OS_TCBInit();OS_Sched();......OSStart();}OSTaskCreate()//此函数只能在main()及任务中调用,中断服务子程序不能调用{......OSTaskStkInit();//此函数在OS_CPU_C.C中,用于创建任务堆栈,在移植过程中可根据//具体情况做修改OS_TCBInit();//此函数在OS_CORE.C中,用于初始化任务控制块,及就绪表......OS_Sched()();//此函数在OS_CORE.C中,是任务级调度函数,作用是获得最高优先级任务......//并进行调度,此函数包含一个重要函数OS_TASK_SW()}OSStart(){......If(没有任务启动){ 获取最高优先级任务OSStartHighRdy();//此函数在OS_CPU_A.ASM中,用于启动任务,在移植过程中随处理器//不同要作修改}}OS_TASK_SW()//在OS_CPU.H中它是一个宏定义,用于产生任务切换的中断,移植中要作修改#define uCOS 0x80#define OS_TASK_SW() asm INT uCOS为什么在OSTaskCreate()中调用OS_Sched()后还要调用OSStart()来启用任务呢?事实上在从main()中创建的任务是不执行OS_Sched()函数的,因为此时的任务并未启动,OSRunning的值为0。

Ucos-II基础原理讲解,任务创建及中断问题

Ucos-II基础原理讲解,任务创建及中断问题

Ucos-II基础原理讲解,任务创建及中断问题2013-6-26 周三Haibara AI Ucos-II在移植过程中的特性,首先要理解所加入的实时操作系统是一个给予定时器节拍的系统。

怎么理解这个问题呢,由该定时器产生脉冲来驱动不同的任务调度,且由于该系统是基于可剥夺内核类型,任务之间的切换时间间隔也由该定时器完成。

不宜过大,否则会造成CPU利用率不高,不宜过小,否则会造成CPU在执行任务时非常被动,时间特别赶。

就想人的心脏一样,动力是固定的,你非要去跑个100公里,心脏不加速你是会窒息而死的。

我们正常心脏跳动是60次左右,同样,单片机也需要一个这样的相对宽松的节拍驱动。

注:众所周知,脉冲本质上仍由晶振提供(或实时时钟),原理都一样,再次请各位不要较真,就暂时以晶振为例。

大家可以考虑一下,晶振的作用是否特别类似于人体的心脏呢?答案是很显然的。

心脏跳动给人体提供输送血液和养料的压力,晶振的设计原理也正是源于此。

他可以像人体心脏一样提供动力输送各个外设(相当于人体器官)所需要的能量。

说这么多,就是要大家理解,人可以实时做出反应,因为人是有生命的,也就是他有反应、判断和处理能力,可以决定什么时间应该做什么。

但是单片机是没有生命的,换句话说,他所谓的处理能力源于人们的代码和程序。

那么,怎么让单片机像人一样拥有生命呢?答案很简单,给他指令,帮助他决定什么时间该做什么,这也就是所谓的实时操作系统。

不只是ucos,其他实时操作系统也是这个道理。

下面我以代码为例,讲述一下ucos的工作流程,如有错误,还请各位前辈指点。

首先任务是怎么样开始执行的?os_err = OSTaskCreateExt((void (*)(void *)) App_TaskStart, */1 (void * ) 0, 2(OS_STK * )&App_TaskStartStk[APP_TASK_START_STK_SIZE - 1],3(INT8U ) APP_TASK_START_PRIO,4(INT16U ) APP_TASK_START_PRIO,5(OS_STK * )&App_TaskStartStk[0],6(INT32U ) APP_TASK_START_STK_SIZE,7(void * )0,8(INT16U )(OS_TASK_OPT_STK_CLR | OS_TASK_OPT_STK_CHK));9这个东西好像是非常复杂,但是实际上并不需要细究(当然非要细究也是允许的,只不过是C语言而已,看也不是看不懂,对于初学者而言并不推荐而已)。

uCOSii中断处理过程详解(一)

uCOSii中断处理过程详解(一)

一. UCOSII的中断过程简介系统接收到中断请求后,如果CPU处于开中断状态,系统就会中止正在运行的当前任务,而按中断向量的指向去运行中断服务子程序,当中断服务子程序运行完成后,系统会根据具体情况返回到被中止的任务继续运行,或转向另一个中断优先级别更高的就绪任务。

由于UCOS II是可剥夺型的内核,所以中断服务程序结束后,系统会根据实际情况进行一次任务调度,如果有优先级更高的任务,就去执行优先级更高的任务,而不一定要返回被中断了的任务。

二.UCOSII的中断过程的示意图三.具体中断过程1.中断到来,如果被CPU识别,CPU将查中断向量表,根据中断向量表,获得中断服务子程序的入口地址。

2.将CPU寄存器的内容压入当前任务的任务堆栈中(依处理器的而定,也可能压入被压入被中断了的任务堆栈中。

3.通知操作系统将进入中断服务子程序。

即:调用OSIntEnter()或OSIntNesting直接加1。

4.If(OSIntNesting==1){OSTCBCur->OSTCBStrPtr=SP;} //如果是第一层中断,则将堆栈指针保存到被中断任务的任务控制块中5.清中断源,否则在开中断后,这类中断将反复的打入,导致系统崩贵6.执行用户ISR7.中断服务完成后,调用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#endifOS_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”的原因==避免调整堆栈指针.出现这个问题的根源是当低优先级的任务被中断,当中断完成后由于有高优先级的任务就绪,则必须调度高优先级的任务,原来的低优先级任务继续被中断着,但是此时的低优先级任务的堆栈已经被破坏,已不能被调度程序直接调度了,要想被调度而必须调整堆栈指针。

uCOSii中断处理过程详解

uCOSii中断处理过程详解

一. UCOSII的中断过程简介系统接收到中断请求后,如果CPU处于开中断状态,系统就会中止正在运行的当前任务,而按中断向量的指向去运行中断服务子程序,当中断服务子程序运行完成后,系统会根据具体情况返回到被中止的任务继续运行,或转向另一个中断优先级别更高的就绪任务。

由于UCOS II是可剥夺型的内核,所以中断服务程序结束后,系统会根据实际情况进行一次任务调度,如果有优先级更高的任务,就去执行优先级更高的任务,而不一定要返回被中断了的任务。

二.UCOSII的中断过程的示意图三.具体中断过程1.中断到来,如果被CPU识别,CPU将查中断向量表,根据中断向量表,获得中断服务子程序的入口地址。

2.将CPU寄存器的内容压入当前任务的任务堆栈中(依处理器的而定,也可能压入被压入被中断了的任务堆栈中。

3.通知操作系统将进入中断服务子程序。

即:调用OSIntEnter()或OSIntNesting直接加1。

4.If(OSIntNesting==1){OSTCBCur->OSTCBStrPtr=SP;} //如果是第一层中断,则将堆栈指针保存到被中断任务的任务控制块中5.清中断源,否则在开中断后,这类中断将反复的打入,导致系统崩贵6.执行用户ISR7.中断服务完成后,调用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#endifOS_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”的原因==避免调整堆栈指针.出现这个问题的根源是当低优先级的任务被中断,当中断完成后由于有高优先级的任务就绪,则必须调度高优先级的任务,原来的低优先级任务继续被中断着,但是此时的低优先级任务的堆栈已经被破坏,已不能被调度程序直接调度了,要想被调度而必须调整堆栈指针。

uCOS中断处理过程详解

uCOS中断处理过程详解

再看3处代码:在uCOS_II.H中有如下定义:OS_EXT OS_TCB *OSTCBPrioTbl[OS_LOWEST_PRIO + 1];//定义指向任务控制块的指针数//组,且每个优先级在同一时刻只对应一个任务OS_EXT INT8U OSPrioCur;//用于保存目前任务的优先级OS_EXT INT32U OSCtxSwCtr;//32位无符号全局整型变量,作为任务切换计数器OS_EXT OS_TCB *OSTCBHighRdy;//指向最高优先级任务任务控制块的指针if (OSPrioHighRdy != OSPrioCur)//就绪态任务中的最高优先级已不是目前任务的优先级,则进行中断级的任务//切换{OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];//将最高优先级任务控制块指针指向当前优先级最高的任务的任务控制块OSCtxSwCtr++;//任务切换计数器加1OSIntCtxSw();//调用中断级任务切换函数}此段代码体现出了可剥夺型实时操作系统内核的特点.OSIntCtxSw()在80x86上的移植代码,此代码在OS_CPU_A.ASM中,代码如下:_OSIntCtxSw PROC FAR;CALL FAR PTR _OSTaskSwHook ; 调用OSTaskSwHook()函数,此函数在;OS_CPU_C.C中只是个空函数,留给用户;在代码移植时自定义;MOV AX, SEG _OSTCBCur ;由于发生了段转移,恢复刚才(当前任务)数MOV DS, AX;据段;MOV AX, WORD PTR DS:_OSTCBHighRdy+2 ;AH=_OSTCBHighRdy+3;AL=_OSTCBHighRdy+2MOV DX, WORD PTR DS:_OSTCBHighRdy ;DH=_OSTCBHighRdy+1;DL=_OSTCBHighRdyMOV WORD PTR DS:_OSTCBCur+2, AX ;_OSTCBCur+3=AH;_OSTCBCur+2=ALMOV WORD PTR DS:_OSTCBCur, DX ;_OSTCBCur+1=DH;_OSTCBCur=DL;OSTCBCur=OSTCBHighRdyMOV AL, BYTE PTR DS:_OSPrioHighRdy ;MOV BYTE PTR DS:_OSPrioCur, AL;OSPrioCur= OSPrioHighRdy ;LES BX, DWORD PTR DS:_OSTCBHighRdy ;取址指令MOV SS, ES:[BX+2] ;MOV SP, ES:[BX] ;;SS:SP=OSTCBHighRdy->OSTCBStkPtrPOP DS ;DS出栈POP ES ;ES出栈POPA ;CPU其余寄存器出栈;IRET ; 中断返回;_OSIntCtxSw ENDP以上汇编代码在移植时根据处理器不同要作修改四.在ISR中通知任务做事的理解(以OSSemPost()为例)在理解OSSemPost(),先要理解事件,如下是事件的数据结构:typedef struct {INT8U OSEventType;//事件类型,这里是OS_EVENT_TYPE_SEM即信号量INT8U OSEventGrp; //等待任务所在的组INT16U OSEventCnt; //当事件是信号量时,使用此计数器void *OSEventPtr; //信号量时不使用INT8U OSEventTbl[OS_EVENT_TBL_SIZE];//等待任务列表} OS_EVENT;其中OSEventGrp与OSEventTbl[]构成等待事件的任务列表,前面所讲的OSRdyGrp与OSRdyTbl[]具有同样的功能,划分也一模一样.在ISR中调用函数OSSemPost(),给任务发信息,此函数在OS_SEM.C中:INT8U OSSemPost (OS_EVENT *pevent){#if OS_CRITICAL_METHOD == 3OS_CPU_SR cpu_sr;#endif //定义开关中断类型#if OS_ARG_CHK_EN > 0//如果启用了函数参数检查功能则进行参数检查if (pevent == (OS_EVENT *)0) {return (OS_ERR_PEVENT_NULL);//检查是否有事件发生,如果没有则报错}if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {return (OS_ERR_EVENT_TYPE);//检查当前事件是不是信号量,不是则出错}#endifOS_ENTER_CRITICAL();//关中断if (pevent->OSEventGrp != 0x00) { //如果等待事件发生的任务列表不为空,//即有任务处于等待状态,则进入if OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM);//使对应事件的任务从等待变为就绪OS_EXIT_CRITICAL();//开中断OS_Sched(); //进行任务调度return (OS_NO_ERR);}if (pevent->OSEventCnt < 65535) { //如果等待事件发生的任务列表为空,且信号量计数//器的值小于65535,则信号量计数器加1,否则不执//行if,而报信号量益出pevent->OSEventCnt++;OS_EXIT_CRITICAL();return (OS_NO_ERR);}OS_EXIT_CRITICAL();return (OS_SEM_OVF);}附:uCOS_II 大致的启动过程:main(){......OSInit();......OSTaskCreate();//此函数在OS_TASK.C中,用于创建任务,调用了三个重要的系统函数//它们是OSTaskInit();OS_TCBInit();OS_Sched();......OSStart();}OSTaskCreate()//此函数只能在main()及任务中调用,中断服务子程序不能调用{......OSTaskStkInit();//此函数在OS_CPU_C.C中,用于创建任务堆栈,在移植过程中可根据//具体情况做修改OS_TCBInit();//此函数在OS_CORE.C中,用于初始化任务控制块,及就绪表......OS_Sched()();//此函数在OS_CORE.C中,是任务级调度函数,作用是获得最高优先级任务......//并进行调度,此函数包含一个重要函数OS_TASK_SW()}OSStart(){......If(没有任务启动){ 获取最高优先级任务OSStartHighRdy();//此函数在OS_CPU_A.ASM中,用于启动任务,在移植过程中随处理器//不同要作修改}}OS_TASK_SW()//在OS_CPU.H中它是一个宏定义,用于产生任务切换的中断,移植中要作修改#define uCOS 0x80#define OS_TASK_SW() asm INT uCOS为什么在OSTaskCreate()中调用OS_Sched()后还要调用OSStart()来启用任务呢?事实上在从main()中创建的任务是不执行OS_Sched()函数的,因为此时的任务并未启动,OSRunning的值为0。

描述ucos中中断实现过程

描述ucos中中断实现过程

描述ucos中中断实现过程UCOS中的中断实现过程在嵌入式系统中,中断是一种常见的机制,用于处理紧急事件和响应外部设备的请求。

中断可以打破程序的正常顺序执行,将处理器的控制权转移到一个特殊的处理函数,在完成相关任务后再返回到被中断的位置。

在本文中,我们将详细讨论UCOS中中断的实现过程,从中断的触发到处理函数的执行,以及恢复正常程序执行的过程。

一、中断的概念和分类在开始讨论UCOS中的中断实现过程之前,我们先了解一下中断的概念和分类。

中断是指在程序正常执行的过程中,由于硬件或软件的触发,使处理器暂时停下目前正在执行的任务,转而去执行一个特定的中断服务程序。

中断可以分为外部中断和内部中断两种类型。

1. 外部中断:外部中断是由外部设备触发的,如按键的按下、定时器的溢出等。

外部中断需要通过硬件电路来检测和触发,然后通过中断控制器将中断请求信号发送给处理器。

2. 内部中断:内部中断是由处理器内部的异常或错误触发的,如除零错误、非法指令执行等。

内部中断是由处理器内部的各种异常检测电路自动触发的。

UCOS中的中断实现过程主要是针对外部中断的,它涉及到如何检测和响应外部中断请求,并且在中断处理函数执行完成后,恢复正常的程序执行顺序。

二、UCOS中的中断处理器UCOS中的中断处理器是使用硬件中断控制器来检测和响应外部中断请求的。

硬件中断控制器的作用是将外部中断请求信号转换为中断向量,并将处理器的控制权转移到对应的中断处理函数。

UCOS可以使用多种硬件中断控制器,如8259A芯片、PIC芯片、ARM 内核自带的中断控制器等。

具体使用哪种硬件中断控制器,取决于嵌入式系统的硬件架构和具体需求。

实现中断处理的第一步是配置硬件中断控制器,使其能够正确检测和响应外部中断请求。

相关配置包括中断优先级设置、中断请求触发方式、中断控制器的初始化等。

三、UCOS中的中断向量表中断向量表是用来存放中断处理函数地址的数据结构,每个中断向量表项对应一个外部中断请求。

第4章uCOSII的时钟和中断

第4章uCOSII的时钟和中断
函数作用就是把全局变量 OSIntNesting加1,从而用它来 记录中断嵌套的层数
(2)退出中断服务函数
入口 中断嵌套层数=0? No
Yes
调度器未被锁 Yes 获得最高优先级别就绪任务的prio 任务是被中断的任务 No 获得任务TCB的指针 执行中断级任务切换 Yes 返回中断服务程序 No
10
开关中断的实现方法1
根据微处理器和C编译器的不同,通过在移植文件OS_CPU.H 中配置OS_CRITICAL_METHOD来选择开/关中断的方法:
• OS_CRITICAL_METHOD==1用处理器指令关中断 • 执行OS_ENTER_CRITICAL( ),关中断 • 执行OS_EXIT_CRITICAL( ) ,开中断;
宏OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()。
9
开关中断的宏
• 当处理临界段代码时,需要关中断,处理完毕后,再开中断;
• 关中断时间是实时内核重要的指标之一; • 在实际应用中,关中断的时间很大程度中取决于微处理器的
结构和编译器生成的代码质量; • C/OS-II定义两个宏开关中断: OS_ENTER_CRITICAL(); OS_EXIT_CRITICAL(); 因为这2个宏的定义取决于所使用的微处理器,因此在 OS_CPU.H中可以找到相应的宏定义。 OS_CPU.H是微处理 器相关的。
任 务 响 应 时 间
无新高级任务则 返回原任务
注意:对于可剥夺型内核,中断服务 子程序结束后,系统进行一次任务 调度去运行优先级最高的就绪任务, 而不是一定要接续运行被中断的任 务。
3
中断的进入和离开 (1)进入中断函数
void OSIntEnter (void) { if(OSRunning==TRUE) { if(OSIntNesting<255) { OSIntNesting++;} //中断嵌套层数计数器加1 } } 调用情况: 此函数在中断服务程序保护断点数据后,运行用户中断服 务代码之前来调用,所以通常把它叫做进入中断服务函数。

uCOSii中断处理过程详解(一)

uCOSii中断处理过程详解(一)

一. UCOSII‎的中断过程简‎介系统接收到中‎断请求后,如果CPU处‎于开中断状态‎,系统就会中止‎正在运行的当‎前任务,而按中断向量‎的指向去运行‎中断服务子程‎序,当中断服务子‎程序运行完成‎后,系统会根据具‎体情况返回到‎被中止的任务‎继续运行,或转向另一个‎中断优先级别‎更高的就绪任‎务。

由于UCOS‎II是可剥夺‎型的内核,所以中断服务‎程序结束后,系统会根据实‎际情况进行一‎次任务调度,如果有优先级‎更高的任务,就去执行优先‎级更高的任务‎,而不一定要返‎回被中断了的‎任务。

二.UCOSII‎的中断过程的‎示意图三.具体中断过程‎1.中断到来,如果被CPU‎识别,CPU将查中‎断向量表,根据中断向量‎表,获得中断服务‎子程序的入口‎地址。

2.将CPU寄存‎器的内容压入‎当前任务的任‎务堆栈中(依处理器的而‎定,也可能压入被‎压入被中断了‎的任务堆栈中‎。

3.通知操作系统‎将进入中断服‎务子程序。

即:调用OSIn‎t Enter‎()或OSInt‎N estin‎g直接加1。

4.If(OSIntN‎e sting‎==1) {OSTCBC‎u r->OSTCBS‎t rPtr=SP;} //如果是第一层‎中断,则将堆栈指针‎保存到被中断‎任务的任务控‎制块中5.清中断源,否则在开中断‎后,这类中断将反‎复的打入,导致系统崩贵‎6.执行用户IS‎R7.中断服务完成‎后,调用OSIn‎t Exit().如果没有高优‎先级的任务被‎中断服务子程‎序激活而进入‎就绪态,那么就执行被‎中断了的任务‎,且只占用很短‎的时间.8.恢复所有CP‎U寄存器的值‎.9.执行中断返回‎指令.四.相关代码与编译器相关‎的数据类型:typede‎f unsign‎e d char BOOLEA‎N;typede‎f unsign‎e d char INT8U;typede‎f unsign‎e d int OS_STK‎; //堆栈入口宽度‎为16 位(一) void OSIntE‎n ter (void)的理解uCOS_I‎I.H中定义:#ifdef OS_GLO‎B ALS#define‎ OS_EXT‎#else#define‎ OS_EXT‎ extern‎#endif //定义全局宏O‎S_EXT#ifndef‎TRUE#define‎TRUE 1#endifOS_EXT‎ BOOLEA‎N OSRunn‎i ng; //定义外部BO‎O LEAN类‎型全局变量,用来指示//核是否在运行‎OS_EXT‎ INT8U OSIntN‎e sting‎;//定义外部8位‎无符号整型数‎全局变量,用来表//示中断嵌套层‎数OS_COR‎E.C中的OSI‎n tEnte‎r()函数原型:void OSIntE‎n ter (void){if (OSRunn‎i ng == TRUE) //如果内核正在‎运行则进入i‎f{if (OSIntN‎e sting‎< 255) //如果嵌套层数‎小于255,则可以继//续{OSIntN‎e sting‎++; //嵌套层数加1‎}}}(二)在中断服务子‎程序中加if‎( OSIntN‎e sting‎==‎1){…}的原因uCOS_I‎I.H中定义:typede‎f struct‎os_tcb‎{OS_STK‎ *OSTCBS‎t kPtr;//声明指向任务‎堆栈栈顶的1‎6位指针………………‎} OS_TCB‎;//定义名为OS‎_TCB的结‎构体数据类型‎,即任务控制块‎的数据结构OS_EXT‎ OS_TCB‎ *OSTCBC‎u r;//声明一个指向‎任务控制块的‎全局指针变量‎//用于指向当前‎任务的任务控‎制块中断服务程序‎中添加的代码‎:if ( OSIntN‎e sting‎== 1){OSTCBC‎u r->OSTCBS‎t kPtr = SP; // 如果是第一层‎中断,则将被中断任‎务//的堆栈指针保‎存在被中断任‎务的任务//任务控制块中‎}关于uCOS‎-II的中断服‎务程序(ISR)中必须加“OSIntN‎e sting‎==‎1”的原因==避免调整堆栈‎指针.出现这个问题‎的根源是当低‎优先级的任务‎被中断,当中断完成后‎由于有高优先‎级的任务就绪‎,则必须调度高‎优先级的任务‎,原来的低优先‎级任务继续被‎中断着,但是此时的低‎优先级任务的‎堆栈已经被破‎坏,已不能被调度‎程序直接调度‎了,要想被调度而‎必须调整堆栈‎指针。

ucosii中的中断

ucosii中的中断

UC/OS-II中断相关的问题要弄清楚以下函数的意义:OSTimeTick()在OS_CORE.C中,为时钟管理函数。

OSTickISR( )在OS_CPU_A.S中以汇编的形式编写。

任何计算机系统都应该有一系统时钟,UCOS系统的系统时钟是通过硬件定时器产生中断来实现的,这个中断会产生一个时钟中断服务程序,时钟中断服务程序也叫做节拍服务。

各个任务运行都需要一个周期性的信号指示,即每一个任务允许运行的时间片是多少,必须规定好。

这个时间片就是系统时钟节拍UCOS系统响应中断的过程:系统正在运行任务,此时有中断发生,且系统收到了中断请求(系统如何收到中断请求,中断以何种方式告知操作系统?)。

如果处理器处于中断允许状态,系统就中止当前任务的运行,而按照中断向量去执行相应的中断服务程序;中断服务自程序结束前,会进行一次任务调度。

这样中断结束后,系统将会根据情况返回到被中止的任务继续运行,或者转到另外一个具有更高优先级的就绪任务上运行。

全局变量OSIntNesting有两个用途:第一是用来记录中断嵌套的层数,中断嵌套也就是说当第一个中断发生而没有结束的时候,又发生了第二个更重要的中断,依次类推,此时OSIntNesting就用来表示嵌套的层数,也就是有多少个中断在发生或者等待处理,也就是说每当有中断发生时,就将OSIntNesting加1,有中断结束的时候,就将OSIntNesting减1;第二是作为调度器是否可进行调度的标志,以保证调度器不会在中断服务程序中进行任务调度,也就是当OSIntNesting大于0的时候,将调度器加锁,OSIntNesting等于0的时候,调度器解锁。

(这样理解调度器的加锁和解锁,是否正确?中断服务自程序结束前,会进行一次任务调度。

这个时候调度器不是锁上的吗?如何调度呢?)UCOS用两个函数OSIntEnter (void)和OSIntExit (void)来处理变量SIntNesting。

μC/OS-Ⅱ的中断系统设计

μC/OS-Ⅱ的中断系统设计

引言嵌入式实时系统要求系统有很好的实时性,能够及时处理各种异常事件,因此中断系统是嵌入式实时系统的重要组成部分,其时间和空间性能对嵌入式实时系统性能的影响至关重要。

要想缩短嵌入式实时系统的中断响应时间并提高系统中断处理效率,合理地设计中断系统非常关键。

S3C44BOX是三星公司基于ARM7TDMI内核的微处理器,支持IRQ和FIQ中断请求,同时还支持向量中断,以缩短中断响应时间。

嵌入式实时操作系统μC/OS-II提供了简单的中断管理机制对系统中断进行统一管理,但是对于不同的微处理器没有给出具体的中断处理方法。

本文在深入分析S3C448OX中断控制系统和μC/OS-II中断管理机制的基础上,进行中断系统设计,使之能更好地满足实际应用的需求。

1 S3C4480X中断系统图1所示为S3C44BOX的中断系统结构框图。

中断控制器的任务是在片内外围和片外中断源组成的多重中断发生时,经过优先级判断、选择其中一个中断;通过IRQ或FIQ向ARM7内核发出IRQ或FIQ中断请求,ARM7内核从中断控制器中获取中断信息,然后对中断进行处理,控制中断设备的操作过程。

当ARM7内核接收到中断控制器的中断请求时会自动执行以下几步操作,以实现中断环境保护和程序跳转:①将程序状态寄存器CPSR的内容保存到将要执行的中断模式的程序状态保存寄存器SPSR中,以实现对处理器当前状态、中断屏蔽位和各条件标志位的保存。

②设置当前CPSR中的相应位,屏蔽相应中断并切换处理器模式。

③将引起中断指令的下一条指令的地址(断点地址)保存到中断模式的子程序链接寄存器LR中,使中断服务程序执行完后能正确返回原程序。

④给程序计数器PC强制赋值,使程序从相应的向量地址开始执行中断服务程序。

当中断服务程序执行完后,需要执行以下几步操作从中断服务程序中返回:①从中断模式堆栈中恢复所有修改过的通用寄存器(RO~R12)。

②将中断模式SPSR寄存器的内容复制到CPSR中,恢复被中断模式程序的工作状态。

STM32 uCOS_II 实践 之 外部中断事件 及 系统运行过程 .dot

STM32 uCOS_II 实践 之 外部中断事件 及 系统运行过程 .dot

在进行uCOSII的程序之前先来复习下,裸机平台下stm32的外部中断的操作。

大概可以分作4个步骤:1-配置相应管脚为浮空输入;2-配置相应管脚为外部中断口并设定其中断属性及参数;3-配置NVIC相关寄存器,设定中断优先级;4-编写中断服务函数。

废话不说直接上代码:第一步:配置相应管脚为浮空输入,来自文件Key.cvoid Key_Port_Configuration(void){GPIO_InitTypeDefGPIO_InitStructure_EXTI_KEY_PORTE;GPIO_InitStructure_EXTI_KEY_PORTE.GPIO_Pin=GPIO_Pin_4; // 端口4GPIO_InitStructure_EXTI_KEY_PORTE.GPIO_Mode=GPIO_Mode_IN_FLOATING; // 浮空输入GPIO_InitStructure_EXTI_KEY_PORTE.GPIO_Speed=GPIO_Speed_50MHz; // 口线翻转速度为50MHzGPIO_Init(GPIOE, &GPIO_InitStructure_EXTI_KEY_PORTE); // 端口初始化GPIO_InitStructure_EXTI_KEY_PORTE.GPIO_Pin=GPIO_Pin_3; // 端口3GPIO_InitStructure_EXTI_KEY_PORTE.GPIO_Mode=GPIO_Mode_IN_FLOATING; // 浮空输入GPIO_InitStructure_EXTI_KEY_PORTE.GPIO_Speed=GPIO_Speed_50MHz; // 口线翻转速度为50MHzGPIO_Init(GPIOE, &GPIO_InitStructure_EXTI_KEY_PORTE); // 端口初始化第二步:配置相应管脚为外部中断口并且设定其中断属性及参数,来自文件EXTIG.c void EXTI_PORTE_Configuration(void){EXTI_InitTypeDefEXTI_InitStructure_EXTI_LINE4;EXTI_InitTypeDefEXTI_InitStructure_EXTI_LINE3;/* Connect EXTI Line4,3 to PE4,PE3 */GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource4); // 配置管脚PE4用作外部中断线路GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource3); // 配置管脚PE3用作外部中断线路/* Configure EXTI Line4 to generate an interrupt on falling edge */EXTI_InitStructure_EXTI_LINE4.EXTI_Line=EXTI_Line4; //配置使能或失能的外部线路EXTI_InitStructure_EXTI_LINE4.EXTI_Mode=EXTI_Mode_Interrupt; //配置EXTI线路为中断请求(或者是事件请求)EXTI_InitStructure_EXTI_LINE4.EXTI_Trigger=EXTI_Trigger_Falling; //配置使能线路的触发边沿-- 下降沿触发中断EXTI_InitStructure_EXTI_LINE4.EXTI_LineCmd=ENABLE; //配置状态为使能EXTI_Init(&EXTI_InitStructure_EXTI_LINE4); // 初始化外部中断线路4/* Configure EXTI Line3 to generate an interrupt on falling edge */EXTI_InitStructure_EXTI_LINE3.EXTI_Line=EXTI_Line3; //配置使能或失能的外部线路EXTI_InitStructure_EXTI_LINE3.EXTI_Mode=EXTI_Mode_Interrupt; //配置EXTI线路为中断请求(或者是事件请求)EXTI_InitStructure_EXTI_LINE3.EXTI_Trigger=EXTI_Trigger_Falling; //配置使能线路的触发边沿-- 下降沿触发中断EXTI_InitStructure_EXTI_LINE3.EXTI_LineCmd=ENABLE; //配置状态为使能EXTI_Init(&EXTI_InitStructure_EXTI_LINE3); // 初始化外部中断线路3/* Generate software interrupt: simulate a falling edge applied on EXTI line 13 */ EXTI_GenerateSWInterrupt(EXTI_Line4); //线路4产生一个软件中断EXTI_GenerateSWInterrupt(EXTI_Line3); //线路3产生一个软件中断}第三步:配置NVIC相关寄存器,设定中断优先级,来自文件SysInit.cvoid NVIC_Configuration(void){NVIC_InitTypeDefNVIC_InitStructure_EXTI_LINE;/* ================ NVIC-EXTI-PORTE ================= *//* Configure one bit for preemption priority */NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); // 配置优先级分组长度/* Enable the EXTI15_10 Interrupt */NVIC_InitStructure_EXTI_LINE.NVIC_IRQChannel=EXTI4_IRQn; // 配置使能指定的IRQ(Interrupt ReQuest中断请求)通道NVIC_InitStructure_EXTI_LINE.NVIC_IRQChannelPreemptionPriority=0; // 配置IRQ 的组优先级NVIC_InitStructure_EXTI_LINE.NVIC_IRQChannelSubPriority=0; // 配置IRQ的从优先级NVIC_InitStructure_EXTI_LINE.NVIC_IRQChannelCmd=ENABLE; // 配置IRQ 使能NVIC_Init(&NVIC_InitStructure_EXTI_LINE); // 初始化IRQNVIC_InitStructure_EXTI_LINE.NVIC_IRQChannel=EXTI3_IRQn; // 配置使能指定的IRQ(Interrupt ReQuest中断请求)通道NVIC_InitStructure_EXTI_LINE.NVIC_IRQChannelPreemptionPriority=0; // 配置IRQ 的组优先级NVIC_InitStructure_EXTI_LINE.NVIC_IRQChannelSubPriority=0; // 配置IRQ的从优先级NVIC_InitStructure_EXTI_LINE.NVIC_IRQChannelCmd=ENABLE; // 配置IRQ 使能NVIC_Init(&NVIC_InitStructure_EXTI_LINE); // 初始化IRQ}第四步:编写中断服务程序,来自文件stm32f10x_it.cvoid EXTI3_IRQHandler(void){if(EXTI_GetITStatus(EXTI_Line3) == SET) // 读取中断状态{LED1_LOW;EXTI_ClearITPendingBit(EXTI_Line3); // 清除标志位}}void EXTI4_IRQHandler(void){if(EXTI_GetITStatus(EXTI_Line4) == SET) // 读取中断状态{LED1_HIGH;EXTI_ClearITPendingBit(EXTI_Line4); // 清除标志位}}下面就要说说在uCOSII里的时候了。

UCOSII中OS_CPU_IRQ_ISR移植过程分析

UCOSII中OS_CPU_IRQ_ISR移植过程分析

UCOS-II中OS_CPU_IRQ_ISR移植过程分析在uc/os-II的移植过程中存在一个通用的irq中断处理函数,其中的实现过程如下:OS_CPU_IRQ_ISRSTMFD SP!, {R1-R3} ; We will use R1-R3 as temporary registersMOV R1, SPADD SP, SP, #12 ;Adjust IRQ stack pointerSUB R2, LR, #4 ;Adjust PC for return address to taskMRS R3, SPSR ; Copy SPSR (Task CPSR)MSR CPSR_cxsf, #SVCMODE|NOINT ;Change to SVC mode; SAVE TASK''S CONTEXT ONTO OLD TASK''S STACK STMFD SP!, {R2} ; Push task''s PCSTMFD SP!, {R4-R12, LR} ; Push task''s LR,R12-R4 LDMFD R1!, {R4-R6} ; Load Task''s R1-R3 from IRQ stackSTMFD SP!, {R4-R6} ; Push Task''s R1-R3 to SVC stackSTMFD SP!, {R0} ; Push Task''s R0 to SVC stackLDR R0,=OSIntNesting ;OSIntNesting++LDRB R1,[R0]ADD R1,R1,#1STRB R1,[R0]CMP R1,#1 ;if(OSIntNesting==1){BNE %F1LDRR4,=OSTCBCur ;OSTCBHighRdy->;OSTCBStkPtr=SP;LDR R5,[R4]STR SP,[R5] ;}1 MSR CPSR_c,#IRQMODE|NOINT ;Change to IRQ mode to use IRQ stack to handle interruptLDR R0, =INTOFFSETLDR R0, [R0]LDR R1, IRQIsrVectMOV LR, PC ; Save LR befor jump to the C function we need return backLDR PC, [R1, R0, LSL #2] ; CallOS_CPU_IRQ_ISR_handler();MSR CPSR_c,#SVCMODE|NOINT ;Change to SVC mode BL OSIntExit ;Call OSIntExitMSR SPSR_cxsf,R4LDMFD SP!,{R0-R12,LR,PC}^ ;POP new Task''s contextIRQIsrVect DCD HandleEINT0这个函数是irq中断的通用处理形式,我对其中的代码做一下简要的分析和讨论。

ucos-ii中断结构及中断嵌套的问题

ucos-ii中断结构及中断嵌套的问题

ucos-ii中断结构及中断嵌套的问题问ucos-ii中断结构及中断嵌套的问题中断处理流程1:IRQ中断发生后调用UCOS_IRQHandler()2:UCOS_IRQHandler()先压栈3:后调用OSIntEnter()4:根据IRQ偏移量查找处理函数5:用户中断处理函数6:OSIntExit()7:如果发生中断切换调用INTCTXSW否则恢复现场至中断前任务代码如下:UCOS_IRQHandlerstmfd sp!,{r0-r12,lr}bl OSIntEnterbl C_IRQHandlerbl OSIntExitldr r0,=OSIntCtxSwFlag 调用OSIntCtxSw后置1ldr r1,[r0]cmp r1,#1beq _IntCtxSwldmfd sp!,{r0-r12,lr}subs pc,lr,#4_IntCtxSwmov r1,#0str r1,[r0]ldmfd sp!,{r0-r12,lr}stmfd sp!,{r0-r3}mov r1,spadd sp,sp,#16sub r2,lr,#4mrs r3,spsrorr r0,r3,#NOINTmsr spsr_c,r0ldr r0,=.+8movs pc,r0stmfd sp!,{r2} ; push old task's pcstmfd sp!,{r4-r12,lr} ; push old task's lr,r12-r4 mov r4,r1 ; Special optimised code below mov r5,r3ldmfd r4!,{r0-r3}stmfd sp!,{r0-r3} ; push old task's r3-r0stmfd sp!,{r5} ; push old task's psrmrs r4,spsrstmfd sp!,{r4} ; push old task's spsr; OSPrioCur = OSPrioHighRdyldr r4,=OSPrioCurldr r5,=OSPrioHighRdyldrb r5,[r5]strb r5,[r4]; Get current task TCB addressldr r4,=OSTCBCurldr r5,[r4]str sp,[r5] ; store sp in preempted tasks's TCBbl OSTaskSwHook ; call Task Switch Hook; Get highest priority task TCB addressldr r6,=OSTCBHighRdyldr r6,[r6]ldr sp,[r6] ; get new task's stack pointer; OSTCBCur = OSTCBHighRdystr r6,[r4] ; set new current task TCB addressldmfd sp!,{r4} ; pop new task's spsrmsr SPSR_cxsf,r4ldmfd sp!,{r4} ; pop new task's psrmsr CPSR_cxsf,r4ldmfd sp!,{r0-r12,lr,pc} ; pop new task's r0-r12,lr & pc void C_IRQHandler(void) //void C_IRQHandler(void) {U32 wTemp;wTemp = rINTOFFSET<<2;((void(*)(void))(*((U32 *)(aISR_EINT0+wTemp))))();}void __vWDTInterrupt(){rSRCPND &= BIT_WDT; // Clear pending bit -- Watchdog timerrINTPND &= BIT_WDT;OSTimeTick();}我现在用看门狗做时钟中断,没有其他中断时一切正常,但是我加了个串口中断后发现以下问题,串口中断如下:void __irq Uart1Task(void){rINTSUBMSK|=(BIT_SUB_RXD1|BIT_SUB_TXD1|BIT_SUB_ERR 1);if(rSUBSRCPND&BIT_SUB_RXD1){Uart0RxBuffer[Uart0RxInSp++] =(char)RdURXH1();}rSUBSRCPND&=(BIT_SUB_RXD1|BIT_SUB_ERR1); // Clear Sub int pendingrINTSUBMSK&=~(BIT_SUB_RXD1|BIT_SUB_ERR1);rSRCPND &= BIT_UART1;rINTPND &= BIT_UART1;}1:中断响应慢,而且丢数据,我发送几个数据后串口才开始响应中断,但前几个数据都丢失,本以为是优先级低,采取了取消优先级,及建立高于看门狗优先级的INT0中断,取消掉任务中的关中断及WHILE(1)等,但是问题依旧。

uCOS II在ARM处理器上移植过程中的中断处理

uCOS II在ARM处理器上移植过程中的中断处理

uCOS II在ARM处理器上移植过程中的中断处理uCOS II是一个源码藏匿、可移植、可固化、可剪裁和抢占式的实时多任务操作系统,其大部分源码是用ANSI C编写,与处理器硬件相关的部分用法汇编语言编写。

总量约200行的汇编语言部分被压缩到最低限度,以便于移植到任何一种其它的CPU上。

uCOS II最多可支持56个任务,其内核为占先式,总是执行就绪态的优先级最高的任务,并支持Semaphore (信号量)、Mailbox (邮箱)、MessageQueue(消息队列)等多种常用的进程间通信机制。

与大多商用RTOS不同的是,uCOS II藏匿全部的源代码.并可以免费获得,只对商业应用收取少量License费用。

uCOS II移植跟OS_CUP_C.C、OS_CPU_A.S、OS_CPU.H 3个文件有关,中断处理的移植占领了很大一部分内容。

作为移植的一个重点,本文以标准中断(IRQ)为例研究了移植中的中断处理。

1 uCOS II系统结构uCOS II的软硬件体系结构1。

应用程序处于囫囵系统的顶层.每个任务都可以认为自己独占了CPU,因而可以设计成为一个无限循环。

大部分代码是用法ANSI 书写的,因此uCOS II的可移植性较好。

尽管如此,仍然需要用法C和汇编语言写一些处理器相关的代码。

uCOS II 的移植需要满足以下要求:1)处理器的C编译器可以产生可重入代码:可以用法C调用进入和退出Critical Code(临界区代码);2)处理器必需支持硬件中断,并且需要一个定时中断源;3)处理器需能容纳一定数据的硬件堆栈;4)处理器需有能在CPU寄存器与内存和堆栈交换数据的命令。

移植uCOS II的主要工作就是处理器和编译器相关代码以及BSP(Board Support Package)的编写。

uCOS II处理器无关的代码提供uCOS II的系统服务,应用程序可以用法这些API函数举行内存管理、任务间通信以及创建、删除任务等。

UCOSII与中断(按键)

UCOSII与中断(按键)
统接收到中断请求后,这时如果
CPU 处注于意中!断中允断许服状务态 子( 即程中序断运是行结束
开 的μ放当C的前之次/)任O后任S,务-,务系 ,I调系I统 而系度统就 按统去将会 照运会中 中行根止 断正 向优据在 量先情运 的级况行指别进最行高一
向转而的去就运绪行任中务断响,服而应务并子中程不断序是的;一当过定程要接
任务切换过程 其实,调度 根据就绪表获得
器在进行调 获 待得 运待 行运 任行 务任 的务任 度时,在这 的 务任 控务 制控 块制 指块 针
个位置还要
进行一下判 断:究竟是 待运行任务
处理器的SP=任 务块中保存的SP
是否为当前 任务,如果 是,则不切
恢复待运行任务 的运行环境
换;如果不
是才切换, 处理器的PC=任
UCOSII与中断(按键) 控制LED
毛德明 142460389
任务运行时与 处理器之间的关系
运行环境包括了两部分: 处理器中的运行环境和
内存中的处运理行器环境
PC
寄存器组
内存 任务代码
SP 处理器通过两个指针寄存
任务堆栈
器(PC和SP)来与任务 程序运行环境 代码和任务堆栈建立联系
并运行它
多任务时任务与处理器
任务控制块或被剥 夺了任务控制块时
。 一个正在运行的
而使任务进入任等务待一状旦态响应中
的状态叫做任务的
断申请就会中止
任务的状态及其转换 睡眠状态
运行而去执行中 断服务程序,这 时任务的状态叫
做中断服务状态
系统为任务配备 了任务控制块且 在任务就绪表中 进行了就绪登记, 这时任务的状态 叫做就绪状态。
起始任务TaskStart的代码

ucos ii时钟中断技术介绍

ucos ii时钟中断技术介绍

ucos ii时钟中断技术介绍一、ucos ii时钟管理系统ucos ii原有的时钟管理系统类似于Linux,但是比Linux简单得多。

它仅向用户提供一个周期性的信号OSTime,时钟频率可以设置在10~100 Hz,时钟硬件周期性地向CPU发出时钟中断,系统周期性响应时钟中断,每次时钟中断到来时,中断处理程序更新一个全局变量OSTime。

ucos ii时钟中断服务程序的核心是调用OSTimeTick ()函数。

OSTimeTick ()函数用来判断延时任务是否延时结束从而将其置于就绪态。

其程序伪代码如下:void OSTimeTick(void) {OSTimeTickHook();// 调用用户定义的时钟节拍外连函数while { (除空闲任务外的所有任务)OS_ENTER_CRITICAL();//关中断对所有任务的延时时间递减;扫描时间到期的任务,并且唤醒该任务;OS_EXIT_CRITICAL();//开中断指针指向下一个任务;}OSTime++;//累计从开机以来的时间}在ucos ii的时钟节拍函数中,需要执行用户定义的时钟节拍外连函数OSTimeTickHook (),以及对任务链表进行扫描并且递减任务的延时。

这样就造成了时钟节拍函数OSTimeTick ()有两点不足:1、在时钟中断中处理额外的任务OSTimeIickHook (),这样增加了中断处理的负担,影响了定时服务的准确性;2、在关中断情况下扫描任务链表,任务越多所需要时间越长,而长时间关中断对中断响应有不利影响,是中断处理应当避免的。

二、改进的时钟管理系统针对上述OSTimeTick ()的不足之处,需加以改进来优化时钟节拍函数。

在Linux中一般对中断的响应分为两部分:立即中断服务和底半中断处理(bottom half)。

立即中断服务仅仅做重要的并且能快速完成的工作,而把不太重要的需要较长时间完成的工作放在底半处理部分来完成,这样就可以提高中断响应速度。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 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.执行用户ISR7.中断服务完成后,调用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#endifOS_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(); ④然而在实际的移植过程中,需要调整的指针偏移量是与编译器相关的,如果想要避免调整,显然一个简单的方法就是在调用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()即为将处理器标志//寄存器的中断标志为清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//为OS_CPU_SR型变量#define OS_EXIT_CRITICAL() (OSCPURestoreSR(cpu_sr))// 从cpu_sr中恢复状态寄存//器#endif //此一整段代码定义为开关中断的方式三,//此段代码只是示意代码,OSCPUSaveSR()及//OSCPURestoreSR(cpu_sr)具体什么函数由//用户编译器所提供的函数决定.//以上宏定义非常重要,在使用不同处理器时要使用相应处理器的开关中断指令,在代码移//植时很有用uCOS_II.H中定义:OS_EXT INT8U OSLockNesting; //8位无符号全局整数,表示锁定嵌套计数器void OSIntExit (void){#if OS_CRITICAL_METHOD == 3OS_CPU_SR cpu_sr;#endif //采用开关中断方式三if (OSRunning == TRUE) //如果内核正在运行,则进入if{OS_ENTER_CRITICAL();//进入临界段,关中断if (OSIntNesting > 0) //判断最外层中断任务是否已完成{OSIntNesting--;//由于此层中断任务已完成,中断嵌套计数器减//一}if ((OSIntNesting == 0) && (OSLockNesting == 0))// OSIntNesting==0表示程序的最外层中断任务以完成, OSLockNesting == 0//表示是否存在任务锁定,整句代码的意思是如果全部中断处理完了且没有其他//任务锁定任务调度则执行下列任务调度代码{OSIntExitY = OSUnMapTbl[OSRdyGrp]; //1OSPrioHighRdy = (INT8U)((OSIntExitY << 3) +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_EXT INT8U OSRdyGrp;即8位无符号整型的全局变量)和OSRdyTb1[](在uCOS_II.H中为OS_EXT INT8U OSRdyTbl[OS_RDY_TBL_SIZE];)先分析OS_EXT INT8U OSRdyTbl[OS_RDY_TBL_SIZE];是怎么回事#define OS_LOWEST_PRIO 12 //在OS_CFG.H中这个宏定义了任务所能具有的最低优先级,那么此处共有从0到12共13个优先级,用户在代码移植时可以修改它,自定义所需要的优先级个数,但max(OS_LOWEST_PRIO)==63#define OS_RDY_TBL_SIZE ((OS_LOWEST_PRIO) / 8 + 1) //在uCOS_II.中OS_RDY_TBL_SIZE用于确定数组OSRdyTbl[]的大小,如果OS_LOWEST_PRIO==63,则上述宏实际上为#define OS_RDY_TBL_SIZE 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中定义如下:INT8U const OSUnMapTbl[] = {0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x00 to 0x0F */4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x10 to 0x1F */5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x20 to 0x2F */4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x30 to 0x3F */6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x40 to 0x4F */4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x50 to 0x5F */5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x60 to 0x6F */4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x70 to 0x7F */7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x80 to 0x8F */4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x90 to 0x9F */5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0xA0 to 0xAF */4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0xB0 to 0xBF */6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0xC0 to 0xCF */4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0xD0 to 0xDF */5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0xE0 to 0xEF */4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 /* 0xF0 to 0xFF */};理解: 我把问题转化为:“一个无符号的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次。

相关文档
最新文档