基于ARM平台的UCOSII中断响应过程详解
东软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-II的任务切换机理及中断调度优化
uCOS-II的任务切换机理及中断调度优化uC/OS-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) 任务处理部分中的内容都是与任务的操作密切相关的。
包括任务的建立、删除、挂起、恢复等等。
uCOS-II中断服务程序代码分析
uC/OS-II中断服务程序代码分析在讲解uC/OS-II中断处理机制之前,大家要了解uC/OS-II中对于中断函数的处理机制。
我们在查阅《嵌入式实时操作系统μCOS-II(第二版)》书中P103页时,可以查看到在uC/OS-II中的中断处理机制如下描述:Void ISP_Function( void ){保存全部的CPU寄存器;调用OSIntEnter()或OSIntNesting++;If(OSIntNesting == 1 ){OSTCBCur->OSTCBStkPtr= SP ;}清中断源;重新打开中断;执行用户代码做中断服务;调用OSIntExit();恢复所有CPU寄存器;执行中断返回指令;}在uC/OS-II中,对于中断中的任务切换,是用两个函数实现的1、OSIntEnter()2、OSIntExit()在OSIntEnter()中将用于记录中断嵌套的计数器OSIntNesting自增1;其函数源代码如下:voidOSIntEnter (void){if (OSRunning == OS_TRUE){if (OSIntNesting < 255u){OSIntNesting++;}}这里我想提醒大家的是:uC/OS-II的程序设计思想是非常严谨的,OSIntEnter首先判断中断发生是否在uC/OS-II整个系统启动后,如果不是这样的话,那么所有的uC/OS-II的系统功能均不能提供给用户使用。
void OSIntExit(void)函数时用于在用户编写的中断服务代码执行完毕以后,调用该函数,从而实现uC/OS-II 始终保证“处于就绪状态下优先级最高的任务始终能得到系统的所有资源。
void OSIntExit(void)函数源代码如下:voidOSIntExit (void){#if OS_CRITICAL_METHOD == 3OS_CPU_SR cpu_sr = 0;#endifif (OSRunning == OS_TRUE){OS_ENTER_CRITICAL();if (OSIntNesting > 0){OSIntNesting--;if (OSIntNesting == 0){if (OSLockNesting == 0){OS_SchedNew();if (OSPrioHighRdy != OSPrioCur){OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];#if OS_TASK_PROFILE_EN > 0OSTCBHighRdy->OSTCBCtxSwCtr++;#endifOSCtxSwCtr++;OSIntCtxSw();}}}OS_EXIT_CRITICAL();}}这部分代码的意思,大家自己想一下了,这里我主要讲解一下在OS_CPU_A.a文件中的OSIntCtxSw()函数了。
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的中断过程简介系统接收到中断请求后,如果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的中断过程简介系统接收到中断请求后,如果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中,恢复被中断模式程序的工作状态。
基于ARM的_C_OS_中断机制改进
ARM 系统结构支持 7 种处理器 模式 : 用 户模 式 ( USR) 、快中断模 式 ( FIQ) 、中 断模 式 ( IRQ) 、管 理模 式 ( SVC) 、终止模式 ( AB T) 、未定义模式 ( UND) 和系统模式 ( S YS) 。当异常发生时 , CPU 自动切换运行模式 ,并跳转 至异常向量处执行 ,不同模式对应的堆栈空间也不相同 。 本文主要讨论 IRQ/ FIQ 中断异常的响应机制 。当中断请 求( IRQ) 到来使 CPU 进入中断响应时 , CPU 将会自动完 成下列操作 ( FIQ 与此类似) : 将 PC 的当前值存入中断态 的 L R ;将 CPSR 的值存入中断态的 SPSR ;改变 CPSR 中 的运行状态位 ,使 CPU 进入中断态并关闭中断 ; 然后将 PC 的值改成 0x18 ,从而使 CPU 的执行转入 0x18 。如前 所述 ,中断态也是一种特权状态 ,但是有自己的 L R 、SP 和 SPSR ,所以并不等同于管理模式 (即常说的“系统模式”) 。
6 6
2007 年第 9 期
adv @mesnet. com. cn (广告专用)
式是指根据中断的优先级进行响应 ,通过 CPU 对中断向 量控制器 ( VIC) 的优先级设置 ,屏蔽比当前优先级低 ( 包 括当前优先级) 的中断 ,响应比当前优先级高的中断 ,这样 就能准确地估计中断响应时间 。
3 μC/ OS2II 中断机制存在的问题及其改进
为了保证μC/ OS2II 的硬实时特性 ,需要对影响中断 响应速度的因素加以考查 。影响中断响应速度的因素包 括硬件因素和软件因素两类 。在特定硬件平台确定后 ,其 性能就只由软件决定 。在μC/ OS2II 原书中 ,中断响应性 能的估算公式回避了临界区保护机制对中断的干扰 。在 μC/ OS2II 中存在大量开 、关中断的代码 ,不考虑临界区保 护是不妥当的 。所以应该把开 、关中断保护限制在最小的 范围内(仅在内核代码中) ,避免应用程序使用开 、关中断 的手段 ,这样估算才有意义 。μC/ OS2II 原书第 63 页的公 式如下 :
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通过任务管理、中断处理、任务切换、事件同步和内存管理等机制,实现了对嵌入式系统的实时调度和资源管理,以提供稳定、可靠的操作系统支持。
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-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中中断实现过程
描述ucos中中断实现过程UCOS中的中断实现过程在嵌入式系统中,中断是一种常见的机制,用于处理紧急事件和响应外部设备的请求。
中断可以打破程序的正常顺序执行,将处理器的控制权转移到一个特殊的处理函数,在完成相关任务后再返回到被中断的位置。
在本文中,我们将详细讨论UCOS中中断的实现过程,从中断的触发到处理函数的执行,以及恢复正常程序执行的过程。
一、中断的概念和分类在开始讨论UCOS中的中断实现过程之前,我们先了解一下中断的概念和分类。
中断是指在程序正常执行的过程中,由于硬件或软件的触发,使处理器暂时停下目前正在执行的任务,转而去执行一个特定的中断服务程序。
中断可以分为外部中断和内部中断两种类型。
1. 外部中断:外部中断是由外部设备触发的,如按键的按下、定时器的溢出等。
外部中断需要通过硬件电路来检测和触发,然后通过中断控制器将中断请求信号发送给处理器。
2. 内部中断:内部中断是由处理器内部的异常或错误触发的,如除零错误、非法指令执行等。
内部中断是由处理器内部的各种异常检测电路自动触发的。
UCOS中的中断实现过程主要是针对外部中断的,它涉及到如何检测和响应外部中断请求,并且在中断处理函数执行完成后,恢复正常的程序执行顺序。
二、UCOS中的中断处理器UCOS中的中断处理器是使用硬件中断控制器来检测和响应外部中断请求的。
硬件中断控制器的作用是将外部中断请求信号转换为中断向量,并将处理器的控制权转移到对应的中断处理函数。
UCOS可以使用多种硬件中断控制器,如8259A芯片、PIC芯片、ARM 内核自带的中断控制器等。
具体使用哪种硬件中断控制器,取决于嵌入式系统的硬件架构和具体需求。
实现中断处理的第一步是配置硬件中断控制器,使其能够正确检测和响应外部中断请求。
相关配置包括中断优先级设置、中断请求触发方式、中断控制器的初始化等。
三、UCOS中的中断向量表中断向量表是用来存放中断处理函数地址的数据结构,每个中断向量表项对应一个外部中断请求。
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中断处理过程详解
再看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。
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。
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里的时候了。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
FOR STUDY
3
2009-8-11
Nil.Ryan
版本:1.0
MRS temp, SPSR ORR temp, temp, #NoInt MSR SPSR_c, temp } OsEnterSum++; break; ………………………………………………
问题:SWI_Exception 函数的参数是如何传递的? 【提示:汇编和 C 语言之间传递参数一般是用 R0~R3,当参数超过 4 个时,会使用堆栈辅 助进行参数传递;】
LDR PC, FIQ_Addr
Reset_Addr Undef_Addr SWI_Addr PAbt_Addr DAbt_Addr
FIQ_Addr
DCD Reset_Handler DCD Undef_Handler DCD SoftwareInterrupt DCD PAbt_Handler DCD DAbt_Handler DCD 0xB9206E28 DCD FIQ_Handler
中断向量表可以在启动文件(一般是 startup.s 文件)中找到:
Vectors
LDR PC, Reset_Addr
LDR PC, Undef_Addr
LDR PC, SWI_Addr
LDR PC, PAbt_Addr
LDR PC, DAbt_Addr
NOP
; Reserved Vector
LDR PC, [PC, #-0x0120] ; Vector from VicVectAddr
FOR STUDY
2
2009-8-11
Nil.Ryan
版本:1.0
一 前言
本文主要描述给予 KEIL MDK 和 LPC2000 系列 ARM 芯片的 UCOSII 系统的中断响应 过程;从中断的性质上区分,主要分为两部分:软中断和硬件中断;
中断是一种机制,用于通知 CPU 某个异步事件发生了。中断一旦被系统识别,CPU 则 保存部分(或全部)现场(context),即部分(或全部)寄存器的值,然后跳转到专门的子程序, 称为中断服务子程序(ISR)。中断服务子程序做事件处理,处理完成后执行任务调度,程序 回到就绪态优先级最高的任务开始运行(对于可剥夺型内核)。
2. 软中断的作用
软中断可以用于用户模式下的程序调用特权操作指令, 在实时操作系统中可以通过该 机制实现系统调用。软中断也可以用于系统的各种异常处理;在没有软中断机制的平台上运 行操作系统是一件不可想象的事情;
3. 软中断与硬件中断的区别
软中断是软件实现的中断,也就是程序运行时其他程序对它的中断;而硬件中断是硬件实现的 中断,是程序运行时设备或模块对它的中断。 (1) 软中断发生的时间是由程序控制的,而硬中断发生的时间是随机的 (2) 软中断是由程序调用发生的,而硬中断是由外设引发的
CMP LDRLO LDREQ
R0, #1 PC, =OSIntCtxSw PC, =__OSStartHighRdy
; 中断前是否是 Thumb 状态 ; 是: 取得 Thumb 状态 SWI 号 ; 否: 取得 arm 状态 SWI 号 ; r0 = SWI 号,R1 指向参数存储位置
; SWI 0x01 为第一次任务切换
switch(SWI_Num) {
//case 0x00: // break; //case 0x01: // break; case 0x02:
__asm {
/* 任务切换函数 OS_TASK_SW,参考 os_cpu_s.s 文件 */ /* 启动任务函数 OSStartHighRdy,参考 os_cpu_s.s 文件 */ /* 关中断函数 OS_ENTER_CRITICAL(),参考 os_cpu.h 文件 */
BL
SWI_Exception
LDMFD SP!, {R0-R3, R12, PC}^
进入 SoftwareInterrupt 函数后,首先进行任务环境的保护,然后读取软中断的功能号(软 中断的功能号在指令代码中,而指令代码的地址可以根据 PC 指针的返回地址寄存器来推算 出来);接下来就通过功能号跳转到不同的功能代码中执行; 通过指令 CMP R0, #1,将保存在 R0 寄存器中的功能号跟 1 比较: ¾ 如果小于 1,则功能号是 0,则执行指令【LDRLO PC, =OSIntCtxSw】,即实现任务切
/* 运行优先级最高的任务
*/
__swi(0x02) void OS_ENTER_CRITICAL(void);
/* 关中断
*/
__swi(0x03) void OS_EXIT_CRITICAL(void);
/* 开中断
*/
__swi(0) void *GetOSFunctionAddr(int Index); /* 获取系统服务函数入口
*/
__swi(0x41) void *GetUsrFunctionAddr(int Index); /* 获取自定义服务函数入口 */
__swi(0x42) void OSISRBegin(void);
/* 中断开始处理
*/
__swi(0x43) int OSISRNeedSwap(void);
/* 判断中断是否需要切换
; Reserved Address
从上面的代码我们可以看出,程序触发软中断指令后,最终会跳转到 SoftwareInterrupt
函数中;
在 OS_CPU_A.S 文件中,我们可以找到 SoftwareInterrupt 的实现代码:
;软件中断
SoftwareInterrupt
LDR SP, StackSvc
*/
(2) 以 OS_ENTER_CRITICAL(void)为例介绍具体响应过程
OS_ENTER_CRITICAL(void)是我们在嵌入式应用层变成中常用的一个功能;当我们调用该
函数时,系统执行__swi(0x02)功能;也就是在中断向量表中找到软中断的入口地址,然后
转向功能号为 2 的中断服务子程序;
注:UCOS 系统下,中断实现的方式有多种,不同的实现方式,代码的效率不同,本文只介 绍其中比较常见的一种实现方式的中断响应过程;
二 软中断
1. 什么是软中断
软中断目前偶还没找到官方的定义,软中断应该是指软中断机制,这个是模仿硬件中 断的思想,通常意义上是指由软件指令产生的中断;也就是通过执行一条指令,来通知 CPU 模拟一次中断过程;如 X86 架构的 INT 指令、ARM 架构的 SWI 指令等;
SWI_Exception 函数的部分代码如下:
void SWI_Exception(int SWI_Num, int *Regs)
{
OS_TCB *ptcb; unsigned int temp;
//以前的 keil for 2.5 或 ADS1.2 下,这个是不用这样子定义的 //直接用 R0 即可,,
FOR STUDY
1
2009-8-11
Nil.Ryan
版本:1.0
4. 软中断的响应过程
(1)首先看一下我们定义了那些软中断
在 OS_CPU.H 文件中,我们可以找到以下定义:
__swi(0x00) void OS_TASK_SW(void);
/* 任务级任务切换函数
*/
__swi(0x01) void _OSStartHighRdy(void);
1. 什么是软中断......................................................................................................................1 2. 软中断的作用......................................................................................................................1 3. 软中断与硬件中断的区别..................................................................................................1 4. 软中断的响应过程..............................................................................................................2 三 硬件中断...................................................................................................................................4 1. 什么是硬件中断..................................................................................................................4 2. 硬件中断的作用..................................................................................................................4 3. 硬件中断的分类..................................................................................................................4 4. 硬件中断的响应过程..........................................................................................................5 四 补充说明.................................................................................................................................10