UCOS时间片轮转调度算法详解2009年8月4日1.UCOS一种只支持优先级抢占型调度的操作系统。它不支持同一个优先级有2个及以上的任务同时运作。我修改的UCOS支持不同优先级调度的同时,支持同一个优先级有2个以上的任务以时间片轮转方式进行调度。这个就是UCOS和我修改的UCOS的区别。我修改后的UCOS,在以后的文段中就称为“FIFO-UCOS”。FIFO就是先进先出的意思,和时间片轮转调度差不多的意思。一.FIFO-UCOS--核心思想UCOS在调度的时候,会按照优先级选择进程进行调度,我做的部分就仅仅是在他进行优先级检查之前,把和运行态同等级的进程进行了替换,替换成了时间片轮转调度的下一个进程!二.TCB的修改FIFO-UCOS和UCOS并不能完全兼容,最大的改变,就是对TCB的结构做了改动,加入了我自己的段。该部分代码在UCOS-II.H文件中:typedefstructos_tcb{OS_STK*OSTCBStkPtr;/*当前任务堆栈栈顶指针*/#ifOS_TASK_CREATE_EXT_EN0void*OSTCBExtPtr;/*指向用户定义的任务控制块扩展*/OS_STK*OSTCBStkBottom;/*指向任务堆栈栈底指针*/INT32UOSTCBStkSize;/*存有栈中可容纳的指针元数目而不是用字节(Byte)表示的栈容量总数。*/INT16UOSTCBOpt;/*TaskoptionsaspassedbyOSTaskCreateExt()*/INT16UOSTCBId;/*TaskID(0..65535)存储任务的识别码ID,备用*/#endifstructos_tcb*OSTCBNext;/*指向后一个任务控制块的指针*/structos_tcb*OSTCBPrev;/*指向前一个任务控制块的指针*/#if((OS_Q_EN0)&&(OS_MAX_QS0))||(OS_MBOX_EN0)||(OS_SEM_EN0)||(OS_MUTEX_EN0)/*OS_EVENT_EN定义为:能使队列代码产生&&申请队列控制块最大数不为零||能使邮箱代码产生||能使信号量代码产生||能使互斥量代码产生*/OS_EVENT*OSTCBEventPtr;/*指向事件控制块的指针*/#endif#if((OS_Q_EN0)&&(OS_MAX_QS0))||(OS_MBOX_EN0)void*OSTCBMsg;/*MessagereceivedfromOSMboxPost()orOSQPost()指向传递给任务的消息的指针*/#endif#if(OS_VERSION=251)&&(OS_FLAG_EN0)&&(OS_MAX_FLAGS0)#ifOS_TASK_DEL_EN0/*OS版本大于等于251&&能使事件标志代码产生&&最大标志数大于零*/OS_FLAG_NODE*OSTCBFlagNode;/*指针指向事件标志节点*/#endifOS_FLAGSOSTCBFlagsRdy;/*Eventflagsthatmadetaskreadytorun事件标志使任务准备运行*/#endifINT16UOSTCBDly;/*任务等待的时限*/INT8UOSTCBStat;/*任务的当前状态标志*/INT8UOSTCBPrio;/*任务优先级(0==highest,63==lowest)*//*以下四行语句用于快速访问就绪表的数据*/INT8UOSTCBX;/*Bitpositioningroupcorrespondingtotaskpriority(0..7)*/INT8UOSTCBY;/*Indexintoreadytablecorrespondingtotaskpriority*/INT8UOSTCBBitX;/*Bitmasktoaccessbitpositioninreadytable*/INT8UOSTCBBitY;/*Bitmasktoaccessbitpositioninreadygroup*/#ifOS_TASK_DEL_EN0BOOLEANOSTCBDelReq;/*Indicateswhetherataskneedstodeleteitself*/#endif/***********************************************************************以下代码是我自己加的:**********************************************************************/#ifdefOS_TIME_SCHEDULEstructos_tcb*OSTSnext;structos_tcb*OSTSprev;INT8UOSTSLen;/*记录了该进程占用多少个时间片*/INT8UOSTSCurLen;/*记录的是该进程现在还剩下多少个时间片时间可以用*/#endif/***********************************************************************/}OS_TCB;三.进程创建进程创建的主要目的是跳过原代码中的优先级占用检查,并在这里加入FIFO进程创建。文件在OS_TASK.C中:INT8UOSTaskCreate(void(*task)(void*pd),void*pdata,OS_STK*ptos,INT8Uprio,INT16Uid,INT8UTSlen){#ifOS_CRITICAL_METHOD==3/*为CPU状态寄存器分配存储空间*/OS_CPU_SRcpu_sr;//CPU状态字是十六位cpu_sr为OS_CPU_SR型变量#endifOS_STK*psp;//创建一个指向数据类型为OS_STK的指针和一个8位的整型数INT8Uerr;#ifOS_ARG_CHK_EN0if(prioOS_LOWEST_PRIO){/*保证优先级在允许范围内*/return(OS_PRIO_INVALID);}#endifOS_ENTER_CRITICAL();/*OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()为定义的宏,用来关闭、打开CPU的中断。*/if(OSTCBPrioTbl[prio]==(OS_TCB*)0){/*保证优先级没有被其它任务占用*//***********************************************************************ifyouwantruntheFIFOmaskthiscodeOSTCBPrioTbl[prio]=(OS_TCB*)1;/*Reservetheprioritytopreventothersfromdoing...*//*...thesamethinguntiltaskiscreated.*///那就是说有一个任务存在了,不再是Nul/***********************************************************************/OS_EXIT_CRITICAL();psp=(OS_STK*)OSTaskStkInit(task,pdata,ptos,0);/*初始化任务堆栈,即建立任务堆栈*/err=OS_TCBInit(prio,psp,(OS_STK*)0,id,0,(void*)0,0,TSlen);/*初始化任务控制块,从空闲的OS_TCB缓冲池中获得并初始化一个任务控制块*/if(err==OS_NO_ERR){//如果初始化没有错OS_ENTER_CRITICAL();//进入临界状态OSTaskCtr++;/*任务数量加一*/OS_EXIT_CRITICAL();if(OSRunning==TRUE){/*如果多任务开始,寻找最高优先级任务*/OS_Sched();}}else{//如果初始化任务控制块有错OS_ENTER_CRITICAL();OSTCBPrioTbl[prio]=(OS_TCB*)0;/*Makethispriorityavailabletoothers把这一优先级给其它任务*/OS_EXIT_CRITICAL();}return(err);//返回错误信息/***********************************************************************/else//这是FIFO的任务创建代码{OS_EXIT_CRITICAL();psp=(OS_STK*)OSTaskStkInit(task,pdata,ptos,0);/*Initializethetask'sstack初始化任务堆栈,即建立任务堆栈*/err=OS_TCBInit(prio,psp,(OS_STK*)0,id,0,(void*)0,0,TSlen);if(err==OS_NO_ERR){OS_ENTER_CRITICAL();OSTaskCtr++;/*任务数量加一*/OS_EXIT_CRITICAL();if(OSRunning==TRUE){/*Findhighestprioritytaskifmultitaskinghasstarted*/OS_Sched();}}return(err);}/***********************************************************************/OS_EXIT_CRITICAL();return(OS_PRIO_EXIST);}其中加入的传递参数有两个,一个是id,一个是TSLen因为会出现同优先级的任务,那么采用优先级做为任务ID的方式是不可取的了,我们必须加入任务id段TSLen段,是该进程的时间片为多长。四.进程初始化进程初始化基本保留以前的东西不动,要的就仅仅是把TSLen加入TCB,把上面说到的那个链表链接起来。代码在文件OS_CORE.C中初始化任务控制块1.参数:prio:任务创建时的优先级2.ptos:假定CPU寄存器放置于堆栈中指向堆栈栈顶的指针。栈顶当OS_STK_GROWTH为1时是寄存器的高位、当OS_STK_GROWTH为0时是寄存器的低位,堆栈增长是CPU的特权。3.pbos:栈底指针。由OSTaskCreate()调用时传入空指针。4.id:任务的ID5.stk_size:堆栈大小。当堆栈单位是int8us时,堆栈大小包含堆栈数量个字节,当堆栈单位是int32us时,堆栈大小包含“4*stk_size”个字节。堆栈单位由“#defineconstantOS_STK”建立,它是CPU特有。如果被OSTaskCreate()调用stk_size为0。6.pext:用户提供存储器空间的指针,用于任务控制块。允许存储浮点寄存器常量,MMU寄存器或者其它在内容转换时有用的东西。甚至在TCB扩展中为每个任务指定一个名字存到这个名字里面。OSTaskCreate()调用的时候为空指针。7opt:传到OSTaskCreateExt()时可以选择,被OSTaskCreate()调用的时候为0。INT8UOS_TCBInit(INT8Uprio,OS_STK*ptos,OS_STK*pbos,INT16Uid,INT32Ustk_size,void*pext,INT16Uopt,INT8UTSlen){#ifOS_CRITICAL_METHOD==3/*为CPU状态寄存器分配存储空间*/OS_CPU_SRcpu_sr;#endifOS_TCB*ptcb;OS_ENTER_CRITICAL();ptcb=OSTCBFreeList;/*从空TCB列表中得到一块空TCB*/if(ptcb!=(OS_TCB*)0){//分配空TCB成功OSTCBFreeList=ptcb-OSTCBNext