嵌入式实时操作系统ucosII_第1页
嵌入式实时操作系统ucosII_第2页
嵌入式实时操作系统ucosII_第3页
嵌入式实时操作系统ucosII_第4页
嵌入式实时操作系统ucosII_第5页
已阅读5页,还剩345页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

嵌入式操作系统基础——C/OS-Ⅱ

“嵌入式操作系统基础”课程内容132548嵌入式实时操作系统C/OS-Ⅱ操作系统及任务C/OS-Ⅱ的中断、时钟及时间管理C/OS-Ⅱ的任务管理C/OS-Ⅱ的初始化、启动C/OS-Ⅱ的移植6C/OS-Ⅱ任务通信与同步7C/OS-Ⅱ内存管理9基于C/OS-Ⅱ应用的开发

第一讲嵌入式实时操作系统第一节嵌入式系统目前国内一个普遍被认同的定义是:以应用为中心、以计算机技术为基础,软件硬件可裁剪,适应应用系统对功能、可靠性、成本、体积、功耗严格要求的专用计算机系统。而这专用计算机系统是嵌入到对象中。只见对象,不见计算机。如图1.1、1.2、1.3、1.4所示。这个专用计算机系统承担对象的数据处理和对象各部件运动的控制。随着大规模集成电路的发展、嵌入式软件工程的发展,嵌入的对象越来越广泛。第二节

嵌入式实时操作系统正如通用计算机系统,有很多软、硬件资源需要一个操作系统来管理,并提供用户一个良好的程序运行的环境。同样,作为嵌入式系统—专用计算机也需要一个操作系统。这个操作系统必须是实时的、嵌入式的。许多早期的嵌入式系统开发者认为嵌入式系统不需要操作系统,但现在除了最简单的系统外,越来越多的嵌入式系统都引入了操作系统,比如中断驱动系统在引入嵌入式操作系统之后,系统的可靠性、安全性、可扩展性、功能性、灵活性、可管理性都大大提高。当然,我们这里所讲的嵌入式操作系统不一定是UcOS、VxWorks、WinCE、Linux等通用产品,也包括开发者自己编写的专用嵌入式操作系统。

嵌入式实时操作系统在这些嵌入式操作系统中封装了越来越多的功能,除了对任务的切换、调度、通信、同步、互斥、中断管理、时钟管理等,还可进一步封装内存管理、网络通讯协议、文件管理等功能,这些功能可以根据需要进行裁减。Linux正是由于其源代码开放,可以使开发者根据自己的需要进行裁剪而受到开发者的青睐。1.2.1计算机实时操作系统实时操作系统首要特点是实时性。为此:⑴实时操作系统必须是多任务的。⑵实时操作系统内核应该是可剥夺型的。

图1.1

图1.2

图1.3

图1.4

关于内核应该是可剥夺型的这种可剥夺性表现为:一个在运行的进程可被另一个进程剥夺其在CPU的运行权;另一方面,被剥夺运行权的进程,一旦再次获得运行时,能够正确无误运行,得到正确结果。为此,编译器、程序设计都要保证这点。①可重入函数 ②不可重入的函数viodstrcpy(char*dest,char*src) intTemp;{ voidswap(int*x,int*y)while(*dest++=*src++){ {; Temp=*x;} *x=*y;*dest=NULL; *y=Temp;} }对于含有不可剥夺的函数的进程是不剥夺的。⑶进程调度的延时可预测并尽可能小⑷系统提供的服务时间可预知.

嵌入式实时操作系统

实时嵌入式操作系统的种类繁多,大体上可分为两种,商用型和免费型。商用型的实操作系统功能稳定、可靠,有完善的技术支持和售后服务,但往往价格昂贵,如Vxworks、QNX、WinCE、PalmOS等。免费型的实时操作系统在价格方面具有优势,目前主要有Linux、eCos和μC/OS-Ⅱ,稳定性与服务性存在挑战。μC/OS-Ⅱ得到了美国航空管理局的认证,可用在飞行器上。这说明μC/OS-Ⅱ是稳定可靠的,可用在与人性命攸关的安全紧要的系统上。本课程讲授的就是μC/OS-Ⅱ。它是一个十分小的内核。⑸中断延时尽可能小。否则影响高优先级进程的执行。1.2.2嵌入式实时操作系统嵌入式系统是嵌入到某一对象中的专用计算机,它所占用的空间和所需的能源十分有限,甚至是苛刻的。这就要求操作系统是可剪裁的。对于不同的应用对象,必须剪裁掉与其无关的部分。这样嵌入式系统不但是实时的,而且是可剪裁的。这点与通用操作系统是不同的.

学习嵌入式操作系统学习一种实时操作系统RTOS,如uc/OS,掌握实时系统的概念和设计方法;嵌入式系统以应用为中心,应用时选择“适用”的操作系统;知道如何剪裁操行系统;嵌入式Linux、eCos;自己“写”RTOS——一种学习态度;由于嵌入式系统自身的特点,采用的程序设计语言是汇编语言、C/C++语言、JAVA语言。所用的编译器应与处理器相适应。

RTOS在嵌入式系统中的位置嵌入式硬件平台BSP(板级支持包)KERNELFSTCP/IP设备驱动设备I/O调试工具其它组件应用RTOSC/C++

第二讲

C/OS

