uCOS中断处理过程详解

合集下载

Ucos学习之中断的应用

Ucos学习之中断的应用

在线学习好工作/Ucos学习之中断的应用在正常的情况下,是我们的主程序在运行,也就是我们的任务在运行,假设我们的主程序运行到某个地方的时候,产生了中断请求,产生了中断请求以后,CPU 来响应这个中断,它在响应这个中断之前呢,首先要做一件事就是现场的保护,这个很好理解,为什么这样呢?因为当我们在执行完中断函数以后,我们还有退回到原来的主函数中去,开始接着往下执行,那这样的话,必须保护这个现场,如果不保护这个现场,我们以后从中断函数退出的时候,那捏怎么知道从什么地方执行呢?所以,在这里,我们中断函数以后,要进行一个现场的保护。

现场保护要做的是什么事情呢?实际上就是保护CPU集成器,现场保护以后,CPU就转入中断函数执行,这个时候,就执行中断,执行中断也叫做ISR,执行完ISR以后,接下来我们要回到主程序执行,那它们之间的过程刚好是个相反的过程。

刚刚我们进行了一个现场保护,那么现在我们要进行一个现场恢复,恢复完现场以后,接下来我们要干的事情就是执行主程序,这个是我们整个中断的过程。

1)中断延迟中断延迟指的是,从产生中断开始,到执行第一条中断函数,这个时间被称作中断延迟时间。

也就是说,从这一时刻,我开始产生中断请求,到另一个时刻,我才执行中断函数,那么这段时间,就被称做中断延迟。

在这个中断延迟中,它都干了些什么事情,实际上就是一个CPU的现场保护。

2)中断响应比如说,某一个事件产生了,那件产生了多长时间以后才会来响应这个事件,这个就叫做中断响应过程,中断响应和中断延迟是有一定的区别的。

我们刚刚说中断延迟是从产生到延迟到执行第一条中断函数服务,而中断响应指的是产生中的请求然后到对这个中断进行处理,这个时间叫做中断响应。

3)中断恢复中断恢复指的是这个中断函数执行完毕以后到我们的主程序去执行这一段时间就是中断恢复的时间。

在我们不带操作系统的开发当中,也就是逻辑开发当中,我们中断延迟和中断响应是一样的。

假设我们跑了操作系统以后,跑了一个OS以后,我们看一下这个会变成什么样。

ucos开关中断

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的中断与时钟

实验六 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 串口中断接收写法UCOS(Micrium公司所开发的一款实时操作系统)是一款非常灵活的嵌入式操作系统,在嵌入式系统中广泛应用。

在UCOS中使用串口中断来接收数据可以极大地提高系统的响应速度和效率。

本文将逐步介绍UCOS中串口中断接收数据的实现方法和写法。

一、UCOS的基本概念与串口中断的作用UCOS是一种多任务实时操作系统,被广泛应用于嵌入式系统中。

它具有高度的可移植性和可扩展性,能够满足各种不同的应用需求。

串口中断是嵌入式系统中常用的通信方式之一,其作用是在数据传输过程中,当接收到数据时立即通知操作系统进行处理,提高系统的实时性和效率。

串口中断接收数据的写法可以通过编写中断处理函数来实现。

二、编写串口中断接收数据的准备工作在开始编写串口中断接收数据之前,需要进行一些准备工作:1. 确定串口通信参数:包括波特率、数据位数、停止位等。

这些参数需要与通信的发送端保持一致。

2. 初始化串口:通过设置串口通信模块的相应寄存器来初始化串口。

3. 编写中断处理函数:中断处理函数负责接收串口中断产生的数据,并进行相应处理。

三、编写串口中断接收数据的步骤下面将详细介绍UCOS中串口中断接收数据的写法步骤:1. 创建串口中断接收任务:在UCOS中,每个任务都是一个独立的实体,需要通过创建任务的方式来执行相应的任务。

首先,创建一个任务来执行串口接收数据的相关操作。

2. 初始化串口:在任务中,首先需要进行串口的初始化操作,确保串口模块能够正常工作。

将串口通信所需的参数设置好,并通过相应寄存器进行配置。

3. 创建中断处理函数:UCOS提供了中断处理函数的接口,在其中进行串口接收数据的处理。

在中断处理函数中,首先判断是否为接收中断,并判断接收寄存器是否有数据可读。

如果有数据可读,则将数据保存到缓冲区中,并在接收完成后通知任务进行数据处理。

4. 任务处理数据:当中断处理函数接收到数据后,需要通知相应的任务来处理数据。

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

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

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

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

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

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

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

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

