uCOS中断处理过程详解
Ucos学习之中断的应用
在线学习好工作/Ucos学习之中断的应用在正常的情况下,是我们的主程序在运行,也就是我们的任务在运行,假设我们的主程序运行到某个地方的时候,产生了中断请求,产生了中断请求以后,CPU 来响应这个中断,它在响应这个中断之前呢,首先要做一件事就是现场的保护,这个很好理解,为什么这样呢?因为当我们在执行完中断函数以后,我们还有退回到原来的主函数中去,开始接着往下执行,那这样的话,必须保护这个现场,如果不保护这个现场,我们以后从中断函数退出的时候,那捏怎么知道从什么地方执行呢?所以,在这里,我们中断函数以后,要进行一个现场的保护。
现场保护要做的是什么事情呢?实际上就是保护CPU集成器,现场保护以后,CPU就转入中断函数执行,这个时候,就执行中断,执行中断也叫做ISR,执行完ISR以后,接下来我们要回到主程序执行,那它们之间的过程刚好是个相反的过程。
刚刚我们进行了一个现场保护,那么现在我们要进行一个现场恢复,恢复完现场以后,接下来我们要干的事情就是执行主程序,这个是我们整个中断的过程。
1)中断延迟中断延迟指的是,从产生中断开始,到执行第一条中断函数,这个时间被称作中断延迟时间。
也就是说,从这一时刻,我开始产生中断请求,到另一个时刻,我才执行中断函数,那么这段时间,就被称做中断延迟。
在这个中断延迟中,它都干了些什么事情,实际上就是一个CPU的现场保护。
2)中断响应比如说,某一个事件产生了,那件产生了多长时间以后才会来响应这个事件,这个就叫做中断响应过程,中断响应和中断延迟是有一定的区别的。
我们刚刚说中断延迟是从产生到延迟到执行第一条中断函数服务,而中断响应指的是产生中的请求然后到对这个中断进行处理,这个时间叫做中断响应。
3)中断恢复中断恢复指的是这个中断函数执行完毕以后到我们的主程序去执行这一段时间就是中断恢复的时间。
在我们不带操作系统的开发当中,也就是逻辑开发当中,我们中断延迟和中断响应是一样的。
假设我们跑了操作系统以后,跑了一个OS以后,我们看一下这个会变成什么样。
ucos开关中断
为了处理临界区代码,必须关中断,等处理完毕后,再开中断。
关中断可以避免其他任务或中断进入临界区代码。
uC/OS-II定义了这两个宏来实现,但注意一条:调用uC/OS-II 功能函数时,中断应该总是开着的。
1)当OS_CRITICAL_METHOD= = 1时,简单实现如下:#define OS_ENTER_CRITICAL() disable_int()#define OS_EXIT_CRITICAL() enable_int()但这样有一个问题,如果禁止中断的情况下调用uC/OS-II功能函数,那么从功能函数返回时,中断可能变成允许的了,而实际上还是希望是禁止的。
2)当OS_CRITICAL_METHOD= = 2时,实现如下:#define OS_ENTER_CRITICAL()asm(“PUSH PSW”);asm(“DI”);#define OS_EXIT_CRITICAL()asm(“POP PSW”);执行OS_ENTER_CRITICAL()时,先将中断状态保存到堆栈,然后关中断;执行OS_EXIT_CRITICAL()时,再从堆栈中恢复原来的中断开/关状态。
这种方法不会改变中断状态,避免前面的问题。
3)当OS_CRITICAL_METHOD= = 3时,实现如下:#define OS_ENTER_CRITICAL()cpu_sr = get_processor_psw();disable_interrupts();#define OS_EXIT_CRITICAL()set_ processor_psw(cpu_sr);====================这里注意的是OS_CRITICAL_METHOD ,ucos提供了3种方法实现,第一种方法是直接简单的开关中断方式,但是一旦嵌套会发生意外,比如:view plaincopy to clipboardprint? .........10........20........30........40........50........60........70........80........90........100.......110.......120.......130.......140. (150)void Task (void *data).........OS_ENTER_CRITICAL();//进入临界区1//调用了某一函数,该函数也需要进入临界区:{OS_ENTER_CRITICAL();................OS_EXIT_CRITICAL();}//这里就自然变成废墟了...........//临界区切掉OS_EXIT_CRITICAL();}void Task (void *data){.........OS_ENTER_CRITICAL();//进入临界区1//调用了某一函数,该函数也需要进入临界区:{OS_ENTER_CRITICAL();................OS_EXIT_CRITICAL();}//这里就自然变成废墟了...........//临界区切掉OS_EXIT_CRITICAL();}此方法太多弊端,所以新内核中看不到她的影子了于是出现第二种方法,执行OS_ENTER_CRITICAL()时首先保存中断状态到堆栈中,然后关中断,执行OS_EXIT_CRITICAL()时,再从堆栈中恢复原来的中断开/关状态。
实验六 uCOS的中断与时钟
实验六中断与时钟一:实验目的:系统响应中断的过程是:系统接收到中断请求后,如果这时CPU处于中断允许状态,系统就会终止正在运行的当前任务,而按照中断向量的指向转而去运行中断服务子程序;当中断服务子程序运行结束后,系统就会根据情况返回到被终止的任务继续运行,或者转向另一个具有跟高优先级的就绪任务。
二:实验内容:完成教材4-2的实验内容,观察结果,掌握时钟与中断机制。
#include "includes.h"#define TASK_STK_SIZE 512OS_STK MyTaskStk[TASK_STK_SIZE];OS_STK YouTaskStk[TASK_STK_SIZE];OS_STK InterTaskStk[TASK_STK_SIZE];INT16S key;INT8U x=0,y=0;BOOLEAN InterKey=FALSE;char *s = "运行了中断所要求运行的任务InterTask。
";voidMyTask(void *data);voidYouTask(void *data);voidInterTask(void *data);/***************************主函数**********************/void main(void){char * s_M="M";OSInit();PC_DOSSaveReturn();PC_VectSet(uCOS,OSCtxSw);OSTaskCreate(MyTask,s_M,&MyTaskStk[TASK_STK_SIZE-1],);OSStart();}/***********************任务MyTask******************/ voidMyTask(void *pdata){char* s_Y="Y";char* s_H="H";#if OS_CRITICAL_METHOD == 3;OS_CPU_SR cpu_sr;#endifINT8U err;pdata = pdata;OS_ENTER_CRITICAL();PC_VectSet(0x08,OSTickISR);PC_SetTickRate(OS_TICKS_PER_SEC);OS_EXIT_CRITICAL();OSTaskCreate(YouTask,s_H,&YouTaskStk[TASK_STK_SIZE-1],1);OSTaskCreate(InterTask,s_M,&InterTaskStk[TASK_STK_SIZE-1],2);for(;;){if(x>50){x=0;y+=2;}PC_DispChar(x,y,*(char *)pdata,DISP_BGND_BLACK+DISP_FGND_WHITE);x+=1;if(PC_GetKey(&key)==TRUE){if(key==0x1B){PC_DOSReturn();}}OSTimeDlyHMSM(0,0,3,0);}}/***********************************************************************/ voidYouTask(void * pdata){# if OS_CRITICAL_METHOD==3OS_CPU_SR cpu_sr;#endifpdata=pdata;for(;;){if(x>50){x=0;y+=2;}PC_DispChar(x,y,*(char *)pdata,);x+=1;OSTimeDlyHMSM(0,0,1,0);}}/************************************************************/ voidInterTask(void * pdata){# if OS_CRITICAL_METHOD==3OS_CPU_SR cpu_sr;#endifpdata=pdata;for(;;){if(InterKey){if(x>50){x=0;y+=2;}PC_DispChar(x,y,*(char *)pdata,DISP_BGND_BLACK+DISP_FGND_WHITE);PC_DispStr(5,6,s,DISP_BGND_BLACK+DISP_FGND_WHITE);x+=1;}InterKey=FALSE;OSIntNesting--;OSTimeDlyHMSM(0,0,1,0);}}/***********************************************************************/ extern BOOLEAN InterKey;INT16U InterCtr=0;voidOSTimeTickHook(void){if(InterCtr==10000){InterKey=TRUE;}InterCtr++;}将os_cpu_c.c文件中的以下代码:#if OS_CPU_HOOKS_EN > 0void OSTimeTickHook (void){}#endif改为:#if OS_CPU_HOOKS_EN > 0extern BOOLEAN InterKey;INT16U InterCtr=0;voidOSTimeTickHook(void){if(InterCtr==10000){InterKey=TRUE;}InterCtr++;}#endif程序分析:程序运行时,按照优先级的高低,先运行MyTask,输出字符串:MyTask。
ucos 串口中断接收写法
ucos 串口中断接收写法UCOS(Micrium公司所开发的一款实时操作系统)是一款非常灵活的嵌入式操作系统,在嵌入式系统中广泛应用。
在UCOS中使用串口中断来接收数据可以极大地提高系统的响应速度和效率。
本文将逐步介绍UCOS中串口中断接收数据的实现方法和写法。
一、UCOS的基本概念与串口中断的作用UCOS是一种多任务实时操作系统,被广泛应用于嵌入式系统中。
它具有高度的可移植性和可扩展性,能够满足各种不同的应用需求。
串口中断是嵌入式系统中常用的通信方式之一,其作用是在数据传输过程中,当接收到数据时立即通知操作系统进行处理,提高系统的实时性和效率。
串口中断接收数据的写法可以通过编写中断处理函数来实现。
二、编写串口中断接收数据的准备工作在开始编写串口中断接收数据之前,需要进行一些准备工作:1. 确定串口通信参数:包括波特率、数据位数、停止位等。
这些参数需要与通信的发送端保持一致。
2. 初始化串口:通过设置串口通信模块的相应寄存器来初始化串口。
3. 编写中断处理函数:中断处理函数负责接收串口中断产生的数据,并进行相应处理。
三、编写串口中断接收数据的步骤下面将详细介绍UCOS中串口中断接收数据的写法步骤:1. 创建串口中断接收任务:在UCOS中,每个任务都是一个独立的实体,需要通过创建任务的方式来执行相应的任务。
首先,创建一个任务来执行串口接收数据的相关操作。
2. 初始化串口:在任务中,首先需要进行串口的初始化操作,确保串口模块能够正常工作。
将串口通信所需的参数设置好,并通过相应寄存器进行配置。
3. 创建中断处理函数:UCOS提供了中断处理函数的接口,在其中进行串口接收数据的处理。
在中断处理函数中,首先判断是否为接收中断,并判断接收寄存器是否有数据可读。
如果有数据可读,则将数据保存到缓冲区中,并在接收完成后通知任务进行数据处理。
4. 任务处理数据:当中断处理函数接收到数据后,需要通知相应的任务来处理数据。
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处于开中断状态,系统就会中止正在运行的当前任务,而按中断向量的指向去运行中断服务子程序,当中断服务子程序运行完成后,系统会根据具体情况返回到被中止的任务继续运行,或转向另一个中断优先级别更高的就绪任务。
由于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”的原因==避免调整堆栈指针.出现这个问题的根源是当低优先级的任务被中断,当中断完成后由于有高优先级的任务就绪,则必须调度高优先级的任务,原来的低优先级任务继续被中断着,但是此时的低优先级任务的堆栈已经被破坏,已不能被调度程序直接调度了,要想被调度而必须调整堆栈指针。
ucosIII中断、临界区与时间管理
ucosIII中断、临界区与时间管理中断:应内部或外部异步事件的请求中止当前任务,而去处理异步事件所要求的任务的过程叫做中断。
void USART1_IRQHandler(void){OSIntEnter();//中断服务程序OSIntExit();}•1•2•3•4•5•6void OSIntEnter (void){if (OSRunning != OS_STATE_OS_RUNNING) {//用于确定系统是否正常运行return}if (OSIntNestingCtr >= (OS_NESTING_CTR)250u) {return;}OSIntNestingCtr++;//中断嵌套的层数}•1•2•3•4•5•6•7•8•9•10OSIntNestingCtr来记录中断嵌套次数,UCOSIII最多支持250级的中断嵌套。
退出中断服务函数时要调用函数OSIntExit()。
退出函数内部步骤如下:1.系统是否运行。
不符合则退出2.关闭全局中断3.中断嵌套次数和任务切换次数记录4.进行中断级任务切换void OSIntExit (void){CPU_SR_ALLOC();//宏定义的CPU_SRif (OSRunning != OS_STATE_OS_RUNNING) { /* Has the OS started? */return; /* No */ }/*关闭全局中断,包括关闭滴答定时器中断*/CPU_INT_DIS();if (OSIntNestingCtr == (OS_NESTING_CTR)0) { /*Prevent OSIntNestingCtr from wrapping */CPU_INT_EN();return;}OSIntNestingCtr--;//中断嵌套次数if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* ISRsstill nested? */CPU_INT_EN(); /* Yes */return;}/*OSSchedLockNestingCtr 调度器是否加锁的标志*/if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) { /* Scheduler still locked? */CPU_INT_EN(); /* Yes */return;}/*获得最高优先级的任务*/OSPrioHighRdy = OS_PrioGetHighest(); /* Findhighest priority */OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr;/* Get highest priority task ready-to-run */if (OSTCBHighRdyPtr == OSTCBCurPtr) { /* Currenttask still the highest priority? */CPU_INT_EN(); /* Yes */return;}#if OS_CFG_TASK_PROFILE_EN > 0uOSTCBHighRdyPtr->CtxSwCtr++; /* Inc. # of context switches for this new task */#endifOSTaskCtxSwCtr++; //任务切换的次数 /* Keep track of the total number of ctx switches */#if defined(OS_CFG_TLS_TBL_SIZE) && (OS_CFG_TLS_TBL_SIZE > 0u)OS_TLS_TaskSw();#endif/*中断级任务调度*/OSIntCtxSw(); /* Perform interrupt level ctx switch */CPU_INT_EN();}•1•2•3•4•5•6•7•8•9•10•11•12•13•14 •15 •16 •17 •18 •19 •20 •21 •22 •23 •24 •25 •26 •27 •28 •29 •30 •31 •32 •33 •34 •35 •36 •37 •38 •39 •40 •41 •421.临界段代码也叫做临界区,是指那些必须完整连续运行,不可被打断的代码段。
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。
描述ucos中中断实现过程
描述ucos中中断实现过程UCOS中的中断实现过程在嵌入式系统中,中断是一种常见的机制,用于处理紧急事件和响应外部设备的请求。
中断可以打破程序的正常顺序执行,将处理器的控制权转移到一个特殊的处理函数,在完成相关任务后再返回到被中断的位置。
在本文中,我们将详细讨论UCOS中中断的实现过程,从中断的触发到处理函数的执行,以及恢复正常程序执行的过程。
一、中断的概念和分类在开始讨论UCOS中的中断实现过程之前,我们先了解一下中断的概念和分类。
中断是指在程序正常执行的过程中,由于硬件或软件的触发,使处理器暂时停下目前正在执行的任务,转而去执行一个特定的中断服务程序。
中断可以分为外部中断和内部中断两种类型。
1. 外部中断:外部中断是由外部设备触发的,如按键的按下、定时器的溢出等。
外部中断需要通过硬件电路来检测和触发,然后通过中断控制器将中断请求信号发送给处理器。
2. 内部中断:内部中断是由处理器内部的异常或错误触发的,如除零错误、非法指令执行等。
内部中断是由处理器内部的各种异常检测电路自动触发的。
UCOS中的中断实现过程主要是针对外部中断的,它涉及到如何检测和响应外部中断请求,并且在中断处理函数执行完成后,恢复正常的程序执行顺序。
二、UCOS中的中断处理器UCOS中的中断处理器是使用硬件中断控制器来检测和响应外部中断请求的。
硬件中断控制器的作用是将外部中断请求信号转换为中断向量,并将处理器的控制权转移到对应的中断处理函数。
UCOS可以使用多种硬件中断控制器,如8259A芯片、PIC芯片、ARM 内核自带的中断控制器等。
具体使用哪种硬件中断控制器,取决于嵌入式系统的硬件架构和具体需求。
实现中断处理的第一步是配置硬件中断控制器,使其能够正确检测和响应外部中断请求。
相关配置包括中断优先级设置、中断请求触发方式、中断控制器的初始化等。
三、UCOS中的中断向量表中断向量表是用来存放中断处理函数地址的数据结构,每个中断向量表项对应一个外部中断请求。
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。
ucos中断处理和时间管理
取消延时函数
延时的任务可以不等延时期满,而是通过其
他任务取消延时而使自己进入就绪状态。
取消延时函数为:
INT8U OSTimeDlyResume( INT8U prio);
INT8U OSTimeDlyResume (INT8U prio) {
OS_TCB *ptcb; 。。。。。。
判断优先级是否有效
三、配置中断源和向量中断控制器
1、中断源初始化: 以定时器1为例,让产生周期为10ms的中断 的参数配置如下:
T1IR = 0xFFFFFFFF; T1TC = 0x00; T1PR = 0x00; T1TCR = 0x01; T1MCR = 0x03; //匹配时产生中断并复位定时器1 T1MR0 = Fpclk/100; //定时时间为10ms
μC/OS-II 用硬件定时器产生一个周期为 ms 级的周期性中断来实现系统时钟,时钟 节拍(Time Tick)就是两次中断之间相间 隔的时间。 硬件定时器以时钟节拍为周期定时地产 生中断,该中断的中断服务程序叫做 OSTickISR( )。中断服务程序通过调用函数 OSTimeTick( )来完成系统在每个时钟节拍 时需要做的工作(如确定任务延时时间是 否结束或等待事件的时限是否已到?。
函数OSTimeTick( )的 任务,就是在每个时 钟节拍了解每个任务 的延时状态,使其中 已经到了延时时限的 非挂起任务进入就绪 状态。
时间服务函数
问题:如何使优先级高 的任务不独占CPU,给其他 任务优先级别较低的任务获 得CPU使用权的机会?
调用延时函数OSTimeDly( ),使当前任 务的延时(暂停)一段时间并进行一次 任务调度,以让出CPU的使用权。 调用挂起函数OSTaskSuspend( ),使当前 任务挂起并进行一次任务调度,以让出 CPU的使用权。 调用等待事件函数OSXXXPend( ),使当 前任务等待某一事件发生并进行一次任 务调度,以让出CPU的使用权。
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是一个源码藏匿、可移植、可固化、可剪裁和抢占式的实时多任务操作系统,其大部分源码是用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与中断(按键)
CPU 处注于意中!断中允断许服状务态 子( 即程中序断运是行结束
开 的μ放当C的前之次/)任O后任S,务-,务系 ,I调系I统 而系度统就 按统去将会 照运会中 中行根止 断正 向优据在 量先情运 的级况行指别进最行高一
向转而的去就运绪行任中务断响,服而应务并子中程不断序是的;一当过定程要接
任务切换过程 其实,调度 根据就绪表获得
器在进行调 获 待得 运待 行运 任行 务任 的务任 度时,在这 的 务任 控务 制控 块制 指块 针
个位置还要
进行一下判 断:究竟是 待运行任务
处理器的SP=任 务块中保存的SP
是否为当前 任务,如果 是,则不切
恢复待运行任务 的运行环境
换;如果不
是才切换, 处理器的PC=任
UCOSII与中断(按键) 控制LED
毛德明 142460389
任务运行时与 处理器之间的关系
运行环境包括了两部分: 处理器中的运行环境和
内存中的处运理行器环境
PC
寄存器组
内存 任务代码
SP 处理器通过两个指针寄存
任务堆栈
器(PC和SP)来与任务 程序运行环境 代码和任务堆栈建立联系
并运行它
多任务时任务与处理器
任务控制块或被剥 夺了任务控制块时
。 一个正在运行的
而使任务进入任等务待一状旦态响应中
的状态叫做任务的
断申请就会中止
任务的状态及其转换 睡眠状态
运行而去执行中 断服务程序,这 时任务的状态叫
做中断服务状态
系统为任务配备 了任务控制块且 在任务就绪表中 进行了就绪登记, 这时任务的状态 叫做就绪状态。
起始任务TaskStart的代码
ucos 时钟中断处理
//中断退出函数OSInitExit(),标志着中断服务子程序的终结void OSInitExit(void){#if OS_CRITICAL_METHOD==3OS_CPU_SR cpu_sr;#endifif(OSRunning==TRUE){OS_ENTER_CRITICAL();if(OSIntNesting>0){OSIntNesting--; //中断嵌套层数计算器减一}if((OSIntNesting==0)&&(OSLockNesting==0)){//所有ISR 执行完毕,而且调度没有加锁,则进行重现调度OSIntExitY=OSUnMapTbl[OSRdyGrp]; //OSUnMapTbl是优先级判定表 OSPrioHighRby=(INT8U)((OSIntExitY<<3)+OSUnMapTbl[OSRdyTbl[OSIntExitY]]);if(OSPrioHighRby!=OSPrioCur){//若当前任务不是最高优先级任务OSTCBHighRby=OSTCBPrioTbL[OSPriohighRby];OSCtxSwCtr++;//保持对上下文切换次数的记录OSIntCtxSw();//进行中断级的上下文切换,OSIntCtxSw()}}OS_EXIT_CRITICAL();}}//C 语言时钟节拍函数OSTimeClick()void OSTimeTick(void){OS_TCB *ptcb;OSTimeTickHook(); //用户定义的时钟节拍接口函数ptcb=OSTCBList; //ptcb指向TCB 的头while(ptcb->OSTCBPrio!=OS_IDLE_PRIO){//遍历TCB 联表中的每一个TCBOS_ENTER_CRITICAL();if(ptcb->OSTCBDly!=0){//对节拍延时计算值没有达到零的任务的处理if(--ptcb->OSTCBDly==0){//对延时计算减一,若计数结束则满足条件if(!(ptcb->OSTCBStat&OS_STAT_SUSPEND))//判断是否挂起{OSRdyGrp|=ptcb->OSTCBBitY; //没有被挂起OSRdyTbl[ptcb->OSTCBY]|=ptcb->OSTCBBitX;//}else//确实被挂起的任务不会进入就绪态{ptcb->OSTCBDly=1;//使能再次判断挂起任务是否解除了挂起}}}ptcb=ptcb->OSTCBNext;//联表指针指向下一个TCBOS_EXIT_CRITICAL();}OS_ENTER_CRITICAL();OSOSTime++; //32位数加1操作通常使用多条指令,为临界区OS_EXIT_CRITICAL();}//任务延时函数void OSTimeDly(INT16U ticks){#if OS_CRITICAL_METHOD==3OS_CPU_SR cpu_sr;#endifif(ticks>0) //指定0值,则表明用户不想延时任务,函数立即返回到调用者{OS_ENTER_CRITICAL();if((OSRdyTbl[OSTCBCur->OSTCBY]&=~OSTCBCur->OSTCBBitX)==0) //将当前任务从就绪表中移除{OSRdyGrp&=~OSTCBCur->OSTCBBitY;}OSTCBCur->OSTCBDly=ticks; //延时节拍数会被保存在当期的OS—TCB中OS_EXIT_CRITICAL();OS_Sched(); //任务调度程序}}//任务延时函数,可提供更好的交互性INT8U OSTimeDlyHMSM(INT8U hours,INT8U minutes,INT8U seconds,INT16U milli){INT32U ticks;INT16U loops;if(hours>0||minutes>0||seconds>0||milli>0){if(minutes>59){return (OS_TIME_INVALID_MINUTES);}if(seconds>59){return (OS_TIME_INVALID_SECONDS);}if(milli>999){return (OS_TIME_INVALID_MILLI);}ticks=((INT32U)hours*3600L+(INT32U)minutes*60L+(INT32U)seconds)*OS_TICKS_PER_SEC+OS_TICKS_PE R_SEC*((INT32U)milli+500L/OS_TICKS_PER_SEC)/1000L;loops=(INT16U)(ticks/65536L);ticks=ticks%65536L;OSTimeDly((INT16U)ticks);while(loops>0){OSTimeDly(32768);OSTimeDly(32768);loops--;}return (OS_NO_ERR);}return (OS_TIME_ZERO_DLY);};基S3C44BOX 处理器硬件平台的OSTickISR汇编程序.GLOBAL OSTickISRSTMDB SP!,{R0-R11,LR}; 保存寄存器的值到栈MRS R0,CPSR; 以下三条指令是关中断,置I 位为1ORR R0,R0,#0x80msr,CPSR_cxsf,R0LDR R0,=I_ISPC 把IRQ模式下的中断悬挂寄存器I_ISPR地址存入R0的寄存器LDR R1,=BIT_TIMER0; BIT_TIMER0是定时器0的写入位,在头文件中定义STR R1,[R0] 定时器0的中断服务悬挂位被清BL IrqStart 中断计数BL OSTimeTick 检查所有被延时的进程控制块,将延时节拍计数减1BL OSIntEXIT 退出中断,检查有无优先级更高的程序已经就绪,如果有,则置变量need_to_swap_context-1LDR R0,=need_to_swap_context 取变量need_to_swap_context的地址LDR R2,[R0] 将变量need_to_swap_context存入R0CMP R2,#1比较need_to_swap_context是否为1LDREQ PC,=_CTX_SW; 如果是则跳转到_CTX_SW,进行上下文切换_NOT_CTX_SW 无须进行上下文切换LDMIA SP!,{R0-R11,LR} 恢复寄存器的值SUBS PC,LR,#4 OSTickISR函数返回,返回地址等于LR -4_CTX_SW 进行上下文切换MOV R1,#0将变量need_to_swap_context置为0STR R1,[R0]现在进行上下文切换LDMIA SP!,{R0-R11,LR} 恢复寄存器的值和堆栈指针SUB LR,LR,#4返回地址等于LR-4STR LR,SAVED_LR 保存被抢占程序的返回地址到标SAVED_LR所在的字MRS LR,SPSR 用4条指令切换管理SVC模式AND LR,LR,#OXFFFFFFE0ORR LR,LR,#Ox13MSR CPSR_CXSF,LR现在进入SVC管理模式STR R12,[SP,#-8] 暂时保存R12到栈指针-8的位置LDR R12,SAVED_LR 从标号SAVED_LR的内存位置取被抢占任务PC到R12STMFD SP!,{R12} 将R12(原任务的PC)存放到栈区SUB SP,SP,#4将栈指针下移一个元素,指向暂存R12字的位置LDMIA SP!,{R12} 恢复R12寄存器的值,SP上移1个单元STMFD SP!,{LR} 保存被抢占任务的连接寄存器LRSTMFD SP!,{R0-R12} 保存被抢占任务的R0-R12MRS R4,CPSRSTMFD SP!,{R4} 保存CPSRMRS R4,SPSRSTMFD SP!,{R4} 保存SPSR以下四条指令完成OSPrioCur=OSPrioHighRbyLDR R4,addr_OSPrioCurLDR R5,addr_OSPrioHighRdyLDRB R6,[R5]STRB R6,[R4]以下三条指令完成将当前任务栈指针Sp存放到被抢占任务的TCB 中LDR R4,addr_OSTCBCurLDR R5,[R4]LDR SP!,[R5] 将SP保存在被抢占任务的TCB第一个字段以下三条指令得到最高优先级任务的TCB地址,并将它存入SP寄存器LDR R6,addr_OSTCBHighRbyLDR R6,[R6]LDR SP,[R6]以下单条指令实现了TCB指针的福祉操作:OSTCBCur=OSTCBHighRdySTR R6,[R4] 将抢占任务的TCB指针值给当前任务TCB 指针LDMFD SP!,{R4} 恢复SPSRMSR SPSR_cxsf,R4LDMFD SP!,{R4} 恢复CPSRMSR CPSR_cxsf,R4LDMFD SP!,{R0-R12,LR,PC} 恢复寄存器R0-r12,LR和PC,执行抢占任务的执行函数。
ucos 串口中断接收写法 -回复
ucos 串口中断接收写法-回复UCOS是一个实时操作系统,可以用于嵌入式系统中。
在嵌入式系统中,串口中断接收是一种重要的通信方式,可以实现设备之间的数据传输。
本文将详细介绍UCOS中串口中断接收的写法,包括初始化串口口,配置中断,处理接收数据等步骤,以帮助读者理解和使用串口中断接收功能。
第一步,初始化串口口:在UCOS中使用串口中断接收前,需要先对串口进行初始化。
初始化过程包括:1. 引入相关头文件:首先,在代码开头的地方引入与串口相关的头文件,如"uart.h"。
2. 设置串口参数:设置串口的波特率、数据位、校验位和停止位等参数。
这些参数需要根据具体的应用场景进行设置。
3. 打开串口:通过调用相关的接口函数,打开待使用的串口口。
例如,可以调用"uart_open()"函数打开串口口。
第二步,配置中断:在UCOS中使用串口中断接收时,需要配置中断。
具体配置中断的步骤包括:1. 设置中断优先级和中断向量:在代码中设置中断的优先级和中断向量。
中断优先级决定了中断的处理顺序,中断向量则用于指定中断处理函数的入口地址。
2. 定义中断处理函数:在代码中定义中断处理函数,用于处理串口接收中断。
中断处理函数的定义格式通常为"void UART_IRQHandler(void)",其中"UART_IRQHandler"是用户自定义的函数名。
3. 注册中断处理函数:通过调用相关的接口函数,将中断处理函数注册到中断向量表中。
例如,可以调用"NVIC_RegisterIRQHandler()"函数来注册中断处理函数。
第三步,处理接收数据:在UCOS中,串口接收中断发生后,需要编写代码来处理接收到的数据。
处理接收数据的步骤包括:1. 判断接收数据是否有效:在中断处理函数中,首先需要判断接收到的数据是否有效。
有效性判断的方式可以根据具体的应用需求来定制,如是否满足数据长度、是否是正确的数据格式等。
ucos 串口中断接收写法 -回复
ucos 串口中断接收写法-回复UCOS是一个嵌入式操作系统,它可以在各种硬件平台上运行。
在嵌入式系统中,串口是一种常用的通信接口。
串口中断接收是一种实现串口通信的方法之一,它可以提高系统的实时性和可靠性。
本文将从串口中断接收的原理、UCOS中的串口中断接收函数、编写UCOS串口中断接收的步骤等方面,详细介绍UCOS中串口中断接收的写法。
一、串口中断接收的原理串口中断接收是基于硬件的一种数据接收方式,通过设置串口的接收中断,当接收到数据时,硬件会产生中断信号,通知CPU进行相应的处理。
串口中断接收的原理如下:1. 串口初始化:首先需要对串口进行初始化,包括设置波特率、数据位、奇偶校验位、停止位等参数。
2. 中断使能:对串口接收中断进行使能,使串口接收到数据时,能够产生中断信号。
3. 中断处理函数:当接收到数据时,硬件会触发中断信号,CPU会跳转到相应的中断处理函数进行处理。
4. 数据读取:在中断处理函数中,通过读取串口数据寄存器,获取接收到的数据。
5. 数据处理:对接收到的数据进行相应的处理,比如存储、解析、回应等。
二、UCOS中串口中断接收函数的调用UCOS提供了一些函数来实现串口中断接收的功能,其中比较常用的函数是"OSTaskCreate()"和"OSStart()"。
在使用这些函数之前,需要先进行相应的配置和初始化工作。
首先,需要创建一个任务来处理串口中断接收的数据。
可以使用"OSTaskCreate()"函数来创建任务,该函数的调用格式如下:OSTaskCreate(p_task_entry, p_arg, p_tos, prio)其中,p_task_entry是任务的入口函数,p_arg是传递给任务的参数,p_tos 是任务的堆栈指针,prio是任务的优先级。
接下来,使用"OSStart()"函数来启动UCOS系统。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
再看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。
任务启动要通过OSStart()才行。
相反,当在一个已启动的任务中调用OSTaskCreate()就通过OS_Sched()函数(OSRunning==1),而不用OSStart(),OSStart()只在操作系统启动时调用,任务中不调用一.任务调度中的几个函数的区别:----------------------------------------uCOSII启动时的任务调度--------------------------------------OSStartHighRdy():该函数在OS_CPU_A.ASM中原形如下:_OSStartHighRdy PROC FARMOV AX, SEG _OSTCBHighRdy ;MOV DS, AX ;获得要运行任务的任务控制块所在段的段址CALL FAR PTR _OSTaskSwHook ;调用用户自定义的任务切换接口函数MOV AL, 1 ;0MOV BYTE PTR DS:_OSRunning, AL ;置任务运行标志;LES BX, DWORD PTR DS:_OSTCBHighRdy ;MOV SS, ES:[BX+2] ;MOV SP, ES:[BX+0] ;从任务控制块首指的四个8位内存单元获得该任务的任务堆栈的地址;POP DS ;DS出栈至任务堆栈POP ES ;ES出栈至任务堆栈POPA ;将其余CPU寄存器出栈;IRET ;恢复代码段及指令寄存器内容,运行任务_OSStartHighRdy ENDP该函数由OSStart()调用void OSStart (void)//在OS_CORE.C中{INT8U y;INT8U x;if (OSRunning == FALSE) {y = OSUnMapTbl[OSRdyGrp];x = OSUnMapTbl[OSRdyTbl[y]];OSPrioHighRdy = (INT8U)((y << 3) + x);OSPrioCur = OSPrioHighRdy;OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];OSTCBCur = OSTCBHighRdy;OSStartHighRdy();}//如果多任务环境还没有启动,则先获得就绪表中任务的最高优先级,再获得该优先级下任务的任务控制块的地址(通过OSTCBHighRdy =OSTCBPrioTbl[OSPrioHighRdy],OSTCBPrioTbl[]是一个指针数组,用于存放各优先级任务的任务控制块的地址,它在OS_TCBInit()中被赋值),然后调用OSStartHighRdy()启动任务。
}-------------------------------任务级的任务切换--------------------------------OSCtxSw():函数在OS_CPU_A.ASM中的原形如下:_OSCtxSw PROC FAR;PUSHA ;将所有CPU寄存器压栈PUSH ES ;经附加段寄存器压栈PUSH DS ;将数据段寄存器压栈MOV AX, SEG _OSTCBCur ;获取当前任务所在段的段址,放入DSMOV DS, AX ;LES BX, DWORD PTR DS:_OSTCBCur ;获取当前任务任务控制块的段地址及偏移地址MOV ES:[BX+2], SS ;将当前任务堆栈的断址保存在当前任务的任务控制块中MOV ES:[BX+0], SP ;将当前任务堆栈的偏移地址保存在当前的任务控制块中CALL FAR PTR _OSTaskSwHook ;MOV AX, WORD PTR DS:_OSTCBHighRdy+2 ; OSTCBCur = OSTCBHighRdyMOV DX, WORD PTR DS:_OSTCBHighRdyMOV WORD PTR DS:_OSTCBCur+2, AXMOV WORD PTR DS:_OSTCBCur, DXMOV AL, BYTE PTR DS:_OSPrioHighRdy ; OSPrioCur = OSPrioHighRdyMOV BYTE PTR DS:_OSPrioCur, AL;LES BX, DWORD PTR DS:_OSTCBHighRdy ;将最高优先级任务的堆栈MOV SS, ES:[BX+2] ;指针放回CPU的堆栈段寄存MOV SP, ES:[BX] ;器及堆栈指针寄存器中;SS:SP= OSTCBHighRdy->OSTCBStkPtr此时的任务堆栈已改变,变为最高优先级任务(已是当前任务)的任务堆栈POP DS ;POP ES ;POPA ;IRET ;_OSCtxSw ENDP该函数并非由OS_Sched()直接调用而是通过软中断指令INT 0x80(CPU为80x86),产生中断,到中断向量表中找的OSCtxSw()的入口地址,然后跳转到该函数并执行的。