–II及任务µC/OS-II的特点µC/OS-II文件结构与内核µC/OS-II任务及其存储结构µC/OS-II任务控制块与任务堆栈µC/OS-II系统的任务、空闲任务与统计任务

公开源代码可移植性(Portable)

绝大部分

C/OS-II的源码是用移植性很强的ANSIC写的。和微处理器硬件相关的那部分是用汇编语言写的。汇编语言写的部分已经压到最低限度,使得

C/OS-II便于移植到其他微处理器上。

C/OS-II可以在绝大多数8位、16位、32位以至64位微处理器、微控制器、数字信号处理器(DSP)上运行。可固化(ROMable)

C/OS-II是为嵌入式应用而设计的,这就意味着,只要读者有固化手段(C编译、连接、下载和固化),

C/OS-II可以嵌入到读者的产品中成为产品的一部分。可裁剪(Scalable)

可以只使用

C/OS-II中应用程序需要的那些系统服务。也就是说某产品可以只使用很少几个

C/OS-II调用,而另一个产品则使用了几乎所有

C/OS-II的功能,这样可以减少产品中的

C/OS-II所需的存储器空间(RAM和ROM)。这种可剪裁性是靠条件编译实现的。第一节C/OS的性能特点(一)

占先式(Preemptive)多任务

C/OS-II可以管理64个任务,然而,目前这一版本保留8个给系统。应用程序最多可以有56个任务可确定性

全部

C/OS-II的函数调用与服务的执行时间具有可确定性。任务栈

每个任务有自己单独的栈,

C/OS-II允许每个任务有不同的栈空间,以便压低应用程序对RAM的需求。系统服务

C/OS-II提供很多系统服务,例如邮箱、消息队列、信号量、块大小固定的内存的申请与释放、时间相关函数等。中断管理

中断可以使正在执行的任务暂时挂起,如果优先级更高的任务被该中断唤醒,则高优先级的任务在中断嵌套全部退出后立即执行,中断嵌套层数可达255层。稳定性与可靠性C/OS的性能特点(二)

第二节C/OS-II的文件结构与内核

任务管理:任务的描述、任务的创建、任务的调度。任务之间通信与同步。临界区的代码的处理。时间管理:时钟节拍的处理。中断服务程序的设计。

C/OS的初始化与启动。

C/OS的多任务的运行。C/OS-II的内核结构

C/OS-II中使用的数据类型typedefunsignedcharBOOLEAN;typedefunsignedcharINT8U;/*Unsigned8bitquantity*/typedefsignedcharINT8S;/*Signed8bitquantity*/typedefunsignedintINT16U;/*Unsigned16bitquantity*/typedefsignedintINT16S;/*Signed16bitquantity*/typedefunsignedlongINT32U;/*Unsigned32bitquantity*/typedefsignedlongINT32S;/*Signed32bitquantity*/typedeffloatFP32;/*Singleprecisionfloatingpoint*/typedefdoubleFP64;/*Doubleprecisionfloatingpoint*/typedefunsignedintOS_STK;/*Eachstackentryis16-bitwide*/typedefunsignedshortOS_CPU_SR;/*DefinesizeofCPUstatusregister(PSW=16bits)*/#defineBYTEINT8S/*Definedatatypesforbackwardcompatibility...*/#defineUBYTEINT8U/*...touC/OSV1.xx.Notactuallyneededfor...*/#defineWORDINT16S/*...uC/OS-II.*/#defineUWORDINT16U#defineLONGINT32S#defineULONGINT32U为了移植方便,在C/OS-II中重新定义一套新的数据类型。OS_CPU.h文件中描述了针对x86类型CPU的C语言中的这二种数据类型之间的关系:

第三节µC/OS-II的任务及其存储结构C/OS

–II的任务任务是一个无限循环。一个典型的例子:voidmytask(void*pdata){for(;;){dosomething;waiting;dosomething;}}C/OS

–II2.5版本支持64个任务,每个任务一个特定的优先级。优先级越高,数字越小。系统占用了8个任务,保留优先级为0、1、2、3、OS_LOWEST_PRIO-3、OS_LOWEST_PRIO-2、OS_LOWEST_PRIO-1、OS_LOWEST_PRIO-0。

