第4章μc/OS-II嵌入式实时操作系统内核分析4.1μc/OS-II实时操作系统简介4.2μc/OS-II的内核结构分析4.3μc/OS-II的任务通信和同步μc/OS-II实时操作系统特点1.公开源代码2.可移植性3.可固化4.可裁减5.可剥夺性(抢占式内核)6.多任务运行7.可确定性8.任务栈9.系统服务10.中断管理11.稳定性和可靠性4.1μc/OS-II实时操作系统简介4.2μc/OS-II的内核结构分析4.2.1μc/OS-II的内核结构1.文件结构应用软件(用户代码)uC/OS-II内核文件(与处理器类型无关的代码)OS_CORE.COS_TASK.COS_FLAG.COS_TIME.COS_MBOX.CuCOS-II.COS_MEM.CuCOS-II.HOS_MUTEX.COS_SEM.COS_Q.CuC/OS-II配置文件(与应用程序有关)OS_CFG.HINCLUDES.H移植uC/OS-II(与处理器类型有关的代码)OS_CPU.HOS_CPU_C.COS_CPU_A.ASMCPU定时器图4.1.uC/OS-II的文件结构软件硬件4.2.1μc/OS-II的内核结构在使用uC/OS-II提供的任何功能之前,必须先调用OSInit()函数进行初始化。在main主函数中调用OSStart()启动多任务之前,至少要先建立一个任务。否则应用程序会崩溃。OSInit()初始化uC/OS-II所有的变量和数据结构,并建立空闲任务OS_TaskIdle(),这个任务总是处于就绪态。例:一个典型的应用程序main主函数voidmain(void){/*-----硬件初始化,等用户代码初始化-----*/init_mcu();init_lcd();init_hdtimer();OSInit();/*初始化uC/OS-II*/…/*通过调用OSTaskCreate()或OSTaskCreateExt()创建至少一个任务;*/OSTaskCreate(sample_Task,(void*)0,&sample_TaskStk[TASK_STK_SIZE-1],2);…/*通过调用OSSemCreate()创建信号量等任务通信方式;*/CalcSem=OSSemCreate(0);…OSStart();/*开始多任务调度!OSStart()永远不会返回*/}4.2.1μc/OS-II的内核结构4.2.1μc/OS-II的内核结构……..……..ISR1ISR2…….ISRnmain1()Main2()Main3()Main5()Main4()Main_n()图4.2由多个任务和多个中断组成的实时多任务系统4.2.1μc/OS-II的内核结构多任务应用程序任务1任务2任务3任务n………任务调度任务切换OS_TASK_SW()OSIntCtxSw()内存管理任务堆栈定时器CPURAM任务间通信任务管理ISRISR任务创建任务控制块任务删除信号量互斥信号量事件标志组事件控制块消息邮箱消息队列串行I/OISR时间管理时钟节拍挂起任务恢复任务uC/OS-II启动OSStart任务延时任务延时恢复ROMuC/OS-II初始化OSInit中断服务硬件操作系统应用程序图4-3uC/OS-II内核体系结构2、uC/OS-II内核体系结构4.2.2μc/OS-II的任务管理1.多任务把一个大型任务分解成多个小任务,然后在计算机中通过运行这些小任务,最终达到完成大任务的目的。在μC/OS-II中,与上述那些小任务对应的程序实体就叫做“任务”(实质上是一个线程),μC/OS-II就是一个能对这些小任务的运行进行管理和调度的多任务操作系统。在多任务系统中,任务是设计者实现应用系统的基本形式,也是μC/OS-II系统进行调度的基本单元。4.2.2μc/OS-II的任务管理voidYourTask(voidpdata){for(;;){/*用户代码*/}}voidYourTask(void*pdata){/*用户代码*/OSTaskDel(OS_PRIO_SELF);}4.2.2μc/OS-II的任务管理2.任务状态及其转换①睡眠态:指任务驻留在程序空间还没有交给μC/OS-II来管理。通过创建任务将任务交给μC/OS-II。任务被删除后就进入睡眠态。②就绪态:任务创建后就进入就绪态。③运行态:占用CPU资源运行的任务,该任务为进入就绪态的优先级最高的任务。任何时刻只能有一个任务处于运行态。④等待状态:由于某种原因处于等待状态的任务。⑤中断服务态:任务运行时被中断打断,进入中断服务态。正在执行的任务被挂起,中断服务子程序控制了CPU的使用权。正在运行的任务,需要等待一段时间或需要等待一个事件发生再运行时,该任务就会把CPU的使用权让给别的任务而使任务进入等待状态。任务在没有被配备任务控制块或被剥夺了任务控制块时的状态叫做任务的睡眠状态系统为任务配备了任务控制块且在任务就绪表中进行了就绪登记,这时任务的状态叫做就绪状态。处于就绪状态的任务如果经调度器判断获得了CPU的使用权,则任务就进入运行状态一个正在运行的任务一旦响应中断申请就会中止运行而去执行中断服务程序,这时任务的状态叫做中断服务状态3.任务管理4.2.2μc/OS-II的任务管理μC/OS-II可以管理最多64个任务。任务管理包括创建任务、删除任务、改变任务的优先级及挂起和恢复任务等。(1)建立任务OSTaskCreate()、OSTaskCreateExt()(2)任务堆栈uC/OS-II支持的处理器的堆栈既可以是递减的,也可以是递增的。4.2.2μc/OS-II的任务管理(3)删除任务,OSTaskDel()(4)请求删除任务,OSTaskDelReq()(5)改变任务优先级,OSTaskChangePrio()(6)挂起任务,OSTaskSuspend()(7)恢复任务,OSTaskResume()4.2.3μc/OS-II的任务调度μC/OS-II总是运行进入就绪态的优先级最高的任务。任务调度器的功能是:在就绪表中查找最高优先级的任务,然后进行必要的任务切换,运行该任务。μC/OS-II的任务调度有两种情况:任务级的任务调度是由于有更高优先级的任务进入就绪态,当前的任务的CPU使用权被剥夺,发生了任务到任务的切换,由OS_Sched()完成中断级的调度是指当前运行的任务被中断打断,由于ISR运行过程中有更高优先级的任务被激活进入就绪态,由OSIntExt()完成1.任务切换(1)任务级的任务切换OS_TASK_SW()①保存当前运行的任务的CPU寄存器值到该任务的堆栈。②将要运行的高优先级的任务的寄存器值从堆栈恢复到CPU寄存器。③进行TCB的切换,并运行任务。(2)中断级的任务切换OSIntCtxSw()2.就绪表每个就绪的任务都放在就绪表中就绪表有两个变量:OSRdyGrp和OSRdyTbl[]OSRdyGrp中,将任务按优先级分组,八个为一组。OSRdyGrp的每一位代表每组任务是否有进入就绪态的任务。优先级判定表OSUnMapTbl[],OSUnMapTbl[]是常量表。4.2.4中断与时间管理1.中断管理μC/OS-II系统响应中断的过程:系统接收到中断请求后,这时如果CPU处于中断允许状态(即中断是开放的),系统就会中止正在运行的当前任务,而按照中断向量的指向转而去运行中断服务子程序;当中断服务子程序的运行结束后,系统将会根据情况返回到被中止的任务继续运行或者转向运行另一个具有更高优先级别的就绪任务。注意:中断服务子程序运行结束之后,系统将会根据情况进行一次任务调度去运行优先级别最高的就绪任务,而并不是一定要接续运行被中断的任务的。用户中断服务子程序:保存CPU寄存器;调用OSIntEnter();if(OSIntNesting==1){OSTCBCur-OSTCBStkPtr=SP;}清中断源;重新开中断;执行用户ISR代码;调用OSIntExit();恢复CPU寄存器;执行中断返回指令;4.2.4中断与时间管理2.时间管理(1)系统时钟4.2.4中断与时间管理μC/OS-II与大多数计算机系统一样,用硬件定时器产生一个周期为ms级的周期性中断来实现系统时钟,最小的时钟单位就是两次中断之间相间隔的时间,这个最小时钟单位叫做时钟节拍(TimeTick)。硬件定时器以时钟节拍为周期定时地产生中断,该中断的中断服务程序叫做OSTickISR()。中断服务程序通过调用函数OSTimeTick()来完成系统在每个时钟节拍时需要做的工作。4.2.4中断与时间管理voidOSTickISR(void){保存CPU寄存器;调用OSIntEnter();//记录中断嵌套层数if(OSIntNesting==1;{OSTCBCur-OSTCBStkPtr=SP;//保存堆栈指针}调用OSTimeTick();//节拍处理清除中断;开中断;调用OSIntExit();//中断嵌套层数减一恢复CPU寄存器;中断返回;}voidOSTimeTick(void){……OSTimeTickHook();……OSTime++;//记录节拍数……if(OSRunning==TRUE){ptcb=OSTCBList;while(ptcb-OSTCBPrio!=OS_IDLE_PRIO){OS_ENTER_CRITICAL();if(ptcb-OSTCBDly!=0){if(--ptcb-OSTCBDly==0)//任务的延时时间减一{if((ptcb-OSTCBStat&OS_STAT_SUSPEND)==OS_STAT_RDY){OSRdyGrp|=ptcb-OSTCBBitY;OSRdyTbl[ptcb-OSTCBY]|=ptcb-OSTCBBitX;}else{ptcb-OSTCBDly=1;}}}ptcb=ptcb-OSTCBNext;OS_EXIT_CRITICAL();}}(2)任务的延时4.2.4中断与时间管理由于嵌入式系统的任务是一个无限循环,并且μC/OS-II还是一个抢占式内核,所以为了使高优先级别的任务不至于独占CPU,可以给其他任务优先级别较低的任务获得CPU使用权的机会,μC/OS-II规定:除了空闲任务之外的所有任务必须在任务中合适的位置调用系统提供的函数OSTimeDly(),使当前任务的运行延时(暂停)一段时间并进行一次任务调度,以让出CPU的使用权。voidOSTimeDly(INT16Uticks){#ifOS_CRITICAL_METHOD==3OS_CPU_SRcpu_sr;#endifif(ticks0){OS_ENTER_CRITICAL();if((OSRdyTbl[OSTCBCur-OSTCBY]&=~OSTCBCur-OSTCBBitX)==0){OSRdyGrp&=~OSTCBCur-OSTCBBitY;//取消当前任务的就绪状态}OSTCBCur-OSTCBDly=ticks;//延时节拍数存入任务控制块OS_EXIT_CRITICAL();OS_Sched();//调用调度函数}}4.2.4中断与时间管理4.3μc/OS-II的任务通信和同步系统各任务之间通过“任务通信”的方式,实现任务的信息传递和同步控制,“任务通信”的载体就是----事件。用于任务同步和通信的信号量、消息邮箱、消息队列和互斥信号量都叫做“事件”。事件信号量(Sem)消息邮箱(Mbox)消息队列(Q)互斥信号量(Mutex)µC/OS-II将信号量、互斥信号量、消息邮箱、消息队列等统称为“事件”,然后通过一个称为“事件控制块(ECB)”的数据结构来管理事件。信号量的计数器或互斥信号量和优先级继承的计数器事件类型指向邮箱或消息队列的指针等待任务列表4.3.1事件控制块typedefstruct{INT8UOSEventType;//事件的类型INT16UOSEventCnt;//信号量计数器void*OSEventPtr;//消息邮箱或消息队列