4.If(OSIntNesting==1){OSTCBCur->OSTCBStrPtr=SP;} //如果是第一层中断,则将堆栈指针保存到被中断任务的任务控制块中5.清中断源,否则在开中断后,这类中断将反复的打入,导致系统崩贵6.执行用户ISR7.中断服务完成后,调用OSIntExit().如果没有高优先级的任务被中断服务子程序激活而进入就绪态,那么就执行被中断了的任务,且只占用很短的时间.8.恢复所有CPU寄存器的值.9.执行中断返回指令.四.相关代码与编译器相关的数据类型:typedef unsigned char BOOLEAN;typedef unsigned char INT8U;typedef unsigned int OS_STK; //堆栈入口宽度为16 位(一) void OSIntEnter (void)的理解uCOS_II.H中定义:#ifdef OS_GLOBALS#define OS_EXT#else#define OS_EXT extern#endif //定义全局宏OS_EXT#ifndef TRUE#define TRUE 1#endifOS_EXT BOOLEAN OSRunning; //定义外部BOOLEAN类型全局变量,用来指示//核是否在运行OS_EXT INT8U OSIntNesting;//定义外部8位无符号整型数全局变量,用来表//示中断嵌套层数OS_CORE.C中的OSIntEnter()函数原型:void OSIntEnter (void){if (OSRunning == TRUE) //如果内核正在运行则进入if{if (OSIntNesting < 255) //如果嵌套层数小于255,则可以继//续{OSIntNesting++; //嵌套层数加1}}}(二)在中断服务子程序中加if ( OSIntNesting == 1){…}的原因uCOS_II.H中定义:typedef struct os_tcb {OS_STK *OSTCBStkPtr;//声明指向任务堆栈栈顶的16位指针………………} OS_TCB;//定义名为OS_TCB的结构体数据类型,即任务控制块的数据结构OS_EXT OS_TCB *OSTCBCur;//声明一个指向任务控制块的全局指针变量//用于指向当前任务的任务控制块中断服务程序中添加的代码:if ( OSIntNesting == 1){OSTCBCur->OSTCBStkPtr = SP; // 如果是第一层中断,则将被中断任务//的堆栈指针保存在被中断任务的任务//任务控制块中}关于uCOS-II的中断服务程序(ISR)中必须加“OSIntNesting == 1”的原因==避免调整堆栈指针.出现这个问题的根源是当低优先级的任务被中断,当中断完成后由于有高优先级的任务就绪,则必须调度高优先级的任务,原来的低优先级任务继续被中断着,但是此时的低优先级任务的堆栈已经被破坏,已不能被调度程序直接调度了,要想被调度而必须调整堆栈指针。

uCOSii中断处理过程详解

uCOSii中断处理过程详解

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

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

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

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

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

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

4.If(OSIntNesting==1){OSTCBCur->OSTCBStrPtr=SP;} //如果是第一层中断,则将堆栈指针保存到被中断任务的任务控制块中5.清中断源,否则在开中断后,这类中断将反复的打入,导致系统崩贵6.执行用户ISR7.中断服务完成后,调用OSIntExit().如果没有高优先级的任务被中断服务子程序激活而进入就绪态,那么就执行被中断了的任务,且只占用很短的时间.8.恢复所有CPU寄存器的值.9.执行中断返回指令.四.相关代码与编译器相关的数据类型:typedef unsigned char BOOLEAN;typedef unsigned char INT8U;typedef unsigned int OS_STK; //堆栈入口宽度为16 位(一) void OSIntEnter (void)的理解uCOS_II.H中定义:#ifdef OS_GLOBALS#define OS_EXT#else#define OS_EXT extern#endif //定义全局宏OS_EXT#ifndef TRUE#define TRUE 1#endifOS_EXT BOOLEAN OSRunning; //定义外部BOOLEAN类型全局变量,用来指示//核是否在运行OS_EXT INT8U OSIntNesting;//定义外部8位无符号整型数全局变量,用来表//示中断嵌套层数OS_CORE.C中的OSIntEnter()函数原型:void OSIntEnter (void){if (OSRunning == TRUE) //如果内核正在运行则进入if{if (OSIntNesting < 255) //如果嵌套层数小于255,则可以继//续{OSIntNesting++; //嵌套层数加1}}}(二)在中断服务子程序中加if ( OSIntNesting == 1){…}的原因uCOS_II.H中定义:typedef struct os_tcb {OS_STK *OSTCBStkPtr;//声明指向任务堆栈栈顶的16位指针………………} OS_TCB;//定义名为OS_TCB的结构体数据类型,即任务控制块的数据结构OS_EXT OS_TCB *OSTCBCur;//声明一个指向任务控制块的全局指针变量//用于指向当前任务的任务控制块中断服务程序中添加的代码:if ( OSIntNesting == 1){OSTCBCur->OSTCBStkPtr = SP; // 如果是第一层中断,则将被中断任务//的堆栈指针保存在被中断任务的任务//任务控制块中}关于uCOS-II的中断服务程序(ISR)中必须加“OSIntNesting == 1”的原因==避免调整堆栈指针.出现这个问题的根源是当低优先级的任务被中断,当中断完成后由于有高优先级的任务就绪,则必须调度高优先级的任务,原来的低优先级任务继续被中断着,但是此时的低优先级任务的堆栈已经被破坏,已不能被调度程序直接调度了,要想被调度而必须调整堆栈指针。

ucosIII中断、临界区与时间管理

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中断处理过程详解

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。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 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()的入口地址,然后跳转到该函数并执行的。

相关文档
最新文档