一个任务的例子voidTask1 (void*pdata){uint8err; pdata=pdata;

while(1) {OSSemPend(UART0_Sem,0,&err); //请求一个信号量UART_SendStr(“Task1isrunning!\r\n”); //通过串口在屏幕显示OSTimeDly(OS_TICKS_PER_SEC); //延时OSSemPost(UART0_Sem); //本任务发送一个信号量 }}

任务存储结构任务控制块前一个任务控制块指针任务的代码Voidmytask(void*pdata){….For(;;){….}}指向任务堆栈的指针后一个任务控制块指针任务的优先级任务堆栈指向任务的代码

任务状态

第四节任务控制块(TCB)与任务堆栈任务控制块OS_TCB是一个数据结构,保存该任务的相关参数,包括任务堆栈指针,状态,优先级,任务表位置,任务链表指针等。所有的任务控制块分为两条链表,空闲链表和使用链表。

µC/OS-II任务控制块typedefstructos_tcb{OS_STK*OSTCBStkPtr;/*Pointertocurrenttopofstack*/#ifOS_TASK_CREATE_EXT_EN>0void*OSTCBExtPtr;/*PointertouserdefinabledataforTCBextension*/OS_STK*OSTCBStkBottom;/*Pointertobottomofstack*/INT32UOSTCBStkSize;/*Sizeoftaskstack(innumberofstackelements)*/INT16UOSTCBOpt;/*TaskoptionsaspassedbyOSTaskCreateExt()*/INT16UOSTCBId;/*TaskID(0..65535)*/#endifstructos_tcb*OSTCBNext;/*PointertonextTCBintheTCBlist*/structos_tcb*OSTCBPrev;/*PointertopreviousTCBintheTCBlist*/#if((OS_Q_EN>0)&&(OS_MAX_QS>0))||(OS_MBOX_EN>0)||(OS_SEM_EN>0)||(OS_MUTEX_EN>0)OS_EVENT*OSTCBEventPtr;/*Pointertoeventcontrolblock*/#endif#if((OS_Q_EN>0)&&(OS_MAX_QS>0))||(OS_MBOX_EN>0)void*OSTCBMsg;/*MessagereceivedfromOSMboxPost()orOSQPost()*/#endif

µC/OS-II任务控制块#if(OS_VERSION>=251)&&(OS_FLAG_EN>0)&&(OS_MAX_FLAGS>0)#ifOS_TASK_DEL_EN>0OS_FLAG_NODE*OSTCBFlagNode;/*Pointertoeventflagnode*/#endifOS_FLAGSOSTCBFlagsRdy;/*Eventflagsthatmadetaskreadytorun*/#endifINT16UOSTCBDly;/*Nbrtickstodelaytaskor,timeoutwaitingforevent*/INT8UOSTCBStat;/*Taskstatus*/INT8UOSTCBPrio;/*Taskpriority(0==highest,63==lowest)*/INT8UOSTCBX;/*Bitpositioningroupcorrespondingtotaskpriority(0..7)*/INT8UOSTCBY;/*Indexintoreadytablecorrespondingtotaskpriority*/INT8UOSTCBBitX;/*Bitmasktoaccessbitpositioninreadytable*/INT8UOSTCBBitY;/*Bitmasktoaccessbitpositioninreadygroup*/#ifOS_TASK_DEL_EN>0BOOLEANOSTCBDelReq;/*Indicateswhetherataskneedstodeleteitself*/#endif}OS_TCB;

OSTCBStkPtr指向当前任务堆栈顶的指针OS_TASK_CREATE_EXT_EN用于控制是否允许扩展任务控制块。1-允许0-不允许OSTCBExtPtr指向任务控制块扩展部分的指针OSTCBStkBottom指向当前任务堆栈底的指针OSTCBStkSize任务堆栈的长度OSTCBOpt当允许扩展任务控制块时,OSTCBOpt代表OS_TASK_OPT_STK_CHK、OS_TASK_OPT_STK_CLR、OS_TASK_OPT_SAVE_FP中的一个,将此参数(分别为是否允许堆栈检验、清除,是否允许浮点运算)传给函数OSTaskCreateExt().OSTCBId//用于任务存储的识别码OSTCBNext//指向后一个任务控制块OSTCBPrev//指向前一个任务控制块OS_Q_EN//用于控制是否使用C/OS

–II中的消息队列函数及其相关的数据结构OS_MAX_QS//代表系统可以创建的消息队列的最大数OS_MBOX_EN//用于控制是否使用C/OS

–II中的消息邮箱函数及其相关的数据结构OSTCBEventPtr//指向事件控制块的指针OSTCBMsg//指向传递给任务的消息的指针

OSTCBFLAGNode//指向事件标志节点的指针OSTCBFlagRdy、OSTCBFlagNode//指向信号量集的任务进入就绪态的事件标志及指向信号量集等待任务链表节点指针OS_VERSION//系统版本号OS_FLAG_EN//用于控制是否使用所有事件标志函数及其相关的数据结构。为1使用,为0不使用。OS_MAX_FLAG//用户程序中所需要的事件标志最大数OS_TASK_DEL_EN//在C/OS

–II中是否使用OSTaskDel()函数,为1使用,为0不使用。OSTCBDly//某任务允许等待事件发生的最多时钟节拍数。OSTCBStat//任务当前状态标志OSTCBPrio//任务的优先级OSTCBX//用于快速访问就绪表的数据,对应prio%8的值OSTCBY//用于快速访问就绪表的数据,对应prio>>3的值。OSTCBBitX//用于快速访问就绪表的数据,等于OSTCBTbl[prio>>3]的值。OSTCBBitY//用于快速访问就绪表的数据,对应OSMap[prio&0x07]的值,如果它为1则置OSRdyGrp的第Y位的值为1,Y=OSTCBY。OSTCBDelReg//请求删除任务时用到的标志

任务控制块OS_TCB中几个成员的算法OSTCBY=priority>>3;OSTCBBitY=OSMapTbl[priority>>3];OSTCBX=priority&0x07;OSTCBBitX=OSMapTbl[priority&0x07];

空任务列表所有的任务控制块都被放置在任务控制块列表数组OSTCBTbl[]中,系统初始化时,所有任务控制块被链接成空任务控制块的单向链表,任务建立后,空任务控制块指针OSTCBFreeList指向的任务控制块就赋给了该任务,然后OSTCBFreeList的值调整为指向链表中的下一个空任务控制块。

任务控制块链表

任务的堆栈SP处理器OSTCBStkPtr创建任务时TaskStk任务运行时任务创建时,把任务堆栈的栈顶地址赋给OSTCBStkPtr。任务运行时,OSTCBStkPtr赋给SP(堆栈栈顶指针寄存器)该任务运行时,SP的值会发生变化。实际上任务的堆栈是用一个类型为OS_STK的数组:#defileTASK_STK_SIZE512OS_STKTeskStr[TASK_STK_SIZE];//这里并没有确定栈顶的位置

任务的堆栈低地址高地址堆栈增长的方向堆栈增长的方向增长方向为向下的堆栈OS_STK_GROWTH=1//为缺省值&TeskStr[TASK_STK_SIZE-1]指向栈顶增长方向为向上的堆栈OS_STK_GROWTH=0&TeskStr[0]指向栈顶(参考书中84页)

临界区临界区是正在运行的一段不可中断的程序代码。在进入临界区之前,要关一切允许中断标志。在退出临界区之后,要立刻开启一切允许中断标志。关中断时间是实时内核最重要的指标之一;在实际应用中,关中断的时间很大程度中取决于微处理器的结构和编译器生成的代码质量;C/OS-II定义两个宏开关中断:OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()。至于如何实现这两个宏,在移植过程中,对于不同的微处理器,采用不同的方法。这样做是便于C/OS-II的移植;

C/OS-II中采用了3种开关中断的方法OS_CRITICAL_METHOD==1用处理器指令关中断,执行OS_ENTER_CRITICAL(),开中断执行OS_EXIT_CRITICAL();OS_CRITICAL_METHOD==2实现OS_ENTER_CRITICAL()时,先在堆栈中保存中断的开/关状态,然后再关中断;实现OS_EXIT_CRITICAL()时,从堆栈中弹出原来中断的开/关状态;OS_CRITICAL_METHOD==3把当前处理器的状态字保存在局部变量中(如OS_CPU_SR,关中断时保存,开中断时恢复

任务控制块初始化函数主要做三件事:⑴从空任务链表取出一任务控制块,填入相关数据;⑵修改就绪表及OSTCBPrioTbl[prio]的值(OSTCBPrioTbl[prio]=ptcb

;⑶修改任务链表;INT8UOS_TCBInit(INT8Uprio,OS_STK*ptos,OS_STK*pbos,INT16Uid,INT32Ustk_size,void*pext,INT16Uopt){#ifOS_CRITICAL_METHOD==3/*AllocatestorageforCPUstatusregister*/OS_CPU_SRcpu_sr;#endifOS_TCB*ptcb;OS_ENTER_CRITICAL();

ptcb=OSTCBFreeList;/*GetafreeTCBfromthefreeTCBlist*/

if(ptcb!=(OS_TCB*)0){OSTCBFreeList=ptcb->OSTCBNext;/*UpdatepointertofreeTCBlist*/OS_EXIT_CRITICAL();ptcb->OSTCBStkPtr=ptos;/*LoadStackpointerinTCB*/ptcb->OSTCBPrio=(INT8U)prio;/*LoadtaskpriorityintoTCB*/ptcb->OSTCBStat=OS_STAT_RDY;/*Taskisreadytorun*/ptcb->OSTCBDly=0;/*Taskisnotdelayed*/

任务控制块初始化函数#ifOS_TASK_CREATE_EXT_EN>0ptcb->OSTCBExtPtr=pext;/*StorepointertoTCBextension*/ptcb->OSTCBStkSize=stk_size;/*Storestacksize*/ptcb->OSTCBStkBottom=pbos;/*Storepointertobottomofstack*/ptcb->OSTCBOpt=opt;/*Storetaskoptions*/ptcb->OSTCBId=id;/*StoretaskID*/#elsepext=pext;/*Preventcompilerwarningifnotused*/stk_size=stk_size;pbos=pbos;opt=opt;id=id;#endif#ifOS_TASK_DEL_EN>0ptcb->OSTCBDelReq=OS_NO_ERR;//OS_NO_ERR为0X00#endif

ptcb->OSTCBY=prio>>3;/*Pre-computeX,Y,BitXandBitY*/ptcb->OSTCBBitY=OSMapTbl[ptcb->OSTCBY];ptcb->OSTCBX=prio&0x07;ptcb->OSTCBBitX=OSMapTbl[ptcb->OSTCBX];

任务控制块初始化函数#ifOS_EVENT_EN>0ptcb->OSTCBEventPtr=(OS_EVENT*)0;/*Taskisnotpendingonanevent*/#endif#if(OS_VERSION>=251)&&(OS_FLAG_EN>0)&&(OS_MAX_FLAGS>0)&&(OS_TASK_DEL_EN>0)ptcb->OSTCBFlagNode=(OS_FLAG_NODE*)0;/*Taskisnotpendingonaneventflag*/#endif#if(OS_MBOX_EN>0)||((OS_Q_EN>0)&&(OS_MAX_QS>0))ptcb->OSTCBMsg=(void*)0;/*Nomessagereceived*/#endif#ifOS_VERSION>=204OSTCBInitHook(ptcb);#endifOSTaskCreateHook(ptcb);/*Calluserdefinedhook*/

OS_ENTER_CRITICAL();

OSTCBPrioTbl[prio]=ptcb;

任务控制块初始化函数

ptcb->OSTCBNext=OSTCBList;/*LinkintoTCBchain*/ptcb->OSTCBPrev=(OS_TCB*)0;if(OSTCBList!=(OS_TCB*)0){OSTCBList->OSTCBPrev=ptcb;}OSTCBList=ptcb;//插入任务链表的首部OSRdyGrp|=ptcb->OSTCBBitY;/*Maketaskreadytorun*/OSRdyTbl[ptcb->OSTCBY]|=ptcb->OSTCBBitX;OS_EXIT_CRITICAL();return(OS_NO_ERR);}OS_EXIT_CRITICAL();return(OS_NO_MORE_TCB);}对于一般方式创建任务:OS_TCBInit(prio,psp,(OS_STK*)0,0,0,(void*)0,0);对于扩展方式创建任务:OS_TCBInit(prio,psp,pbos,id,stk_size,pext,opt);

第五节系统的任务、空闲任务、统计任务系统任务µC/OS-II操作系统本身占据64任务中的8个。空闲任务OSTaskIdle()这是一个系统任务。它的优先级最低:OS_LOWEST_PRIO-0。统计任务OSTaskStat()这也是一个系统任务。它的优先级次低:OS_LOWEST_PRIO-1。

空闲任务OSTaskIdle()voidOSTaskIdle(void*pdata){pdata=pdata;for(;;){OS_ENTER_CRITICAL();OSIdleCtr++;//空闲任务计数器OS_EXIT_CRITICAL();}}

第三讲任务管理创建任务就绪任务的管理任务的挂起和恢复其它任务管理函数任务调度任务的切换

第一节

创建任务UseoneoftwoservicesINT8UOSTaskCreate(void(*task)(task*pd),void*pdata,OS_STK*ptos,INT8Uprio)INT8UOSTaskCreateExt(TaskCreate(void(*task)(task*pd),void*pdata,OS_STK*ptos,INT8Uprio,INT16Uid,OS_STK*pbos,INT32Ustk_size,void*pext,INT16Uopt)其中:id是一个特殊标志,为C/OS-II的扩展而设置。可与prio相同。pext指向用户附加的数据域的指针。为C/OS-II的扩展而设置。opt设置附加选项。

创建一任务检查优先级的合法性在OSTCBPrioTbl[]注册堆栈初始化取出一空任务控制块向任务控制块写数据有没空任务控制块创建失败返回创建失败返回执行一次调度创建成功返回正在执行过程中合法不合法没有有没有正在“正在执行过程中”是指已有任务在CPU中运行。例如本函数的执行正是由某个正在运行的任务需创建一个新任务,此时必须引发一次新的调度。由于调度可能新任务立刻获得CPU的运行权。但是,在一开始(OSStart()之前),没有任何任务开始运行,是不会引发一次新的调度。本任务的任务控制块初始化

建立任务,OSTaskCreate()INT8UOSTaskCreate(void(*task)(void*pd),void*pdata,OS_STK*ptos,INT8Uprio){void*psp;INT8Uerr;if(prio>OS_LOWEST_PRIO){(1)return(OS_PRIO_INVALID);}OS_ENTER_CRITICAL();if(OSTCBPrioTbl[prio]==(OS_TCB*)0){ (2)//该任务是否已存在OSTCBPrioTbl[prio]=(OS_TCB*)1;(3)OS_EXIT_CRITICAL();(4)psp=(void*)OSTaskStkInit(task,pdata,ptos,0);err=OSTCBInit(prio,psp,(void*)0,0,0,(void*)0,0);if(err==OS_NO_ERR){ OS_ENTER_CRITICAL();

OSTaskCtr++; OSTaskCreateHook(OSTCBPrioTbl[prio]); OS_EXIT_CRITICAL();if(OSRunning){//如果本任务是正在执行的任务创建的 OSSched(); }}else{//任务控制块初始化失败OS_ENTER_CRITICAL();OSTCBPrioTbl[prio]=(OS_TCB*)0; OS_EXIT_CRITICAL();}return(err);}else{//没有空闲任务控制块

OS_EXIT_CRITICAL();return(OS_PRIO_EXIST);}}

Void(*task)(Void*pd)//指向任务的指针Void*pdata//传递给任务的指针OS_STK*ptos//指向任务堆栈栈顶的指针INT8Uprio//任务的优先级If(prio>OS_LOWST_PRIO)//判断给出的优先级的合法性:给出的优先级不能低于空闲任务的优先级。OSTCBPrioTbl[]//保存所有(64)个优先级的任务所指向的任务控制块的指针,如果某优先级(Prio)的任务尚未建立,则OSTCBPrioTbl[Prio]==(OS_TCB*)即指针为空。OSTCBPrioTbl[prio]=(OS_TCB*)1//只是给一个非空的指针,说明优先级(Prio)的任务尚已建立,保留该优先级。任务堆栈初始化OSTaskStkInit()过程中将指向任务代码指针、传递给该任务的其它参数存入堆栈,并返回栈顶指针psp。完成堆栈的建立。任务控制块初始化OSTCBInit()过程首先将空任务链表的酋指针OSTCBFreeList所指向的任务控制块赋给OSTCBPrioTbl[prio],并将该任务控制块加入任务链表。把相应参数写入任务控制块,同时在就绪任务表中登记。返回任务控制块初始化是否成功的标志。如果成功,任务计数器加1。同时判断该任务的创建是在某一正在执行过程中,则要执行一次调度。如果创建的任务优先级高,则执行该任务。

创建任务的一般方法voidmain(void){OSInit();/*初始化uC/OS-II (1)*/

...OSTaskCreate(TaskStart,s_M,&MyTaskStk[TASK_STK_SIZE-1],0);OSStart();/*开始多任务调度 (3)*/}voidTaskStart(void*pdata){/*安装并启动uC/OS-II的时钟节拍 (4)*/OSStatInit();/*初始化统计任务 (5)*//*创建用户应用程序任务 */for(;;){/*这里是TaskStart()的代码! */}}

例5-2#include“includes.h”#defineTASK_STK_SIZE512//任务堆栈的长度OS_STKMyTask[TASK_STK_SIZE];//定义任务堆栈区INT16Skey; //用于退出µC/OS-II任务的键INT8Ux=0,y=0; //字符显示的位置VoidMyTask(void*data);//声明一个任务Voidmain(void){char*s_M=“M”;//定义要显示的字符OSInit(); //初始化µC/OS-IIPC_DOSSaveReturn(); //保存DOS环境PC_VectSet(ucos,osctxSw);//安装µC/OS-II任务切换中断向量

OSTaskCreate(MyTask,//创建任务MyTasks_M, //给任务传递参数&MyTaskStk[TASK_STK_SIZE-1],//设置任务堆栈栈顶指针0); //设任务MyTask的优先级为0

}//endofmainVoidMyTask(void*pdata){#ifOS_CRITICAL_METHOD==3//如果采用第三种开关中断方式OS_CPU_SRcpu_sr; //则定义一个寄存器变量cpu_sr#endifptata=ptata; OS_ENTER_CRITICAL(); //关中断PC_VectSet(0x08,OSTickISR); //安装µC/OS-II时钟中断向量

PC_SetTickRate(OS_TICKS_PER_SEC);//设置µC/OS-II时钟频率OS_EXIT_CRITICAL(); //开中断OSStatInit(); //初始化µC/OS-II的统计任务for(;;){if(x>10){x=0;y+=2;}

PC_DispChar(x,y,*(chat*)pdata,DISP_BGND_BLACK+DISP_FGND_WHITE};x+=1;if(PC_GetKey(&key)==TRUE){if(key==0x1B){PC_DOSReturn();//返回DOS}}

OSTimeDlyHMSM(0,0,1,0);//等待1s}}

第二节

就绪任务的管理就绪任务表根据就绪表确定最高优先级任务就绪表的特点根据优先级找到任务在就绪任务表中的位置使任务进入就绪态使任务脱离就绪态采用查表法确定就绪任务队列中最高优先级任务优先级判定表

就绪任务表每个就绪的任务都放入就绪表中(readylist)中,就绪表有两个变量:OSRdyGrp、OSRdyTbl[]OSRdyGrp1207654300XXXYYY任务优先级2017654310891514131211181617232221201926242531302928273432333938373635424041474645444350484955545352515856576362616059[0][1][2][3][4][5][6][7]OSRdyTbl[7]XY优先级最低任务(空闲任务)优先级最高任务任务优先级号

任务就绪表的特点任务就绪表是用INT8U类型的数组OSRdyTbl[]表示。OSRdyTbl[]中每一个元素OSRdyTbl[y]可表达八个任务的就绪状态:1为就绪态;0为不就绪态。长度为8的数组OSRdyTbl[]可表达64个任务的就绪状态。每一个元素OSRdyTbl[y]所表达的八个任务为就绪任务组。优先级prio的最大值为63,可表示为00111111B。任何任务的优先级prio低6位中的前三位的值y表示该任务的就绪状态,在数组OSRdyTbl[y]的元素得到表示。如果该任务就绪,则INT8U类型的变量OSRdyGrp的相对应的第y位为1。低6位中的后三位的值x,表示该任务的就绪状态在数组OSRdyTbl[y]元素的第x位为1。变量OSRdyGrp反映了整个任务就绪情况。任务就绪表中的任务是按优先级排列。数学表示:优先级为prio的任务的就绪状态在数组OSRdyTbl[prio>>3]的第x位。x=prio%8或x=prio&0x07,后者处理速度更快。通过数组OSRdyTbl[]、OSRdyGrp变量可管理64个就绪任务。利用任务就绪表要解决如下几个问题:创建任务时,要在就绪表中登记,在对应位置,置1。删除任务时,要在就绪表中找到对应位置,置0。在任务就绪表中,找到优先级最高的任务。且保证服务时间相同。

根据优先级找到任务在就绪任务表中的位置(1)假设优先级为12的任务进入就绪状态,12=0000

1100b,则OSRdyTbl[1]的第4位置1,且OSRdyGrp的第1位置1,相应的数学表达式为:

OSRdyGrp|=00000010或者OSRdyGrp|=0x02;OSRdyTbl[1]|=00010000或者OSRdyTbl[1]|=0x10;而优先级为21的任务就绪21=0001

0101b,则OSRdyTbl[2]的第5位置1,且OSRdyGrp的第2位置1,相应的数学表达式为:

OSRdyGrp|=00000100或者OSRdyGrp|=0x04;;OSRdyTbl[2]|=00100000或者OSRdyTbl[2]|=0x20;;在上述表达式中,类似0x02、0x10、0x04、0x20如何从任务的优先级数prio导出。为此定义了一个INT8U类型的数组OSMapTbl[]。通过它可以快速找到就绪任务在数组OSRdyTbl[]元素的位置。数组OSMapTbl[]是一个特殊的数组

根据优先级找到任务在就绪任务表中的位置(2)从上面的计算我们可以得到:若OSRdyGrp及OSRdyBbl[]的第n位置1,则应该把OSRdyGrp及OSRdyBbl[]的值与2n相或。uC/OS中,把2n的n=0-7的8个值先计算好存在数组OSMapTbl[]中,也就是:

OSMapTbl[0]=20=0x01(00000001)OSMapTbl[1]=21=0x02(00000010)

……OSMapTbl[7]=27=0x80(10000000)为什么我们要采用数组OSMapTbl[]?事实上,只要给出数组元素的下标值,我们就可找到数组元素的值。不论下标值的大小,所需时间都相等,而且时间可预知。算法如下:数组元素的所在的位置:数组的首地址+下标值×数组元素所占的字节数。优点是,符合实时操作系统的要求。缺点是,空间耗费更大。

使任务进入就绪态一般情况下,如果prio是任务的优先级,也是任务的识别号,则将任务放入就绪表,即使任务进入就绪态的方法是:OSRdyGrp|=OSMapTbl[prio>>3];(1)OSRdyTbl[prio>>3]|=OSMapTbl[prio&0x07];(2)例如,假设优先级为12——1100bOSRdyGrp|=OSMapTbl[1] ; //(00000010)OSRdyTbl[1]|=OSMapTbl[4] ; //(00010000)为了减少在调度过程中,反复计算prio>>3、prio&0x07和OSMapTbl[prio>>3]和OSMapTbl[prio&0x07]的值,设置如下成员变量:ptcb->OSTCBY=prio>>3;ptcb->OSTCBBitY=OSMapTbl[ptcb->OSTCBY];ptcb->OSTCBX=prio&0x07;ptcb->OSTCBBitX=OSMapTbl[ptcb->OSTCBX];这样(1)、(2)式就可写成:OSRdyGrp|=ptcb->OSTCBBitY;(1)OSRdyTbl[ptcb->OSTCBY]|=ptcb->OSTCBBitX;(2)

使任务脱离就绪态使任务脱离就绪态就是将任务就绪表OSRdyTbl[prio>>3]相应元素的相应位清零。只需OSRdyTbl[prio>>3]&=

OSMapTbl[prio&0x07]而且当OSRdyTbl[prio>>3]中的所有位都为零时,即全组任务中没有一个进入就绪态时,OSRdyGrp的相应位才为零。if((OSRdyTbl[prio>>3]&=

OSMapTbl[prio&0x07])==0)OSRdyGrp&=

OSMapTbl[prio>>3];(仅对该位置零)否则任务组中还有进入就绪态的任务

采用查表法确定就绪任务队列中最高优先级任务有多种方法可以从多个就绪任务中找出优先级最高的任务,但是为保证查找的快速和时间到预测。作者采用查表法。从就绪任务表中可看出,首先从OSRdyGrp可求出,优先级最高的任务一定位于其中从右至左,首个不为零的那一位所在的行Y。然后依据OSRdyTbl[Y],优先级最高的任务一定位于其中从右至左,首个不为零的那一位所在的列X。

根据这个原理,我们设计了优先级查找表OSUnMapTbl[],实现高速查找。优先级查找表是一个数组。根据数组的首地址和下标值,可以很快找到该元素的值。所费的时间是相同的。

INT8UconstOSUnMapTbl[]={0,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0};优先级判定表OSUnMapTbl[256]举例:

如OSRdyGrp的值为01101000B,即0X68(104),则查得OSUnMapTbl[OSRdyGrp]的值是3,它相应于OSRdyGrp中的第3位置1;如OSRdyTbl[3]的值是11100100B,即0XE4(228),则查OSUnMapTbl[OSRdyTbl[3]]的值是2,则进入就绪态的最高任务优先级Prio=3*8+2=26

优先级判定表OSUnMapTbl[]是如何产生的我们就不讨论。但同学们可以想一想。

采用查表法确定就绪任务队列中最高优先级任务查表法具有确定的时间,增加了系统的可预测性,uC/OS中所有的系统调用时间都是确定的High3=OSUnMapTbl[OSRdyGrp];//获得优先级高三位Low3=OSUnMapTbl[OSRdyTbl[High3]];//获得优先级低三位Prio=(Hign3<<3)+Low3;//Prio=Hign*8+LowOSRdyGrp1207654300XXXYYY任务优先级2017654310891514131211181617232221201926242531302928273432333938373635424041474645444350484955545352515856576362616059[0][1][2][3][4][5][6][7]OSRdyTbl[7]XY

第三节任务的挂起INT8UOSTaskSuspend(INT8Uprio)Prio是空闲任务?标志self=TRUE?取消任务的就绪状态,并控制块中进行记录返回OS_NO_ERR标志self=FALSE返回OS_PRIO_INVALID返回OS_TASK_SUSPEND_IDLE指针非空?返回OS_TASK_SUPEND_PRIO进入Prio是合法的优先级?prio=OXFF(OS_PRIO_SELF)?标志self=TRUE,并从OSTCBCur中取出prio调用任务调度器OS_Sched()YESNONONOYESYESNOYESNOYES当前任务?NOYES根据prio取任务TCB的指针挂起态:OS_STAT_SUSPEND。被挂起的任务可以是一个正在等待的任务:ptcb->OSTCBStat|=OS_STAT_SUSPEND;

第四节恢复任务INT8UOSTaskResume(INT8Uprio)取消任务在控制块中的挂起的记录,置就绪态返回OS_NO_ERR返回OS_TASK_NOT_SUSPEND返回OS_TASK_RESUME_PRIO返回OS_PRIO_INVALID进入prio=OXFF?调用任务调度器OS_Sched()NONONOYESYESYESPrio是合法的优先级?取任务TCB的指针任务存在&&是被挂起的任务&&等待时间为0指针!=NULL挂起的任务,只能用本函数恢复。

第五节其他任务管理函数任务的优先级的修改INT8UOSTaskChangPrio( INT8Uoldprio,//任务原来的优先级 INT8Unewprio//任务新的优先级 )查询任务 INT8UOSTaskQuery( INT8Uprio , //待查询任务的优先级 OS_TCB*pdata //储存任务信息的结构 )任务的删除 INT8UOSTaskDel(INT8Uprio)//参数为删除任务的优先级

任务的删除任务的删除可以删除:任务自已,参数为OS_PRIO_SELF.将其它任务删除,参数为INT8Uprio。任务删除函数OSTaskDel(INT8Uprio)。如果参数为OS_PRIO_SELF,则从当前任务块中找出prio。任务的删除要做四件事:从任务控制块链表中删除对应该优先级的任务控制块。将对应该优先级的任务控制块,加到空任务控制块链表。在就绪表中,把对应该优先级的任务的就绪状态位置0。执行一次调度。为了保护资源不流失,在实应用中不可直接调用此函数,将任务删除。必须由另一个任务先调用任务删除请求函数申请删除该任务。请求成功后,该任务的OS_TCB的成员OSTCBDelReq值为OS_TASK_DEL_REQ。而该任务同样不断调用任务删除请求函数,其参数为OS_PRIO_SELF,当检测到返回值为OS_TASK_DEL_REQ时,该任务要先释放资源,后调用任务删除函数删除该任务。

任务的删除请求OSTaskDelReq()任务的删除请求OSTaskDelReq()有两种正常执行结果:⑴当优先级不为OS_PRIO_SELF时,返回值为OS_NO_ERR,且置OS_TCB中的成员变量OSTCBDelReq的值为OS_TASK_DEL_REQ⑵当优先级为OS_PRIO_SELF时,返回值为OS_TCB中的成员变量OSTCBDelReq的值整个执行过程如图所示:

任务的删除请求OSTaskDelReq()prio是空闲任务?prio是合法的优先级?prio=OS_PRIO_SELF?prio任务的TCB不存在?进入返回OS_TASK_NOT_EXIST返回被删除任务的OS_TCB的成员OSTCBDelReq的值置prio任务OS_TCB的OSTCBDelReq的值为OS_TASK_DEL_REQ返回OS_NO_ERR返回OS_PRIO_INVALID返回OS_TASK_IDLE_PRIOYesYesYesYesNoNoNoNo

请求删除其它任务的任务代码VoidRequestorTask(void*pdata){INT8Uerr;pdata=pdatafor(;;){/*应用程序代码*/if(任务‘TaskToBeDelected()’是需要删除){//while(OSTaskDelReq(TASK_TO_DEL_PRIO)!=OS_TASK_NOT_EXIST)OSTimeDly(1);}}/*应用程序代码*/}这里TASK_TO_DEL_PRIO是需要删除的任务TaskToBeDelected的优先级。

需要删除自已的任务VoidTaskToBeDeleted(void*pdata){INT8Uerr;pdata=pdatafor(;;){/*应用程序代码*/if(OSTaskDelReq(OS_PRIO_SELF)==OS_TASK_DEL_REQ)释放所有占用的资源;释放所有动态内存;OSTaskDel(OS_PRIO_SELE);}else{/*应用程序代码*/}}该任务是别的任务请求删除的。所有的删除都是要允许的,即满足:OS_TASK_DEL_EN>0。

第六节任务级的任务调度—OS_Sched按照某种规则选择运行的任务叫调度。让CPU中止当前运行的任务,转而去运行另一任务叫切换。

C/OS是占先式实时多任务内核,优先级最高的任务一旦准备就绪,则拥有CPU的所有权开始投入运行。

C/OS中不支持时间片轮转法,每个任务的优先级要求不一样且是唯一的,所以任务调度的工作就是:查找准备就绪的最高优先级的任务并进行上下文切换。

C/OS任务调度所花的时间为常数,与应用程序中建立的任务数无关。

任务调度voidOS_Sched(void){INT8Uy;#ifOS_CRITICAL_METHOD==3OS_CPU_SRCPU_sr#endifOS_ENTER_CRITICAL();if((OSLockNesting=0)&&(OSIntNesting=0)){ y=OSUnMapTbl[OSRdyGrp]; OSPrioHighRdy=(INT8U)((y<<3)+OSUnMapTbl[OSRdyTbl[y]])if(OSPrioHighRdy!=

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论