uCOSii中断处理过程详解
第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-ii用户中断服务程序的编写
用户中断服务程序的编写1.调用OSIntEnter()或者直接OSIntNesting++;目的是告诉任务进入中断服务程序或者发生了用户中断,禁止任务切换。
2.中断处理进行相应的中断处理,可对信号量、消息邮箱、消息队列进行操作,用于任务间的通信3.调用OSIntExit()退出中断服务程序,进行任务级的任务切换串口中断服务程序实例void USART1_IRQHandler(void){unsigned int i;unsigned char msg[50];OS_CPU_SR cpu_sr;OS_ENTER_CRITICAL(); //保存全局中断标志,关总中断// T ell uC/OS-II that we are starting an ISROSIntNesting++;OS_EXIT_CRITICAL(); //恢复全局中断标志//OSTimeTick(); // Call uC/OS-II's OSTimeTick(),在os_core.c文件里定义,主要判断延时的任务是否计时到if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //判断读寄存器是否非空{// Read one byte from the receive data registermsg[RxCounter1++]= USART_ReceiveData(USART1); //将读寄存器的数据缓存到接收缓冲区里if(msg[RxCounter1-1]=='L'){msg[0]='L'; RxCounter1=1;} //判断起始标志if(msg[RxCounter1-1]=='F') //判断结束标志是否是"F"{for(i=0; i< RxCounter1; i++){TxBuffer1[i] =msg[i]; //将接收缓冲器的数据转到发送缓冲区,准备转发}TxBuffer1[RxCounter1]=0; //接收缓冲区终止符RxCounter1=0;//OSSemPost(Com1_SEM);OSMboxPost(Com1_MBOX,(void *)&msg);}}if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET) //{USART_ITConfig(USART1, USART_IT_TXE, DISABLE);}OSIntExit(); //在os_core.c文件里定义,如果有更高优先级的任务就绪了,则执行一次任务切换}。
东软UCOS-II教程-03-中断与时钟
3 Sept. 2008 Confidential
3.1.4 中断级任务切换
与任务级切换函数OSCtxSW() 的原因一样,中断级任务切换函数OSIntCtxSw ()通常 是用汇编语言来编写的:
OSIntCtxSw() { OSTCBCur = OSTCBHighRdy; OSPrioCur = OSPrioHighRdy; SP = OSPrioHighRdy ->OSTCBStkPtr; 用出栈指令把 R1、 R2…… 弹入 CPU 的通用寄存器; RETI ; } // 中断返回,使 PC指向待运行任务 // 使 SP指向待运行任务堆栈 // 任务控制块的切换
学时:3.0学时 教学方法:讲授ppt+上机练 习+点评+案例分析
3 Sept. 2008 Confidential
3.1 uC/OS-II 的中断
� 中断:任务在运行过程中,应内部或外部异步事件的请求中止当前 任务,而去处理异步事件所要求的任务的过程叫做中断。 � 中断服务程序:应中断请求而运行的程序叫中断服务子程序 (ISR)。 � 中断向量:中断服务子程序的入口地址叫中断向量。 � CPU响应中断的条件: •至少有一个中断源向 CPU发出中断信号 •系统允许中断,且对此中断信号未予屏蔽
•
• OS_CRITICAL_METHOD==2 实现OS_ENTER_CRITICAL() 时,先在堆栈中保存中断的开/关状态,然后再 关中断;实现OS_EXIT_CRITICAL() 时,从堆栈中弹出原来中断的开/关状态; 方法2的示意性代码 #define OS_ENTER_CRITICAL() asm(“PUSH asm(“DI”) #define OS_EXIT_CRITICAL() asm(“POP PSW”) PSW”)
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的任务切换机理及中断调度优化
摘要:μC/OS-II是一种适用于嵌入式系统的抢占式实时多任务操作系统,开放源代码,便于学习和使用。
介绍μC/OS-II在任务级和中断级的任务切换原理,以及这一操作系统基于嵌入式系统的对于中断的处理;相对于内存资源较少的单片机,着重讨论一种优化的实用堆栈格式和切换形式,以提高资源的利用率;结合MSP430单片机,做具体的分析。
关键词:实时多任务操作系统μC/OS MSP430 中断堆栈引言在嵌入式操作系统领域,由Jean J. Labrosse开发的μC/OS,由于开放源代码和强大而稳定的功能,曾经一度在嵌入式系统领域引起强烈反响。
而其本人也早已成为了嵌入式系统会议(美国)的顾问委员会的成员。
不管是对于初学者,还是有经验的工程师,μC/OS开放源代码的方式使其不但知其然,还知其所以然。
通过对于系统内部结构的深入了解,能更加方便地进行开发和调试;并且在这种条件下,完全可以按照设计要求进行合理的裁减、扩充、配置和移植。
通常,购买RTOS往往需要一大笔资金,使得一般的学习者望而却步;而μC/OS对于学校研究完全免费,只有在应用于盈利项目时才需要支付少量的版权费,特别适合一般使用者的学习、研究和开发。
自1992 第1版问世以来,已有成千上万的开发者把它成功地应用于各种系统,安全性和稳定性已经得到认证,现已经通过美国FAA认证。
1 μC/OS-II的几大组成部分μC/OS-II可以大致分成核心、任务处理、时间处理、任务同步与通信,CPU的移植等5个部分。
核心部分(OSCore.c) 是操作系统的处理核心,包括操作系统初始化、操作系统运行、中断进出的前导、时钟节拍、任务调度、事件处理等多部分。
能够维持系统基本工作的部分都在这里。
任务处理部分(OSTask.c)任务处理部分中的内容都是与任务的操作密切相关的。
包括任务的建立、删除、挂起、恢复等等。
因为μC/OS-II是以任务为基本单位调度的,所以这部分内容也相当重要。
嵌入式实时操作系统uC OS-2教程(吴永忠)章 (4)
第4章 中断处理与时间管理
4.1 中断处理的基本概念 4.2 μC/OS-Ⅱ的中断处理 4.3 μC/OS-Ⅱ的时钟节拍 4.4 μC/OS-Ⅱ的时间管理 习题
第4章 中断处理与时间管理
4.1 中断处理的基本概念
4.1.1 中断 中断定义为CPU对系统内外发生的异步事件的响应。异步
中断响应考虑的是系统在最坏情况下的响应中断时间,而 不是平均时间。如某系统100次中有99次在100 μs之内响应中 断,只有一次响应中断的时间是250 μs,只能认为中断响应 时间是250 μs。
第4章 中断处理与时间管理
4.1.4 中断恢复时间 中断恢复时间(Interrupt Recovery)定义为CPU返回到被
第4章 中断处理与时间管理 在前后台系统中:
中断延迟
=
MAX
最长指令 时间
,关 最中 长断 时的 间
+
中断向量 距转时间
在不可剥夺型和不可剥夺内核中:
中断延迟 = MAX
最长指令 时间
,中用断户时关间
,中内断核时关间 +
中断向量 跳转时间
第4章 中断处理与时间管理
4.1.3 中断响应 中断响应定义为从中断发生起到开始执行中断用户处理程
特点是中断优先级高、延迟时间短、响应快、不能被嵌套、不 能忍受内核的延迟,一般常应用于紧急事件处理,如掉电保护 等。非屏蔽中断的规则如下:
(1) 在非屏蔽中断处理程序中,不能处理临界区代码、不 能使用内核提供的服务。
(2) 在非屏蔽中断处理程序中,参数的传递必须用全程变 量,且全程变量的字节长度必须能够一.6 μC/OS-Ⅱ的中断处理过程示意图
第4章 中断处理与时间管理
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函数举行内存管理、任务间通信以及创建、删除任务等。
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。
第4章 ucosII中的中断和时钟
4.1.2 中断级任务切换程序
ucos-II在中断中有可能使高优先 在中断中有可能使高优先 级的任务处于就绪的状态, 级的任务处于就绪的状态,所以在 中断返回任务的过程中需要进行任 务的切换 在中断中调用的负责任务切换工作 的函数叫作OSIntCtxSw()中断级 的函数叫作 中断级 任务切换函数 OSIntCtxSw()函数与 函数与OSCtxSw() 函数与 函数类似, 函数类似,通常使用汇编语言编写 OSIntCtxSw()函数的后半断与 函数的后半断与 OSCtxSw()函数的后半段完全相 函数的后半段完全相 只是少了相应的前半段程序, 同,只是少了相应的前半段程序, 因为当中断发生时, 因为当中断发生时,任务相关的寄 存器的内容已经被保存在任务堆栈 中了
4.1.2 ucos-II的中断过程 的中断过程
右图是对中断处理流程 的总结 中断服务子程序的功能
在中断服务程序中通过向 中断处理任务发送消息的 方法去激活相应任务去响 应处理中断 使用这种方法可以保证中 断响应时间尽可能短, 断响应时间尽可能短,系 统具有较好的实时性 中断流程的总结(如图) 中断流程的总结(如图)
优点:进入退出临界段后中断开关状态不会改变 优点: 缺点: 缺点:使用了任务栈保存当前中断状态
#if OS_CRITICAL_METHOD == 2 #define OS_ENTER_CRITICAL() asm("PUSH PSW") asm("DI") #define OS_EXIT_CRITICAL() asm("POP PSW") #endif
注意:不能在临界段中调用 中的功能函数, 注意:不能在临界段中调用ucos-II中的功能函数,以免系统崩溃 中的功能函数
第4章uCOSII的时钟和中断
(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的中断过程简介系统接收到中断请求后,如果CPU处于开中断状态,系统就会中止正在运行的当前任务,而按中断向量的指向去运行中断服务子程序,当中断服务子程序运行完成后,系统会根据具体情况返回到被中止的任务继续运行,或转向另一个中断优先级别更高的就绪任务。
由于UCOSII是可剥夺型的内核,所以中断服务程序结束后,系统会根据实际情况进行一次任务调度,如果有优先级更高的任务,就去执行优先级更高的任务,而不一定要返回被中断了的任务。
二.UCOSII的中断过程的示意图三.具体中断过程1.中断到来,如果被CPU识别,CPU将查中断向量表,根据中断向量表,获得中断服务子程序的入口地址。
2.将CPU寄存器的内容压入当前任务的任务堆栈中(依处理器的而定,也可能压入被压入被中断了的任务堆栈中。
3.通知操作系统将进入中断服务子程序。
即:调用OSInt Enter()或OSIntN esting直接加1。
4.If(OSIntNe sting==1) {OSTCBCu r->OSTCBSt rPtr=SP;} //如果是第一层中断,则将堆栈指针保存到被中断任务的任务控制块中5.清中断源,否则在开中断后,这类中断将反复的打入,导致系统崩贵6.执行用户ISR7.中断服务完成后,调用OSInt Exit().如果没有高优先级的任务被中断服务子程序激活而进入就绪态,那么就执行被中断了的任务,且只占用很短的时间.8.恢复所有CPU寄存器的值.9.执行中断返回指令.四.相关代码与编译器相关的数据类型:typedef unsigne d char BOOLEAN;typedef unsigne d char INT8U;typedef unsigne d int OS_STK; //堆栈入口宽度为16 位(一) void OSIntEn ter (void)的理解uCOS_II.H中定义:#ifdef OS_GLOB ALS#define OS_EXT#else#define OS_EXT extern#endif //定义全局宏OS_EXT#ifndefTRUE#defineTRUE 1#endifOS_EXT BOOLEAN OSRunni ng; //定义外部BOO LEAN类型全局变量,用来指示//核是否在运行OS_EXT INT8U OSIntNe sting;//定义外部8位无符号整型数全局变量,用来表//示中断嵌套层数OS_CORE.C中的OSIn tEnter()函数原型:void OSIntEn ter (void){if (OSRunni ng == TRUE) //如果内核正在运行则进入if{if (OSIntNe sting< 255) //如果嵌套层数小于255,则可以继//续{OSIntNe sting++; //嵌套层数加1}}}(二)在中断服务子程序中加if( OSIntNe sting==1){…}的原因uCOS_II.H中定义:typedef structos_tcb{OS_STK *OSTCBSt kPtr;//声明指向任务堆栈栈顶的16位指针………………} OS_TCB;//定义名为OS_TCB的结构体数据类型,即任务控制块的数据结构OS_EXT OS_TCB *OSTCBCu r;//声明一个指向任务控制块的全局指针变量//用于指向当前任务的任务控制块中断服务程序中添加的代码:if ( OSIntNe sting== 1){OSTCBCu r->OSTCBSt kPtr = SP; // 如果是第一层中断,则将被中断任务//的堆栈指针保存在被中断任务的任务//任务控制块中}关于uCOS-II的中断服务程序(ISR)中必须加“OSIntNe sting==1”的原因==避免调整堆栈指针.出现这个问题的根源是当低优先级的任务被中断,当中断完成后由于有高优先级的任务就绪,则必须调度高优先级的任务,原来的低优先级任务继续被中断着,但是此时的低优先级任务的堆栈已经被破坏,已不能被调度程序直接调度了,要想被调度而必须调整堆栈指针。
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-Ⅱ的中断系统设计
引言嵌入式实时系统要求系统有很好的实时性,能够及时处理各种异常事件,因此中断系统是嵌入式实时系统的重要组成部分,其时间和空间性能对嵌入式实时系统性能的影响至关重要。
要想缩短嵌入式实时系统的中断响应时间并提高系统中断处理效率,合理地设计中断系统非常关键。
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
在进行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移植过程分析
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中断的通用处理形式,我对其中的代码做一下简要的分析和讨论。
UCOSII与中断(按键)
CPU 处注于意中!断中允断许服状务态 子( 即程中序断运是行结束
开 的μ放当C的前之次/)任O后任S,务-,务系 ,I调系I统 而系度统就 按统去将会 照运会中 中行根止 断正 向优据在 量先情运 的级况行指别进最行高一
向转而的去就运绪行任中务断响,服而应务并子中程不断序是的;一当过定程要接
任务切换过程 其实,调度 根据就绪表获得
器在进行调 获 待得 运待 行运 任行 务任 的务任 度时,在这 的 务任 控务 制控 块制 指块 针
个位置还要
进行一下判 断:究竟是 待运行任务
处理器的SP=任 务块中保存的SP
是否为当前 任务,如果 是,则不切
恢复待运行任务 的运行环境
换;如果不
是才切换, 处理器的PC=任
UCOSII与中断(按键) 控制LED
毛德明 142460389
任务运行时与 处理器之间的关系
运行环境包括了两部分: 处理器中的运行环境和
内存中的处运理行器环境
PC
寄存器组
内存 任务代码
SP 处理器通过两个指针寄存
任务堆栈
器(PC和SP)来与任务 程序运行环境 代码和任务堆栈建立联系
并运行它
多任务时任务与处理器
任务控制块或被剥 夺了任务控制块时
。 一个正在运行的
而使任务进入任等务待一状旦态响应中
的状态叫做任务的
断申请就会中止
任务的状态及其转换 睡眠状态
运行而去执行中 断服务程序,这 时任务的状态叫
做中断服务状态
系统为任务配备 了任务控制块且 在任务就绪表中 进行了就绪登记, 这时任务的状态 叫做就绪状态。
起始任务TaskStart的代码
嵌入式操作系统ucosII的中断处理过程
嵌入式操作系统ucosII的中断处理过程(上篇)转_王文罗的空...
/wangwenluo2gxy/item/da2da05e701c2bdb...
四.相关代码 与编译器相关的数据类型: 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,则可以继//续 {
第6页 共11页
2013/11/13 22:38
嵌入式操作系统ucosII的中断处理过程(上篇)转_王文罗的空...
/wangwenluo2gxy/item/da2da05e701c2bdb...
#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]对应的任务中至少有一个任务处于就绪态
ucos-ii工作原理
ucos-ii工作原理uC/OS-II(Micro C/Operating System-II)是一种用于嵌入式系统的实时操作系统。
它的工作原理可以简单归纳为以下几个步骤:1. 任务管理:uC/OS-II使用优先级调度算法管理多个任务。
每个任务都有一个优先级,高优先级的任务会优先执行。
uC/OS-II通过一个任务控制块(TCB)来管理每个任务的信息,包括任务的状态、堆栈信息、优先级等。
2. 中断处理:uC/OS-II可以处理多种类型的中断。
当发生中断时,uC/OS-II会根据中断类型进行相应的处理,并且可以自动切换到中断服务程序(ISR)进行执行。
中断服务程序中的代码通常是短小且高效的,用于处理特定的中断事件。
3. 任务切换:uC/OS-II使用抢占式的任务调度方式,因此任务切换可以发生在任何时刻。
当一个任务的时间片用尽或者有更高优先级的任务需要执行时,uC/OS-II会保存当前任务的上下文信息,并切换到下一个任务的执行。
任务切换时,uC/OS-II会保存当前任务的栈指针等信息,并从下一个任务的栈指针中恢复相应的上下文,以使下一个任务继续执行。
4. 事件同步:uC/OS-II提供了多种事件同步机制,如信号量、事件标志、消息邮箱等,用于任务之间的同步和通信。
这些机制可以帮助任务之间按照一定的顺序进行执行,实现数据共享和互斥访问等功能。
5. 内存管理:uC/OS-II提供了内存管理功能,可以动态分配和释放内存块。
这种内存管理机制可以帮助节省内存空间,提高系统的效率。
总而言之,uC/OS-II通过任务管理、中断处理、任务切换、事件同步和内存管理等机制,实现了对嵌入式系统的实时调度和资源管理,以提供稳定、可靠的操作系统支持。
- 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.执行用户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次。