资源预览内容
第1页 / 共170页
第2页 / 共170页
第3页 / 共170页
第4页 / 共170页
第5页 / 共170页
第6页 / 共170页
第7页 / 共170页
第8页 / 共170页
第9页 / 共170页
第10页 / 共170页
亲,该文档总共170页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
1实时操作系统实时操作系统C/OS-II1 13 32 24 4 C/OS-II概述概述任务管理任务管理中断和时间中断和时间管理管理任务之间的通信与任务之间的通信与同步同步5 5存储管理存储管理2通用操作系统和嵌入式(实时)操作系统通用操作系统和嵌入式(实时)操作系统l通用操作系统:通用操作系统:Windows/NT/XP、Linux、UNIX等,用于等,用于PC机、机、服务器,服务器,l嵌入式(实时)操作系统:用于嵌入式设备的操作系统,具有通嵌入式(实时)操作系统:用于嵌入式设备的操作系统,具有通用操作系统的基本特点,又具有系统实时性、硬件的相关依赖性、用操作系统的基本特点,又具有系统实时性、硬件的相关依赖性、软件固态化以及应用的专用性等特点;软件固态化以及应用的专用性等特点;l嵌入式(实时)操作系统通常包括与硬件相关的底层驱动软件、嵌入式(实时)操作系统通常包括与硬件相关的底层驱动软件、系统内核、设备驱动接口、通信协议、图形界面、标准化浏览器系统内核、设备驱动接口、通信协议、图形界面、标准化浏览器Browser等;等;l嵌入式(实时)操作系统的重要指标:实时性(中断响应时间、嵌入式(实时)操作系统的重要指标:实时性(中断响应时间、任务切换时间等)、尺寸(可裁剪性任务切换时间等)、尺寸(可裁剪性)、可扩展性(内核、中间)、可扩展性(内核、中间件);件);3嵌入式操作系统的发展嵌入式操作系统的发展操作系统内核操作系统内核应用程序应用程序驱动程序和固件驱动程序和固件操作系统内核操作系统内核文件系统文件系统驱动程序和固件驱动程序和固件API GUI应用程序应用程序操作系统内核操作系统内核文件系统文件系统驱动程序和固件驱动程序和固件API GUI应用程序应用程序通信协议通信协议库函数库函数80年代初期年代初期80年代中期年代中期-90年代中年代中期期90年代末期年代末期-21世纪世纪4常见的嵌入式操作系统常见的嵌入式操作系统 实时嵌入式操作系统的种类繁多,大体上可分为两实时嵌入式操作系统的种类繁多,大体上可分为两种,商用型和免费型。种,商用型和免费型。l商用型的实操作系统功能稳定、可靠,有完善的技商用型的实操作系统功能稳定、可靠,有完善的技术支持和售后服务,但往往价格昂贵术支持和售后服务,但往往价格昂贵, ,如如VxworksVxworks、QNXQNX、WinCEWinCE、Palm OSPalm OS等。等。l免费型的实时操作系统在价格方面具有优势,目前免费型的实时操作系统在价格方面具有优势,目前主要有主要有Linux,C/OSLinux,C/OS是一种源码开放的商业是一种源码开放的商业RTOSRTOS;C/OS是商业操作是商业操作系统系统5学习嵌入式操作系统学习嵌入式操作系统 l学习一种实时操作系统学习一种实时操作系统RTOSRTOS,如,如uc/OS,uc/OS,掌握实时系掌握实时系统的概念和设计方法;统的概念和设计方法;l嵌入式系统以应用为中心,应用时选择嵌入式系统以应用为中心,应用时选择“适用适用”的的操作系统;操作系统;l嵌入式嵌入式LinuxLinux;l自己自己“写写”RTOSRTOS一种学习态度;一种学习态度;6C/OS-II的层次示意图的层次示意图l基于基于C/OS-II的的嵌入式系统软件嵌入式系统软件层次示意图如右层次示意图如右图所示图所示7RTOSRTOS在嵌入式系统中的位置在嵌入式系统中的位置嵌入式硬件平台BSPKERNELFSTCP/IP设备驱动设备驱动设备设备I/O调试工具调试工具其它组件其它组件应用RTOSC/C+8C/OS简介1、C/OSMicro Controller O S,微控制器操作系统2 2、 C/OSC/OS简介l美国人美国人Jean Labrosse 1992Jean Labrosse 1992年完成年完成l应用面覆盖了诸多领域,如照相机、医疗器械、音响设备、发动应用面覆盖了诸多领域,如照相机、医疗器械、音响设备、发动机控制、高速公路电话系统、自动提款机等机控制、高速公路电话系统、自动提款机等 l19981998年年 C/OSC/OS-II-II,目前的版本,目前的版本 C/OSC/OS -II V2.61 -II V2.61,2.722.72l20002000年,得到美国航空管理局(年,得到美国航空管理局(FAAFAA)的认证,可以用于飞行器)的认证,可以用于飞行器中中l网站(网站(www.micrium.com)www.micrium.com)9u公开源代码公开源代码u可移植性(可移植性(PortablePortable) 绝大部分绝大部分 C/OS-IIC/OS-II的源码是用移植性很强的的源码是用移植性很强的ANSI CANSI C写的。和微处理器写的。和微处理器硬件相关的那部分是用汇编语言写的。汇编语言写的部分已经压到最低硬件相关的那部分是用汇编语言写的。汇编语言写的部分已经压到最低限度,使得限度,使得 C/OS-IIC/OS-II便于移植到其他微处理器上。便于移植到其他微处理器上。 C/OS-IIC/OS-II可以在绝可以在绝大多数大多数8 8位、位、1616位、位、3232位以至位以至6464位微处理器、微控制器位微处理器、微控制器 、数字信号处理、数字信号处理器(器(DSPDSP)上运行。)上运行。u可固化(可固化(ROMableROMable) C/OS-IIC/OS-II是为嵌入式应用而设计的,这就意味着,只要读者有固化手是为嵌入式应用而设计的,这就意味着,只要读者有固化手段(段(C C编译、连接、下载和固化),编译、连接、下载和固化), C/OS-IIC/OS-II可以嵌入到读者的产品可以嵌入到读者的产品中成为产品的一部分。中成为产品的一部分。u可裁剪(可裁剪(ScalableScalable) 可以只使用可以只使用 C/OS-IIC/OS-II中应用程序需要的那些系统服务。也就是说某产中应用程序需要的那些系统服务。也就是说某产品可以只使用很少几个品可以只使用很少几个 C/OS-IIC/OS-II调用,而另一个产品则使用了几乎所调用,而另一个产品则使用了几乎所有有 C/OS-IIC/OS-II的功能,这样可以减少产品中的的功能,这样可以减少产品中的 C/OS-IIC/OS-II所需的存储器空所需的存储器空间(间(RAMRAM和和ROMROM)。这种可剪裁性是靠条件编译实现的。)。这种可剪裁性是靠条件编译实现的。C/OS的性能特点(一)10u占先式(占先式(PreemptivePreemptive)u多任务多任务 C/OS-IIC/OS-II可以管理可以管理6464个任务,然而,目前这一版本保留个任务,然而,目前这一版本保留8 8个给系统。应用程序最多个给系统。应用程序最多可以有可以有256256个任务个任务u可确定性可确定性 全部全部 C/OS-IIC/OS-II的函数调用与服务的执行时间具有可确定性。的函数调用与服务的执行时间具有可确定性。u任务栈任务栈 每个任务有自己单独的栈,每个任务有自己单独的栈, C/OS-IIC/OS-II允许每个任务有不同的栈空间,以便压低应允许每个任务有不同的栈空间,以便压低应用程序对用程序对RAMRAM的需求。的需求。u系统服务系统服务 C/OS-IIC/OS-II提供很多系统服务,例如邮箱、消息队列、信号量、块大小固定的内存提供很多系统服务,例如邮箱、消息队列、信号量、块大小固定的内存的申请与释放、时间相关函数等。的申请与释放、时间相关函数等。u中断管理中断管理 中断可以使正在执行的任务暂时挂起,如果优先级更高的任务被该中断唤醒,则中断可以使正在执行的任务暂时挂起,如果优先级更高的任务被该中断唤醒,则高优先级的任务在中断嵌套全部退出后立即执行,中断嵌套层数可达高优先级的任务在中断嵌套全部退出后立即执行,中断嵌套层数可达255255层。层。u稳定性与可靠性稳定性与可靠性C/OS的性能特点(二)11C/OS-IIC/OS-II图书图书l描述了描述了C/OS-IIC/OS-II内部的工作原理内部的工作原理l随书的随书的CDCD中包含了源代码中包含了源代码n工业界最清晰的源代码工业界最清晰的源代码l除英文版外,有中文和韩文版除英文版外,有中文和韩文版ChineseKoreanEnglishISBN 1-57820-103-9美国CMP BOOK ISBN 7-81077-290-2北京航空航天大学出版社ISBN 89-951540-5-512C/OS-II的各种商业应用l全世界有数百种产品在应用全世界有数百种产品在应用: :lAvionicslMedicallCellphoneslRoutersandswitcheslHigh-endaudioequipmentlWashingmachinesanddryerslUPS(UninterruptiblePowerSupplies)lIndustrialcontrollerslGPSNavigationSystemslMicrowaveRadioslInstrumentationlPoint-of-saleterminalsl更多更多13C/OS-II提供的系统服务l信号量信号量l带互斥机制的信号量带互斥机制的信号量n减少优先级倒置的问题减少优先级倒置的问题l事件标志事件标志l消息信箱消息信箱l消息队列消息队列l内存管理内存管理l时钟管理时钟管理l任务管理任务管理14C/GUIandC/FSlC/GUIC/GUIl嵌入式的用户界面嵌入式的用户界面l用用ANSI CANSI C书写书写l支持任何支持任何8, 16, 32-bits CPU8, 16, 32-bits CPUl彩色,灰、度,等级或黑白显示彩色,灰、度,等级或黑白显示l代码尺寸小代码尺寸小lC/FSC/FSl嵌入式的文件系统嵌入式的文件系统Written in ANSI CWritten in ANSI Cl用用ANSI CANSI C书写书写l支持任何支持任何8, 16, 32-bits CPU8, 16, 32-bits CPUl支持支持SMC, MMC, SD, CF, IDE, Flash, RAMSMC, MMC, SD, CF, IDE, Flash, RAM其他介质其他介质15可移植的可移植的数据类型数据类型typedefunsignedcharBOOLEAN;typedefunsignedcharINT8U;typedefsignedcharINT8S;typedefunsignedintINT16U;typedefsignedintINT16S;typedefunsignedlongINT32U;typedefsignedlongINT32S;typedeffloatFP32;typedefdoubleFP64;16C/OS-II的文件结构171 13 32 24 4 C/OS-II概述概述任务和任务管理任务和任务管理中断和时间中断和时间管理管理任务之间的通信与任务之间的通信与同步同步5 5存储管理存储管理18任务的实现任务的实现创建任务的系统服务创建任务的系统服务lOSTaskCreate()INT8UOSTaskCreate(void(*task)(void*pd),/任务代码指针任务代码指针void*pdata,/任务参数指针任务参数指针OS_STK*ptos,/任务栈的栈顶指针任务栈的栈顶指针INT8Uprio/任务的优先级任务的优先级);lOSTaskCreateExt()提问:提问: C/OS-II中的任务是进程还是线程?中的任务是进程还是线程?19任务主函数任务主函数一个任务通常是一个无限循环(返回值类型一个任务通常是一个无限循环(返回值类型voidvoid)voidMyTask(void*pdata)while(1)dosomething;waiting;dosomething;Why?20任务也可以自我删除(并非真的删除,只是内核不任务也可以自我删除(并非真的删除,只是内核不再知道该任务)再知道该任务)voidMyTask(void*pdata)./*用户代码用户代码*/OSTaskDel(OS_PRIO_SELF);21lC/OS-C/OS-可以管理多达可以管理多达6464个任务;个任务;l每个任务被赋以不同的优先级,取值从每个任务被赋以不同的优先级,取值从0 0到到OS_LOWEST_PRIO-2OS_LOWEST_PRIO-2,数值越小,优先级越高;,数值越小,优先级越高;l系统保留了优先级为系统保留了优先级为0 0、1 1、2 2、3 3、OS_LOWEST_PRIO-3OS_LOWEST_PRIO-3、OS_LOWEST_PRI0-2OS_LOWEST_PRI0-2,OS_LOWEST_PRI0-1OS_LOWEST_PRI0-1以及以及OS_LOWEST_PRI0OS_LOWEST_PRI0这这8 8个任务个任务以被将来使用,用户可以有以被将来使用,用户可以有5656个应用任务;个应用任务;l任务的优先级同样也是它的标识号任务的优先级同样也是它的标识号IDID。OS_CFG.H中定义中定义6322空闲任务和统计任务空闲任务和统计任务l内核总是创建一个内核总是创建一个空闲任务空闲任务OSTaskIdle()OSTaskIdle();w总是设置为最低优先级,总是设置为最低优先级,OS_LOWEST_PRIOROS_LOWEST_PRIOR;w当所有其他任务都未在执行时,空闲任务开始当所有其他任务都未在执行时,空闲任务开始执行;执行;w应用程序不能删除该任务;应用程序不能删除该任务;w空闲任务的工作就是把空闲任务的工作就是把3232位计数器位计数器OSIdleCtrOSIdleCtr加加1 1,该计数器被统计任务所使用;,该计数器被统计任务所使用;l统计任务统计任务OSTaskStat()OSTaskStat(),提供运行时间统计。每,提供运行时间统计。每秒钟运行一次,计算当前的秒钟运行一次,计算当前的CPUCPU利用率。其优先级利用率。其优先级是是OS_LOWEST_PRIOR-1OS_LOWEST_PRIOR-1,可选。,可选。23任务控制块任务控制块TCBTCBl任务控制块任务控制块 OS_TCBOS_TCB是描述一个任务的核是描述一个任务的核心数据结构,存放了它的各种管理信息,心数据结构,存放了它的各种管理信息,包括任务堆栈指针,任务的状态、优先包括任务堆栈指针,任务的状态、优先级,任务链表指针等;级,任务链表指针等;l一旦任务建立了,任务控制块一旦任务建立了,任务控制块OS_TCBOS_TCB将将被赋值。被赋值。24任务控制块任务控制块TCBTCBtypedefstructos_tcb栈指针;栈指针;INT16UOSTCBId;/*任务的任务的ID*/链表指针;链表指针;OS_EVENT*OSTCBEventPtr;/*事件指针事件指针*/void*OSTCBMsg;/*消息指针消息指针*/INT8UOSTCBStat;/*任务的状态任务的状态*/INT8UOSTCBPrio;/*任务的优先级任务的优先级*/其他其他OS_TCB;25栈指针栈指针lOSTCBStkPtrOSTCBStkPtr:指向当前任务栈顶的指针,指向当前任务栈顶的指针,每个任务可以有自己的栈,栈的容量可以每个任务可以有自己的栈,栈的容量可以是任意的;是任意的;lOSTCBStkBottomOSTCBStkBottom:指向任务栈底的指针;:指向任务栈底的指针;lOSTCBStkSizeOSTCBStkSize:栈的容量,用可容纳的指:栈的容量,用可容纳的指针数目而不是字节数(针数目而不是字节数(ByteByte)来表示。)来表示。2627链表指针链表指针l所有的任务控制块分属于两条不同的链表,所有的任务控制块分属于两条不同的链表,单向的单向的空闲链表空闲链表(头指针为(头指针为OSTCBFreeListOSTCBFreeList)和双向的)和双向的使用链表使用链表(头(头指针为指针为OSTCBListOSTCBList););lOSTCBNextOSTCBNext、OSTCBPrevOSTCBPrev:用于将任务控制用于将任务控制块插入到空闲链表或使用链表中。每个任块插入到空闲链表或使用链表中。每个任务的任务控制块在任务创建的时候被链接务的任务控制块在任务创建的时候被链接到使用链表中,在任务删除的时候从链表到使用链表中,在任务删除的时候从链表中被删除。双向连接的链表使得任一成员中被删除。双向连接的链表使得任一成员都能快速插入或删除。都能快速插入或删除。28空闲空闲TCBTCB链表链表l所有的任务控制块都被放置在任务控制块列表数组所有的任务控制块都被放置在任务控制块列表数组OSTCBTbl中,系统初始化时,所有中,系统初始化时,所有TCBTCB被链接成空闲的单向链表,被链接成空闲的单向链表,头指针为头指针为OSTCBFreeListOSTCBFreeList。当创建一个任务后,就把。当创建一个任务后,就把OSTCBFreeListOSTCBFreeList所指向的所指向的TCBTCB赋给了该任务,并将它加入到赋给了该任务,并将它加入到使用链表中,然后把使用链表中,然后把OSTCBFreeListOSTCBFreeList指向空闲链表中的下一指向空闲链表中的下一个结点。个结点。29系统初始化后系统初始化后指针数组,指向相应指针数组,指向相应TCB30任务的状态休眠任务的状态休眠l休眠状态休眠状态(Dormant):任务存在于内存):任务存在于内存空间中,但内核不可见;空间中,但内核不可见;l可以通过以下函数通知内核,使之变为就可以通过以下函数通知内核,使之变为就绪状态:绪状态:OSTaskCreate()或或OSTaskCreateExt()l可以通过以下函数返回到休眠状态:可以通过以下函数返回到休眠状态:OSTaskDel()31任务的状态就绪任务的状态就绪l就绪状态就绪状态(Ready):万事具备,只欠):万事具备,只欠CPU;l在所有的就绪任务当中,具有最高优先级在所有的就绪任务当中,具有最高优先级的任务被选中去运行;的任务被选中去运行;l如果任务在运行的时候被抢占了如果任务在运行的时候被抢占了CPU(任务任务被中断时才可能被抢占)被中断时才可能被抢占),则又回到就绪状则又回到就绪状态。态。32任务的状态运行任务的状态运行l运行状态运行状态(Running):任务在):任务在CPU上运上运行;行;l当一个任务在运行时,如果没有关闭中断,当一个任务在运行时,如果没有关闭中断,则有可能被中断所打断;则有可能被中断所打断;l当一个任务在运行时,可能因为各种原因进当一个任务在运行时,可能因为各种原因进入阻塞状态。入阻塞状态。OSMBoxPend(),OSQPend(),OSSemPend()OSTaskSuspend(),OSTimeDly()33任务的状态任务的状态ISRISRl中断服务状态中断服务状态(ISR):该任务原来在):该任务原来在CPU上运行,后来被中断所打断,由中断服务程上运行,后来被中断所打断,由中断服务程序序ISR接管了接管了CPU;l当中断服务程序运行完毕后,内核要判断是当中断服务程序运行完毕后,内核要判断是否有新的、更高优先级的任务就绪,如果有,否有新的、更高优先级的任务就绪,如果有,则原有的任务被抢占;如果没有,则原有的则原有的任务被抢占;如果没有,则原有的任务重新运行。任务重新运行。34任务的状态阻塞任务的状态阻塞l阻塞阻塞/等待状态等待状态(Waiting):任务由于正在):任务由于正在等待某个事件(信号量、邮箱或队列)而被等待某个事件(信号量、邮箱或队列)而被挂起;挂起;l当任务等待的事件发生时,回到就绪状态。当任务等待的事件发生时,回到就绪状态。OSMBoxpost(),OSQPost(),OSSemPost(),OSTaskResume(),OSTimeDlyResume()或或OSTimeTick()35状态的转换状态的转换删除任务删除任务36任务就绪表及其操作管理任务就绪表及其操作管理l多个任务的就绪态优先顺序是靠任务就绪表管理多个任务的就绪态优先顺序是靠任务就绪表管理的,就是用存放任务准备就绪标志的列表管理。的,就是用存放任务准备就绪标志的列表管理。对其操作设置算法的设计,要求能保证每次任务对其操作设置算法的设计,要求能保证每次任务的调度切换时间的可确定性、一致性和高速性。的调度切换时间的可确定性、一致性和高速性。l为了做到这点,为了做到这点,C/OSC/OS设计者采用一种特殊的算设计者采用一种特殊的算法方式。整个法方式。整个操作设置算法由两个变量(操作设置算法由两个变量(OSRdyGrpOSRdyGrp, OSRdyTbl8OSRdyTbl8),两个表格(),两个表格(OSMapTblIndexOSMapTblIndex,INT8U const OSUnMapTbl INT8U const OSUnMapTbl ),三个程序组成。三个程序分别用于任务登),三个程序组成。三个程序分别用于任务登记进入就绪态、任务脱离就绪态、找出最高优先记进入就绪态、任务脱离就绪态、找出最高优先级就绪态任务级就绪态任务三种就绪表操作。三种就绪表操作。37任务就绪表及其操作管理任务就绪表及其操作管理l每个任务的就绪态标志放入在就绪表中,就绪表每个任务的就绪态标志放入在就绪表中,就绪表中有两个变量中有两个变量OSRdyGrpOSRdyGrp、OSRdyTblOSRdyTbl。每个任务。每个任务就绪标志置于就绪标志置于OSRdyTblOSRdyTbl相应位中。在相应位中。在登记进入登记进入就绪态就绪态对对OSRdyGrpOSRdyGrp的操作,是为了在第三种操作的操作,是为了在第三种操作时提供有效的信息。时提供有效的信息。l在在OSRdyGrpOSRdyGrp中,任务按优先级分组,中,任务按优先级分组,8 8个任务为个任务为一组。一组。OSRdyGrpOSRdyGrp中的每一位表示中的每一位表示8 8组任务中每一组任务中每一组中是否有进入就绪态的任务。任务进入就绪态组中是否有进入就绪态的任务。任务进入就绪态时,就绪表时,就绪表OSRdyTblOSRdyTbl中的相应元素的相应位也中的相应元素的相应位也置位。置位。38任务就绪表任务就绪表OSRdyGrp OSRdyGrp 1207 6 5 4 300X XX XX XY YY Y Y Y任务优先级任务优先级 20176543108915 14 13 12 1118161723 22 21 20 1926242531 30 29 28 2734323339 38 37 36 3542404147 46 45 44 4350484955 54 53 52 5158565763 62 61 60 5901234567OSRdyTbl8OSRdyTbl8X XY Y优先级最低任务优先级最低任务 (空闲任务)(空闲任务) 优先级最高任务优先级最高任务 任务优先级号任务优先级号 对于整数对于整数OSRdyTbli(0 i 7),若它的某一位),若它的某一位为为1,则,则OSRdyGrp的第的第i位为位为1。任务的优先级由任务的优先级由X和和Y确定确定39任务调度器任务调度器C/OS-II任务就绪表任务就绪表40根据优先级确定就绪表根据优先级确定就绪表(1)(1)n假假 设设 优优 先先 级级 为为 1212的的 任任 务务 进进 入入 就就 绪绪 状状 态态 ,12=1100b,12=1100b,则则 OSRdyTbl1OSRdyTbl1的的 第第 4 4位位 置置 1 1, 且且OSRdyGrpOSRdyGrp的第的第1 1位置位置1 1,相应的数学表达式为,相应的数学表达式为: : OSRdyGrp |=0x02OSRdyGrp |=0x02; OSRdyTbl1 |=0x10;OSRdyTbl1 |=0x10;n而而优优先先级级为为2121的的任任务务就就绪绪21=10 21=10 101b101b,则则OSRdyTbl2OSRdyTbl2的的第第5 5位位置置1 1,且且OSRdyGrpOSRdyGrp的的第第2 2位位置置1,1,相应的数学表达式为:相应的数学表达式为: OSRdyGrp |=0x04OSRdyGrp |=0x04; OSRdyTbl2 |=0x20;OSRdyTbl2 |=0x20;41根据优先级确定就绪表根据优先级确定就绪表(2)(2)n从从上上面面的的计计算算可可知知: :若若OSRdyGrpOSRdyGrp及及OSRdyBblOSRdyBbl的的第第n n位位置置1 1,则则应应该该把把OSRdyGrpOSRdyGrp及及OSRdyBblOSRdyBbl的的值值与与2 2n n 相相或或。uC/OSuC/OS中中,把把2 2n n的的n=0-7n=0-7的的8 8个个值先计算好存在数组值先计算好存在数组OSMapTbl7OSMapTbl7中中, ,也就是:也就是: OSMapTbl0 = 2OSMapTbl0 = 20 0 = 0x01= 0x01(0000 00010000 0001) OSMapTbl1 = 2OSMapTbl1 = 21 1 = 0x02= 0x02(0000 00100000 0010) OSMapTbl7 = 2 OSMapTbl7 = 27 7 = 0x80= 0x80(1000 00001000 0000)42掩码映射表掩码映射表表表 OSMapTblIndexOSMapTblIndex的值的值IndexBit Mask (Binary)00000000110000001020000010030000100040001000050010000060100000071000000043使任务进入就绪态使任务进入就绪态n如如果果prioprio是是任任务务的的优优先先级级,即即任任务务的的标标识识号号,则则将将任任务务放入就绪表,即使放入就绪表,即使任务进入就绪态的方法任务进入就绪态的方法(程序)是:程序)是:OSRdyGrp |= OSMapTblprio3;OSRdyGrp |= OSMapTblprio3;OSRdyTblprio3 |= OSMapTblprio&0x07;OSRdyTblprio3 |= OSMapTblprio&0x07;n假设优先级为假设优先级为12121100b1100bOSRdyGrp |= OSMapTbl123(0x02)OSRdyGrp |= OSMapTbl123(0x02);OSRdyTbl1 |=0x10;OSRdyTbl1 |=0x10;44使任务使任务脱离脱离就绪态就绪态n将将任任务务就就绪绪表表OSRdyTblprio3OSRdyTblprio3相相应应元元素素的的相相应应位位清清零零,而而且且当当OSRdyTblprio3OSRdyTblprio3中中的的所所有有位位都都为为零零时时,即即该该任任务务所所在在组组的的所所有有任任务务中中没没有有一一个个进进入入就就绪绪态态时时,OSRdyGrpOSRdyGrp的相应位才为零。的相应位才为零。任务脱离就绪态的方法任务脱离就绪态的方法(程序)是:程序)是:if(OSRdyTblprio3&= OSMapTblprio&0x07)=0)OSRdyGrp&= OSMapTblprio3;45根据就绪表确定最高优先级根据就绪表确定最高优先级两个关键两个关键: :l将优先级数将优先级数分解分解为高三位和低三位分别确为高三位和低三位分别确定;定;l高优先级有着小的优先级号;高优先级有着小的优先级号;46根据就绪表确定最高优先级根据就绪表确定最高优先级l通过通过OSRdyGrpOSRdyGrp值确定高值确定高3 3位,假设位,假设OSRdyGrpOSRdyGrp0x08=0x08=0x000010000x00001000,第,第3 3位为位为1 1,优先级的高,优先级的高3 3位为位为011011; ;l通过通过OSRdyTbl3OSRdyTbl3的值来确定低的值来确定低3 3位,假设位,假设OSRdyTbl3OSRdyTbl30x3a0x3a,第,第1 1位为位为1 1,优先级的低,优先级的低3 3位为位为001001,3*8+1=3*8+1=252500011001任务优先级任务优先级47源代码中使用了查表法n查查表表法法具具有有确确定定的的时时间间,增增加加了了系系统统的的可可预预测测性性,uC/OSuC/OS中中所所有有的的系系统统调调用用时时间间都都是是确定的确定的Y=OSUnMapTblOSRdyGrp;X=OSUnMapTblOSRdyTblY;Prio=(Y3)+X;参参见见OS_CORE.C48INT8UconstOSUnMapTbl=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;优先级判定表OSUnMapTbl256举例:举例: 如如OSRdyGrpOSRdyGrp的值为的值为01101000B01101000B,即,即0X680X68,则查,则查得得OSUnMapTblOSRdyGrpOSUnMapTblOSRdyGrp的的值是值是3 3,它相应于,它相应于OSRdyGrpOSRdyGrp中的第中的第3 3位置位置1 1; 如如OSRdyTbl3OSRdyTbl3的值是的值是11100100B11100100B,即,即0XE40XE4,则查,则查OSUnMapTblOSRdyTbl3OSUnMapTblOSRdyTbl3的值是的值是2 2,则进入就绪态的,则进入就绪态的最高任务优先级最高任务优先级 Prio=3*8+2=26Prio=3*8+2=26 49任务的调度及任务调度器任务的调度及任务调度器C/OS-II调度算法和调度方式调度算法和调度方式l优先级调度算法原理为:给每一个任务分配一个惟一优先优先级调度算法原理为:给每一个任务分配一个惟一优先级,各优先级用一个整形数值标识,某优先级的值越大,级,各优先级用一个整形数值标识,某优先级的值越大,其优先级越低;某优先级的值越小,其优先级越高。也就其优先级越低;某优先级的值越小,其优先级越高。也就是说,如果当前操作系统准备进行调度,当有两个任务处是说,如果当前操作系统准备进行调度,当有两个任务处于就绪状态,于就绪状态,系统将优先执行优先级别高的任务。系统将优先执行优先级别高的任务。lC/OS-II操作系统有两种调度方式:任务级任务调度和中断操作系统有两种调度方式:任务级任务调度和中断级任务调度,级任务调度,任务级的调度是由函数任务级的调度是由函数OSSched()OSSched()完成的,中完成的,中断级的调度是由另一个函数断级的调度是由另一个函数OSIntExt()OSIntExt()完成的。完成的。 C/OS-II操作系统在完成中断后允许进行新的调度,因此,操作系统在完成中断后允许进行新的调度,因此,C/OS-II操作系统是可抢占性的,是强实时性操作系统,这是操作系统是可抢占性的,是强实时性操作系统,这是C/OS-II操作系统内核的重要特性。操作系统内核的重要特性。50任务的调度任务的调度l C/OSC/OS是可抢占实时多任务内核,它总是运行是可抢占实时多任务内核,它总是运行就绪任务中优先级最高的那一个。就绪任务中优先级最高的那一个。l C/OSC/OS中不支持时间片轮转法,每个任务的优中不支持时间片轮转法,每个任务的优先级要求不一样且是唯一的,先级要求不一样且是唯一的,所以任务调度的所以任务调度的工作就是工作就是:查找准备就绪的最高优先级的任务:查找准备就绪的最高优先级的任务并进行上下文切换。并进行上下文切换。l C/OSC/OS任务调度所花的时间为常数,与应用程任务调度所花的时间为常数,与应用程序中建立的任务数无关。序中建立的任务数无关。51任务调度器任务调度器调度器调度器OSSched()的任务调度:的任务调度:l确定就绪表中哪个就绪任务的优先级最高,应确定就绪表中哪个就绪任务的优先级最高,应该选择哪个任务去运行,这部分的工作是由调该选择哪个任务去运行,这部分的工作是由调度器(度器(SchedulerScheduler)的调度部分来完成的。)的调度部分来完成的。 注意:任务级的调度是由函数注意:任务级的调度是由函数OSSched()OSSched()完成完成的;中断级的调度是由另一个函数的;中断级的调度是由另一个函数OSIntExtOSIntExt()()完成的。完成的。52void OSSched (void) INT8U y;OS_ENTER_CRITICAL(); if (OSLockNesting | OSIntNesting) = 0)(1) y = OSUnMapTblOSRdyGrp;(2) OSPrioHighRdy = (INT8U)(y 3) + OSUnMapTblOSRdyTbly); if (OSPrioHighRdy != OSPrioCur)(3)OSTCBHighRdy = OSTCBPrioTblOSPrioHighRdy;(4)OSCtxSwCtr+; (5)OS_TASK_SW(); (6) OS_EXIT_CRITICAL();开始开始因处理全局变量而关中断因处理全局变量而关中断找出准备就绪且优先级最高的任务找出准备就绪且优先级最高的任务将准备就绪的最高优先级任务将准备就绪的最高优先级任务指向该任务的控制块指向该任务的控制块改任务是否为改任务是否为当前运行任务当前运行任务是否中断嵌套是否中断嵌套或调度上锁或调度上锁开中断开中断调用任务切换函数调用任务切换函数任务切换统计数器加任务切换统计数器加1 1结束结束53 C/OSC/OS任务调度器实现及源代码分析任务调度器实现及源代码分析voidOSSched(void)INT8Uy;OS_ENTER_CRITICAL();if(OSLockNesting|OSIntNesting)=0)y=OSUnMapTblOSRdyGrp;OSPrioHighRdy=(INT8U)(y3)+OSUnMapTblOSRdyTbly);if(OSPrioHighRdy!=OSPrioCur)OSTCBHighRdy=OSTCBPrioTblOSPrioHighRdy;OSCtxSwCtr+;OS_TASK_SW();OS_EXIT_CRITICAL();检查是否中断调用和允许任务调用(调度器上锁)找到优先级最高的任务该任务是否正在运行54voidOSSched(void)INT8Uy;OS_ENTER_CRITICAL();if(OSLockNesting|OSIntNesting)=0)y=OSUnMapTblOSRdyGrp;OSPrioHighRdy=(INT8U)(y 0) OSLockNesting-; if (OSLockNesting | OSIntNesting) = 0) (1) OS_EXIT_CRITICAL(); OSSched(); (2) else OS_EXIT_CRITICAL(); else OS_EXIT_CRITICAL(); 64任务管理的系统服务任务管理的系统服务v创建任务创建任务v删除任务删除任务v修改任务的优先级修改任务的优先级v挂起和恢复任务挂起和恢复任务v获得一个任务的有关信息获得一个任务的有关信息65创建任务创建任务(创建任务的函数创建任务的函数SOSTaskCreate();SOSTaskCreateExt();(OSTaskCreateExt()OSTaskCreateExt()是是OSTaskCreate()OSTaskCreate()的扩展版本,的扩展版本,提供了一些附加的功能提供了一些附加的功能;(任务可以在多任务调度开始任务可以在多任务调度开始 ( (即调用即调用OSStart() OSStart() 之前创建,也可以在其它任务的执行过程中被创之前创建,也可以在其它任务的执行过程中被创建。但在建。但在OSStart()OSStart()被调用之前,用户必须创建至被调用之前,用户必须创建至少一个任务;少一个任务;(不能在中断服务程序不能在中断服务程序(ISR)(ISR)中创建新任务。中创建新任务。66OSTaskCreate()OSTaskCreate()INT8UOSTaskCreate(void(*task)(void*pd),/任务代码指针任务代码指针void*pdata,/任务参数指针任务参数指针OS_STK*ptos,/任务栈的栈顶指针任务栈的栈顶指针INT8Uprio/任务的优先级任务的优先级);返回值返回值OS_NO_ERR:函数调用成功;:函数调用成功;OS_PRIO_EXIT:任务优先级已经存在;:任务优先级已经存在;OS_PRIO_INVALID:任务优先级无效。:任务优先级无效。67OSTaskCreate()OSTaskCreate()的实现过程的实现过程v任务优先级检查任务优先级检查该优先级是否在该优先级是否在0 0到到OS_LOWSEST_PRIOOS_LOWSEST_PRIO之间?之间?该优先级是否空闲?该优先级是否空闲?v调用调用OSTaskStkInit()OSTaskStkInit(),创建任务的栈帧;,创建任务的栈帧;v调用调用OSTCBInit()OSTCBInit(),从空闲的,从空闲的OS_TCBOS_TCB池(即池(即OSTCBFreeListOSTCBFreeList链表)中获得一个链表)中获得一个TCBTCB并初始化其并初始化其内容,然后把它加入到内容,然后把它加入到OSTCBListOSTCBList链表的开头,并链表的开头,并把它设定为就绪状态;把它设定为就绪状态;v任务个数任务个数OSTaskCtrOSTaskCtr加加1 1;v调用用户自定义的函数调用用户自定义的函数OSTaskCreateHook()OSTaskCreateHook();v判断是否需要调度(调用者是正在执行的任务)判断是否需要调度(调用者是正在执行的任务)68OSTaskCreateExt()OSTaskCreateExt()INT8UOSTaskCreateExt(前四个参数与前四个参数与OSTaskCreate相同,相同,INT16Uid,/任务的任务的IDOS_STK*pbos,/指向任务栈底的指针指向任务栈底的指针INT32Ustk_size,/栈栈能容纳的成员能容纳的成员数目数目void*pext,/指向用户附加数据域的指针指向用户附加数据域的指针INT16Uopt/一些选项信息一些选项信息);返回值:与返回值:与OSTaskCreate()相同。相同。69任务的栈空间任务的栈空间(每个任务都有自己的栈空间(每个任务都有自己的栈空间(StackStack),栈必须声),栈必须声明为明为OS_STKOS_STK类型,并且由连续的内存空间组成;类型,并且由连续的内存空间组成;(栈空间的分配方法栈空间的分配方法?静态分配:在编译的时候分配,例如:静态分配:在编译的时候分配,例如:staticOS_STKMyTaskStackstack_size;OS_STKMyTaskStackstack_size;?动态分配:在任务运行的时候使用动态分配:在任务运行的时候使用malloc()malloc()函函数来动态申请内存空间;数来动态申请内存空间;70OS_STK*pstk;pstk=(OS_STK*)malloc(stack_size);/*确认确认malloc()能得到足够的内存空间能得到足够的内存空间*/if(pstk!=(OS_STK*)0)Createthetask;动态分配动态分配71内存碎片问题内存碎片问题(在动态分配中,可能存在内存碎片问题。特别是在动态分配中,可能存在内存碎片问题。特别是当用户反复地建立和删除任务时,内存堆中可能当用户反复地建立和删除任务时,内存堆中可能会出现大量的碎片,导致没有足够大的一块连续会出现大量的碎片,导致没有足够大的一块连续内存区域可用作任务栈,这时内存区域可用作任务栈,这时malloc()malloc()便无法成便无法成功地为任务分配栈空间。功地为任务分配栈空间。3Kb堆初始状态堆初始状态A(1Kb)B(1Kb)C(1Kb)3个任务个任务1KbB(1Kb)1Kb删除删除A,C内碎片内碎片/外碎片外碎片?72栈的增长方向栈的增长方向(栈的增长方向的设置栈的增长方向的设置?从低地址到高地址:在从低地址到高地址:在OS_CPU.HOS_CPU.H中,将常量中,将常量 OS_STK_GROWTHOS_STK_GROWTH设定为设定为 0 0;?从高地址到低地址:在从高地址到低地址:在OS_CPU.HOS_CPU.H中,将常量中,将常量 OS_STK_GROWTHOS_STK_GROWTH设定为设定为 1 1;OS_STKTaskStackTASK_STACK_SIZE;OSTaskCreate(task,pdata,&TaskStackTASK_STACK_SIZE-1,prio);73删除任务删除任务(OSTaskDel()OSTaskDel():删除一个任务,其:删除一个任务,其TCBTCB会从所有可能会从所有可能的系统数据结构中移除。任务将返回并处于休眠状的系统数据结构中移除。任务将返回并处于休眠状态(任务的代码还在)。态(任务的代码还在)。F如果任务正处于就绪状态,把它从就绪表中移如果任务正处于就绪状态,把它从就绪表中移出,这样以后就不会再被调度执行了;出,这样以后就不会再被调度执行了;F如果任务正处于邮箱、消息队列或信号量的等如果任务正处于邮箱、消息队列或信号量的等待队列中,也把它移出;待队列中,也把它移出;F将任务的将任务的OS_TCBOS_TCB从从OSTCBListOSTCBList链表当中移动到链表当中移动到OSTCBFreeListOSTCBFreeList。74(OSTaskChangePrio()OSTaskChangePrio():在程序运行期间,用户可以:在程序运行期间,用户可以通过调用本函数来改变某个任务的优先级。通过调用本函数来改变某个任务的优先级。INT8UOSTaskChangePrio(INT8Uoldprio,INT8Unewprio)(OSTaskQuery()OSTaskQuery():获得一个任务的有关信息:获得一个任务的有关信息F获得的是对应任务的获得的是对应任务的OS_TCBOS_TCB中内容的拷贝。中内容的拷贝。75(OSTaskSuspend()OSTaskSuspend():挂起一个任务:挂起一个任务F如果任务处于就绪态,把它从就绪表中移出;如果任务处于就绪态,把它从就绪表中移出;F在任务的在任务的TCBTCB中设置中设置OS_STAT_SUSPENDOS_STAT_SUSPEND标志,表标志,表明该任务正在被挂起。明该任务正在被挂起。(OSTaskResume()OSTaskResume():恢复一个任务:恢复一个任务F恢复被恢复被OSTaskSuspend()OSTaskSuspend()挂起的任务;挂起的任务;F清除清除TCBTCB中中OSTCBStatOSTCBStat字段的字段的OS_STAT_SUSPENDOS_STAT_SUSPEND位位挂起和恢复任务挂起和恢复任务76第三章、实时操作系统第三章、实时操作系统C/OS-II1 13 32 24 4 C/OS-II概述概述任务管理任务管理中断和时间中断和时间管理管理任务之间的通信与任务之间的通信与同步同步5 5存储管理存储管理6 6 C/OS-II的移植的移植77中断处理中断处理l中断:中断:由于某种事件的发生而导致程序流由于某种事件的发生而导致程序流程的改变。产生中断的事件称为程的改变。产生中断的事件称为中断源中断源。lCPU响应中断的条件:响应中断的条件:n至少有一个中断源向至少有一个中断源向CPU发出中断信发出中断信号;号;n系统允许中断,且对此中断信号未予系统允许中断,且对此中断信号未予屏蔽。屏蔽。78中断服务程序中断服务程序ISRISRl中断一旦被识别,中断一旦被识别,CPU会保存部分(或全会保存部分(或全部)运行上下文(部)运行上下文(context,即寄存器的,即寄存器的值),然后跳转到专门的子程序去处理此值),然后跳转到专门的子程序去处理此次事件,称为次事件,称为中断服务子程序中断服务子程序(ISR)。lC/OS-中,中,中断服务子程序要用汇编语中断服务子程序要用汇编语言来编写,然而,如果用户使用的言来编写,然而,如果用户使用的C语言语言编译器支持在线汇编语言的话,用户可以编译器支持在线汇编语言的话,用户可以直接将中断服务子程序代码放在直接将中断服务子程序代码放在C语言的语言的程序文件中。程序文件中。79(1)保存全部保存全部CPU寄存器的值寄存器的值;(2)调用调用OSIntEnter(),或直接把全局变量,或直接把全局变量OSIntNesting(中断嵌套层次)加(中断嵌套层次)加1;(3)执行用户代码做中断服务执行用户代码做中断服务;(4)调用调用OSIntExit();(5)恢复所有恢复所有CPU寄存器;寄存器;(6)执行中断返回指令。执行中断返回指令。用户用户ISRISR的框架的框架8081OSIntEnter()OSIntEnter()/*在调用本函数之前必须先将中断关闭在调用本函数之前必须先将中断关闭*/voidOSIntEnter(void)if(OSRunning=TRUE)if(OSIntNesting255)OSIntNesting+;82OSIntExit的意义的意义83OSIntExit()OSIntExit()voidOSIntExit(void)OS_ENTER_CRITICAL();/关中断关中断if(-OSIntNesting|OSLockNesting)=0)/判判断嵌套是否为零断嵌套是否为零/把高优先级任务装入把高优先级任务装入OSIntExitY=OSUnMapTblOSRdyGrp;OSPrioHighRdy=(INT8U)(OSIntExitYOSTCBPrio != OS_IDLE_PRIO) (3) OS_ENTER_CRITICAL(); if (ptcb-OSTCBDly != 0) if (-ptcb-OSTCBDly = 0) If (!(ptcb-OSTCBStat & OS_STAT_SUSPEND) (4) OSRdyGrp |= ptcb-OSTCBBitY; (5) OSRdyTblptcb-OSTCBY |= ptcb-OSTCBBitX; else ptcb-OSTCBDly = 1; ptcb = ptcb-OSTCBNext; OS_EXIT_CRITICAL(); OS_ENTER_CRITICAL(); (6) OSTime+; (7) OS_EXIT_CRITICAL();90时间管理时间管理与时间管理相关的系统服务与时间管理相关的系统服务: :lOSTimeDLY()lOSTimeDLYHMSM()lOSTimeDlyResmue()lOStimeGet()lOSTimeSet()91OSTimeDLY()OSTimeDLY()vOSTimeDLY()OSTimeDLY():任务延时函数,申请该服:任务延时函数,申请该服务的任务可以延时一段时间;务的任务可以延时一段时间;v调用调用OSTimeDLYOSTimeDLY后,任务进入等待状态;后,任务进入等待状态;v使用方法使用方法wvoidOSTimeDly(INT16Uticks);wticks表示需要延时的时间长度,用时钟节表示需要延时的时间长度,用时钟节拍的个数来表示。拍的个数来表示。92OSTimeDLY()OSTimeDLY()voidOSTimeDly(INT16Uticks)if(ticks0)OS_ENTER_CRITICAL();if(OSRdyTblOSTCBCur-OSTCBY&=OSTCBCur-OSTCBBitX)=0)OSRdyGrp&=OSTCBCur-OSTCBBitY;OSTCBCur-OSTCBDly=ticks;OS_EXIT_CRITICAL();OSSched();93OSTimeDLY(1)OSTimeDLY(1)的问题的问题94OSTimeDlyHMSM()OSTimeDlyHMSM()vOSTimeDlyHMSM()OSTimeDlyHMSM():OSTimeDly()OSTimeDly()的另一个的另一个版本,即按时分秒延时函数;版本,即按时分秒延时函数;v使用方法使用方法wINT8UOSTimeDlyHMSM(INT8Uhours,/小时小时INT8Uminutes,/分钟分钟INT8Useconds,/秒秒INT16Umilli/毫秒毫秒);95OSTimeDlyResume()OSTimeDlyResume()vOSTimeDlyResume()OSTimeDlyResume():让处在延时期的任:让处在延时期的任务提前结束延时,进入就绪状态;务提前结束延时,进入就绪状态;v使用方法使用方法wINT8UOSTimeDlyResume(INT8Uprio);wprio表示需要提前结束延时的任务的优先级表示需要提前结束延时的任务的优先级/任务任务ID。96系统时间系统时间v每隔一个时钟节拍,发生一个时钟中断,将一每隔一个时钟节拍,发生一个时钟中断,将一个个3232位的计数器位的计数器OSTimeOSTime加加1 1;v该计数器在用户调用该计数器在用户调用OSStart()OSStart()初始化多任务和初始化多任务和4,294,967,2954,294,967,295个节拍执行完一遍的时候从个节拍执行完一遍的时候从0 0开开始计数。若时钟节拍的频率等于始计数。若时钟节拍的频率等于100Hz100Hz,该计数,该计数器每隔器每隔497497天就重新开始计数;天就重新开始计数;vOSTimeGet()OSTimeGet():获得该计数器的当前值;:获得该计数器的当前值;?INT32UOSTimeGet(void);vOSTimeOSTimeS Set()et():设置该计数器的值。:设置该计数器的值。?voidOSTimeSet(INT32Uticks);97何时启动系统定时器l如果在如果在OSStartOSStart之前启动定时器,则系统可能无法正确执行之前启动定时器,则系统可能无法正确执行完完OSStartHighRdyOSStartHighRdylOSStartOSStart函数直接调用函数直接调用OSStartHighRdyOSStartHighRdy去执行最高优先级的去执行最高优先级的任务,任务,OSStartOSStart不返回。不返回。l系统定时器应该在系统的最高优先级任务中启动系统定时器应该在系统的最高优先级任务中启动l使用使用OSRunningOSRunning变量来控制操作系统的运行变量来控制操作系统的运行l在我们的移植版本中,使用了在我们的移植版本中,使用了uCOS-IIuCOS-II中的保留任务中的保留任务1 1作为作为系统任务。负责启动定时器系统任务。负责启动定时器98时钟节拍的启动时钟节拍的启动l用户必须在多任务系统启动以后再开启时钟节拍用户必须在多任务系统启动以后再开启时钟节拍器,也就是在调用器,也就是在调用OSStart()OSStart()之后;之后;l在调用在调用OSStart()OSStart()之后做的第一件事是初始化定时之后做的第一件事是初始化定时器中断。器中断。voidmain(void).OSInit();/*初始化初始化uC/OS-II*/*应用程序初始化代码应用程序初始化代码.*/*调用调用OSTaskCreate()创建至少一个任务创建至少一个任务*/允许时钟节拍中断允许时钟节拍中断;/*错误!可能错误!可能crash!*/OSStart();/*开始多任务调度开始多任务调度*/99系统的初始化与启动系统的初始化与启动l在调用在调用 C/OS-II的任何其它服务之前,用户必须的任何其它服务之前,用户必须首先调用系统初始化函数首先调用系统初始化函数OSInit()OSInit()来初始化来初始化 C/OS的所有变量和数据结构的所有变量和数据结构;lOSInit()OSInit()建立空闲任务建立空闲任务OSTaskIdle()OSTaskIdle(),该任务总,该任务总是处于就绪状态,其优先级一般被设成最低,即是处于就绪状态,其优先级一般被设成最低,即OS_LOWEST_PRIOOS_LOWEST_PRIO;如果需要,;如果需要,OSInit()OSInit()还建立统还建立统计任务计任务OSTaskStat()OSTaskStat(),并让其进入就绪状态;,并让其进入就绪状态;lOSInit()OSInit()还初始化了还初始化了4 4个空数据结构缓冲区:空闲个空数据结构缓冲区:空闲TCBTCB链表链表OSTCBFreeListOSTCBFreeList、空闲事件链表、空闲事件链表OSEventFreeListOSEventFreeList、空闲队列链表、空闲队列链表OSQFreeListOSQFreeList和和空闲存储链表空闲存储链表OSMemFreeListOSMemFreeList。100系统初始化后的状态系统初始化后的状态101 C/OS-IIC/OS-II的启动的启动l多任务的启动是用户通过调用多任务的启动是用户通过调用OSStart()OSStart()实现的。实现的。然而,启动然而,启动C/OS-C/OS-之前,用户至少要建立一个之前,用户至少要建立一个应用任务。应用任务。voidmain(void)OSInit(); /* /* 初始化初始化uC/OS-II */uC/OS-II */ . . 通过调用通过调用OSTaskCreate()OSTaskCreate()或或OSTaskCreateExt()OSTaskCreateExt()创建至少一个任务创建至少一个任务; ; . OSStart(); /*/*开始多任务调度开始多任务调度! ! 永不返回永不返回* */ / 102OSStart()OSStart()voidOSStart(void)INT8UY;INT8UX;if(OSRunning=FALSE)y=OSUnMapTblOSRdyGrp;x=OSUnMapTblOSRdyTbly;OSPrioHighRdy=(INT8U)(YOSEventGrp |= OSMapTblprio 3; pevent-OSEventTblprio 3 |= OSMapTblprio & 0x07;从等待任务列表中删除一个任务从等待任务列表中删除一个任务if (pevent-OSEventTblprio 3 &= OSMapTblprio & 0x07) = 0) pevent-OSEventGrp &= OSMapTblprio 3;115在等待事件的任务列表中查找优先级最高的任务在等待事件的任务列表中查找优先级最高的任务在等待任务列表中查找最高优先级的任务在等待任务列表中查找最高优先级的任务 y = OSUnMapTblpevent-OSEventGrp; x = OSUnMapTblpevent-OSEventTbly; prio = (y 3) + x;116空闲空闲ECBECB的管理的管理lECBECB的总数由用户所需要的信号量、邮箱和消息队列的总的总数由用户所需要的信号量、邮箱和消息队列的总数决定,由数决定,由OS_CFG.HOS_CFG.H中的中的#define OS_MAX_EVENTS#define OS_MAX_EVENTS定义。定义。 l在调用在调用OSInit()OSInit()初始化系统时,所有的初始化系统时,所有的ECBECB被链接成一个被链接成一个单向链表单向链表空闲事件控制块链表;空闲事件控制块链表;l每当建立一个信号量、邮箱或消息队列时,就从该链表中每当建立一个信号量、邮箱或消息队列时,就从该链表中取出一个空闲事件控制块,并对它进行初始化。取出一个空闲事件控制块,并对它进行初始化。0OS_MAX_EVENTSOSEventFreeListOS_EVENT117ECBECB的基本操作的基本操作vOSEventWaitListInit()OSEventWaitListInit()初始化一个事件控制块。初始化一个事件控制块。当创建一个信号量、邮箱或消当创建一个信号量、邮箱或消息队列时,相应的创建函数会调用本函数对息队列时,相应的创建函数会调用本函数对ECBECB的内容进的内容进行初始化,将行初始化,将OSEventGrpOSEventGrp和和OSEventTblOSEventTbl数组清零;数组清零;OSEventWaitListInit(OS_EVENT*pevent);prevent:指向需要初始化的事件控制块的指针。:指向需要初始化的事件控制块的指针。vOSEventTaskRdy()OSEventTaskRdy()。使一个任务进入就绪态使一个任务进入就绪态。当当一个一个事件事件发生时发生时,需要将其需要将其等待任务列表中的最高优先级任务置等待任务列表中的最高优先级任务置为为就绪态就绪态;OSEventTaskRdy(OS_EVENT*pevent,void*msg,INT8Umsk);msg:指向消息的指针;:指向消息的指针;mskmsk:用于设置:用于设置TCBTCB的状态。的状态。118ECBECB的基本操作(续)的基本操作(续)vOSEventTaskWaitOSEventTaskWait()()使一个任务进入等待状态使一个任务进入等待状态。当某个任务要等待一个事件当某个任务要等待一个事件的发生时的发生时,需要调用本函数,需要调用本函数将将该该任务从就绪任务表中删任务从就绪任务表中删除,并放到相应事件的等待任务表中除,并放到相应事件的等待任务表中;OSEventTaskWait(OS_EVENT*pevent);vOSEventTOOSEventTO()()由于等待超时而将任务置为就绪态由于等待超时而将任务置为就绪态。如果一个任务等待。如果一个任务等待的事件的事件在预先指定的时间内没有发生在预先指定的时间内没有发生,需要调用本函数,需要调用本函数将该将该任务任务从等待从等待列表列表中中删除,并把它置删除,并把它置为为就绪状态就绪状态;OSEventTO(OS_EVENT*pevent);119同步与互斥同步与互斥l为了实现资源共享,一个操作系统必须提供为了实现资源共享,一个操作系统必须提供临界临界区区操作的功能;操作的功能;lC/OSC/OS采用关闭采用关闭/ /打开中断的方式来处理临界区打开中断的方式来处理临界区代码,从而避免竞争条件,实现任务间的互斥;代码,从而避免竞争条件,实现任务间的互斥; lC/OSC/OS定义两个宏定义两个宏(macros)(macros)来开关中断,即:来开关中断,即:OS_ENTER_CRITICALOS_ENTER_CRITICAL()()和和OS_EXIT_CRITICAL()OS_EXIT_CRITICAL();l这两个宏的定义取决于所用的微处理器,每种微这两个宏的定义取决于所用的微处理器,每种微处理器都有自己的处理器都有自己的OS_CPU.HOS_CPU.H文件。文件。 120.OS_ENTER_CRITICAL();任务任务1的临界区代码;的临界区代码;OS_EXIT_CRITICAL();.任务任务1任务任务2.OS_ENTER_CRITICAL();任务任务2的临界区代码;的临界区代码;OS_EXIT_CRITICAL();.临界资源临界资源121l当处理临界段代码时,需要关中断,处理完毕后,再当处理临界段代码时,需要关中断,处理完毕后,再开中断;开中断;l关中断时间是实时内核最重要的指标之一;关中断时间是实时内核最重要的指标之一;l在实际应用中,关中断的时间很大程度中取决于微处在实际应用中,关中断的时间很大程度中取决于微处理器的结构和编译器生成的代码质量;理器的结构和编译器生成的代码质量;l C/OSC/OS-II-II定义两个宏开关中断定义两个宏开关中断:OS_ENTER_CRITICAL():OS_ENTER_CRITICAL()和和OS_EXIT_CRITICAL();OS_EXIT_CRITICAL();C/OS-II中开关中断的方法122lOS_CRITICAL_METHOD=1OS_CRITICAL_METHOD=1l用处理器指令关中断,执行用处理器指令关中断,执行OS_ENTER_CRITICAL()OS_ENTER_CRITICAL(),开中断执,开中断执行行OS_EXIT_CRITICAL()OS_EXIT_CRITICAL();lOS_CRITICAL_METHOD=2OS_CRITICAL_METHOD=2l实现实现OS_ENTER_CRITICAL()OS_ENTER_CRITICAL()时,先在堆栈中保存中断的开时,先在堆栈中保存中断的开/ /关状关状态,然后再关中断;实现态,然后再关中断;实现OS_EXIT_CRITICAL()OS_EXIT_CRITICAL()时,从堆栈中弹时,从堆栈中弹出原来中断的开出原来中断的开/ /关状态;关状态;lOS_CRITICAL_METHOD=3OS_CRITICAL_METHOD=3l把当前处理器的状态字保存在局部变量中(如把当前处理器的状态字保存在局部变量中(如OS_CPU_SROS_CPU_SR,关,关中断时保存,开中断时恢复中断时保存,开中断时恢复C/OS-II中采用了3种开关中断的方法123lIntel 80x86Intel 80x86实模式下中断的打开与关闭;实模式下中断的打开与关闭;l方法方法1 16#define OS_ENTER_CRITICAL() asm CLI#define OS_ENTER_CRITICAL() asm CLI6#define OS_EXIT_CRITICAL() asm STI#define OS_EXIT_CRITICAL() asm STIl方法方法2 26#define OS_ENTER_CRITICAL() asm #define OS_ENTER_CRITICAL() asm PUSHF; CLIPUSHF; CLI6#define OS_EXIT_CRITICAL() asm POPF #define OS_EXIT_CRITICAL() asm POPF 124信号量信号量l信号量在多任务系统中的功能信号量在多任务系统中的功能实现对共享资源的互斥访问(包括单个共享实现对共享资源的互斥访问(包括单个共享资源或多个相同的资源);资源或多个相同的资源);实现任务之间的行为同步;实现任务之间的行为同步;l必须在必须在OS_CFG.HOS_CFG.H中将中将OS_SEM_ENOS_SEM_EN开关常量开关常量置为置为1 1,这样,这样C/OSC/OS才能支持信号量。才能支持信号量。125luC/OSuC/OS中信号量由两部分组成:信号量的中信号量由两部分组成:信号量的计数值(计数值(1616位无符号整数)和等待该信位无符号整数)和等待该信号量的任务所组成的等待任务表;号量的任务所组成的等待任务表;l信号量系统服务信号量系统服务OSSemCreate()OSSemPend(),OSSemPost()OSSemAccept(),OSSemQuery()126任务、任务、ISRISR和信号量的关系和信号量的关系或或任务任务任任务ISROSSemAccept()OSSemPend()OSSemQuery()OSSemPost()OSSemPost()OSSemAccept()OSSemCreate()NN127创建一个信号量创建一个信号量lOSSemCreate()OSSemCreate()C创建一个信号量,并对信号量的初始计数值赋创建一个信号量,并对信号量的初始计数值赋值,该初始值为值,该初始值为0 0到到65,53565,535之间的一个数;之间的一个数;COS_EVENT*OSSemCreate(INT16Ucnt);Ccnt:信号量的初始值。:信号量的初始值。l执行步骤执行步骤C从空闲事件控制块链表中得到一个从空闲事件控制块链表中得到一个ECBECB;C初始化初始化ECBECB,包括设置信号量的初始值、把等待,包括设置信号量的初始值、把等待任务列表清零、设置任务列表清零、设置ECBECB的事件类型等;的事件类型等;C返回一个指向该事件控制块的指针。返回一个指向该事件控制块的指针。128等待一个信号量等待一个信号量lOSSemPend()OSSemPend()C等待一个信号量,即操作系统中的等待一个信号量,即操作系统中的P P操作,将信操作,将信号量的值减号量的值减1 1;COSSemPend(OS_EVENT*pevent,INT16Utimeout,INT8U*err);l执行步骤执行步骤C如果信号量的计数值大于如果信号量的计数值大于0 0,将它减,将它减1 1并返回;并返回;C如果信号量的值等于如果信号量的值等于0 0,则调用本函数的任务将,则调用本函数的任务将被阻塞起来,等待另一个任务把它唤醒;被阻塞起来,等待另一个任务把它唤醒;C调用调用OSSched()OSSched()函数,调度下一个最高优先级的函数,调度下一个最高优先级的任务运行。任务运行。129发送一个信号量发送一个信号量lOSSemPost()OSSemPost()C发送一个信号量,即操作系统中的发送一个信号量,即操作系统中的V V操作,将信操作,将信号量的值加号量的值加1 1;COSSemPost(OS_EVENT*pevent);l执行步骤执行步骤C检查是否有任务在等待该信号量,如果没有,检查是否有任务在等待该信号量,如果没有,将信号量的计数值加将信号量的计数值加1 1并返回;并返回;C如果有,将优先级最高的任务从等待任务列表如果有,将优先级最高的任务从等待任务列表中删除,并使它进入就绪状态;中删除,并使它进入就绪状态;C调用调用OSSched()OSSched(),判断是否需要进行任务切换。,判断是否需要进行任务切换。130无等待地请求一个信号量无等待地请求一个信号量lOSSemAccept()OSSemAccept()C当一个任务请求一个信号量时,如果该信号量当一个任务请求一个信号量时,如果该信号量暂时无效,则让该任务简单地返回,而不是进暂时无效,则让该任务简单地返回,而不是进入等待状态;入等待状态;CINT16UOSSemAccept(OS_EVENT*pevent);l执行步骤执行步骤C如果该信号量的计数值大于如果该信号量的计数值大于0 0,则将它减,则将它减1 1,然,然后将信号量的原有值返回;后将信号量的原有值返回;C如果该信号量的值等于如果该信号量的值等于0 0,直接返回该值,直接返回该值(0)(0)。131查询一个信号量的当前状态查询一个信号量的当前状态lOSSemQuery()OSSemQuery()C查询一个信号量的当前状态;查询一个信号量的当前状态;CINT8UOSSemQuery(OS_EVENT*pevent,OS_SEM_DATA*pdata);C将指向信号量对应事件控制块的指针将指向信号量对应事件控制块的指针pevent所指向的所指向的ECB的内容拷贝到指向的内容拷贝到指向用于记录信号量信息的数据结构用于记录信号量信息的数据结构OS_SEM_DATA数据结构的指针数据结构的指针pdata所所指向的缓冲区当中。指向的缓冲区当中。132任务间通信任务间通信v低级通信低级通信w只能传递状态和整数值等控制信息,传送的只能传递状态和整数值等控制信息,传送的信息量小;信息量小;w例如:信号量例如:信号量v高级通信高级通信w能够传送任意数量的数据;能够传送任意数量的数据;w例如:共享内存、邮箱、消息队列例如:共享内存、邮箱、消息队列133共享内存共享内存v在在 C/OS-II中如何实现共享内存?中如何实现共享内存?w内存地址空间只有一个,为所有的任内存地址空间只有一个,为所有的任务所共享!务所共享!w为了避免竞争状态,需要使用信号量为了避免竞争状态,需要使用信号量来实现互斥访问。来实现互斥访问。134消息邮箱消息邮箱l邮箱邮箱(MailBoxMailBox):一个任务或):一个任务或ISRISR可以可以通过邮箱向另一个任务发送一个指针型通过邮箱向另一个任务发送一个指针型的变量,该指针指向一个包含了特定的变量,该指针指向一个包含了特定“消息消息”(messagemessage)的数据结构;)的数据结构;l必须在必须在OS_CFG.HOS_CFG.H中将中将OS_OS_MBOXMBOX_EN_EN开关常开关常量置为量置为1 1,这样,这样C/OSC/OS才能支持邮箱。才能支持邮箱。135l一个邮箱可能处于两种状态:一个邮箱可能处于两种状态:满的状态:邮箱包含一个非空指针型变量;满的状态:邮箱包含一个非空指针型变量;空的状态:邮箱的内容为空指针空的状态:邮箱的内容为空指针NULLNULL;l邮箱的系统服务邮箱的系统服务OSMboxCreate()OSMboxPost()OSMboxPend()OSMboxAccept()OSMboxQuery()136任务、任务、ISRISR和消息邮箱的关系和消息邮箱的关系137邮箱的系统服务(邮箱的系统服务(1 1)lOSMboxCreate()OSMboxCreate():创建一个邮箱:创建一个邮箱在创建邮箱时,须分配一个在创建邮箱时,须分配一个ECBECB,并使用其中的,并使用其中的字段字段OSEventPtrOSEventPtr指针来存放消息的地址;指针来存放消息的地址;OS_EVENT*OSMboxCreate(void*msg);msg:指针的初始值,一般情形下为:指针的初始值,一般情形下为NULLNULL。lOSMboxPendOSMboxPend()():等待一个邮箱中的消息:等待一个邮箱中的消息若邮箱为满,将其内容(某消息的地址)返回;若邮箱为满,将其内容(某消息的地址)返回;若邮箱为空,当前任务将被阻塞,直到邮箱中若邮箱为空,当前任务将被阻塞,直到邮箱中有了消息或等待超时;有了消息或等待超时;OSMboxPend(OS_EVENT*pevent,INT16Utimeout,INT8U*err);138邮箱的系统服务(邮箱的系统服务(2 2)lOSMboxPostOSMboxPost()():发送一个消息到邮箱中:发送一个消息到邮箱中如果有任务在等待该消息,将其中的最高优先如果有任务在等待该消息,将其中的最高优先级任务从等待列表中删除,变为就绪状态;级任务从等待列表中删除,变为就绪状态;OSMboxPost(OS_EVENT*pevent,void*msg);lOSMboxAccept()OSMboxAccept():无等待地请求邮箱消息:无等待地请求邮箱消息若邮箱为满,返回它的当前内容;若邮箱为空,若邮箱为满,返回它的当前内容;若邮箱为空,返回空指针;返回空指针;OSMboxAccept(OS_EVENT*pevent);lOSMboxQuery()OSMboxQuery():查询一个邮箱的状态:查询一个邮箱的状态OSMboxQuery(OS_EVENT*pevent,OS_MBOX_DATA*pdata);139样例程序(样例程序(1 1)OSMboxCreate()函数函数OS_EVENT*CommMbox;voidmain(void).OSInit();.CommMbox=OSMboxCreate(void*)0);.OSStart();OSMboxPend()函数函数voidCommTask(void*pdata)INT8Uerr;void*msg;pdata=pdata;for(;).msg=OSMboxPend(CommMbox,10,&err);if(err=OS_NO_ERR)/*收到消息时的代码收到消息时的代码*/else/*未收到消息时的代码未收到消息时的代码*/140样例程序(样例程序(2 2)OSMboxPost()函数函数OS_EVENT*CommMbox;INT8UCommRxBuf100;voidCommTaskRx(void*pdata)INT8Uerr;.for(;).err=OSMboxPost(CommMbox,(void*)&CommRxbuf0);.141消息队列消息队列l消息队列消息队列(Message QueueMessage Queue):消息队列):消息队列可以使一个任务或可以使一个任务或ISRISR向另一个任务发送向另一个任务发送多个以指针方式定义的变量;多个以指针方式定义的变量;l为了使为了使C/OSC/OS能够支持消息队列,必须能够支持消息队列,必须在在OS_CFG.HOS_CFG.H中将中将OS_Q_ENOS_Q_EN开关常量置为开关常量置为1 1,并且通过常量,并且通过常量OS_MAX_QSOS_MAX_QS来决定系统支来决定系统支持的最多消息队列数。持的最多消息队列数。142l一个消息队列可以容纳多个不同的消息,因一个消息队列可以容纳多个不同的消息,因此可把它看作是由多个邮箱组成的数组,只此可把它看作是由多个邮箱组成的数组,只是它们共用一个等待任务列表:是它们共用一个等待任务列表:l消息队列的系统服务消息队列的系统服务OSQCreate()OSQPend()、OSQAccept()OSQPost()、OSQPostFront()OSQFlush()OSQQuery()143消息队列的体系结构消息队列的体系结构144回忆一下回忆一下ECBECB数据结构数据结构ECB数据结构数据结构typedefstructvoid*OSEventPtr; /*指向消息或消息队列的指针指向消息或消息队列的指针*/INT8UOSEventTblOS_EVENT_TBL_SIZE;/等待任务列表等待任务列表INT16UOSEventCnt; /*计数器(当事件是信号量时)计数器(当事件是信号量时)*/INT8UOSEventType; /*事件类型:信号量、邮箱等事件类型:信号量、邮箱等*/INT8UOSEventGrp; /*等待任务组等待任务组*/OS_EVENT;在实现消息队列时,哪些字段可以用?在实现消息队列时,哪些字段可以用?145队列控制块队列控制块队列控制块队列控制块数据结构数据结构typedefstructos_qstructos_q*OSQPtr;/空闲队列控制块空闲队列控制块指针指针void*OSQStart;/指向消息队列的起始地址指向消息队列的起始地址void*OSQEnd;/指向消息队列指向消息队列的的结束结束地址地址void*OSQIn;/指向消息队列中下一个插入消息的位置指向消息队列中下一个插入消息的位置void*OSQOut;/指向消息队列中下一个取出消息的位置指向消息队列中下一个取出消息的位置INT16UOSQSize;/消息队列中总的单元数消息队列中总的单元数INT16UOSQEntries;/消息队列中当前的消息数量消息队列中当前的消息数量OS_EVENT;146消息队列的数据结构消息队列的数据结构*OSEventPtr012345675657585960616263*OSQPtr*OSStart*OSQEnd*OSQIn*OSQOutOSQSizeOSQEntriesOSQEntriesOSQSizeOSEventCntOSEventTypeOSEventGrpOSEventTblOS_EVENTOS_Q应用程序自己分配的指用程序自己分配的指针数数组未使用未使用void*MsgTbl147空闲队列控制块的管理空闲队列控制块的管理l每一个消息队列都要用到一个队列控制块。在每一个消息队列都要用到一个队列控制块。在 C/OSC/OS中,中,队列控制块的总数由队列控制块的总数由OS_CFG.HOS_CFG.H中的常量中的常量OS_MAX_QSOS_MAX_QS定义。定义。 l在系统初始化时,所有的队列控制块被链接成一个单向链在系统初始化时,所有的队列控制块被链接成一个单向链表表空闲队列控制块链表空闲队列控制块链表OSQFreeListOSQFreeList;OSQPtrOSQStartOSQEndOSQEntriesOSQInOSQSizeOSQOutOSQPtrOSQStartOSQEndOSQEntriesOSQInOSQSizeOSQOutOSQPtrOSQStartOSQEndOSQEntriesOSQInOSQSizeOSQOutOSQFreeListOS_MAX_QSOS_Q0148消息缓冲区消息缓冲区lFIFOlLIFO149创建一个消息队列创建一个消息队列lOSQCreate()OSQCreate()OS_EVENT*OSQCreate(void*start,INT16Usize);start:指针数组,用来存放各个消息的地址:指针数组,用来存放各个消息的地址size:数组的大小(即消息队列的元素个数):数组的大小(即消息队列的元素个数)l执行步骤执行步骤从空闲事件控制块链表中取得一个从空闲事件控制块链表中取得一个ECB;从空闲队列控制块列表中取出一个队列控制块,从空闲队列控制块列表中取出一个队列控制块,并对其进行初始化;并对其进行初始化;初始化初始化ECBECB的内容(事件类型、等待任务列表),的内容(事件类型、等待任务列表),并将并将OSEventPtrOSEventPtr指针指向队列控制块。指针指向队列控制块。150队列控制块与事件控制块队列控制块与事件控制块151请求消息队列中的消息请求消息队列中的消息lOSQPend()OSQPend():等待一个消息队列中的消息:等待一个消息队列中的消息void*OSQPend(OS_EVENT*pevent,INT16Utimeout,INT8U*err);如果消息队列中有至少一条消息,返回消息的如果消息队列中有至少一条消息,返回消息的地址;地址;如果没有消息,相应任务进入等待状态。如果没有消息,相应任务进入等待状态。lOSQAcceptOSQAccept()():无等待地请求消息队列中的消息无等待地请求消息队列中的消息void*OSQAccept(OS_EVENT*pevent);如果消息队列中有消息,返回消息的地址;如果消息队列中有消息,返回消息的地址;如果消息队列中没有消息,返回如果消息队列中没有消息,返回NULLNULL。152向消息队列发送一个消息向消息队列发送一个消息lOSQPost()OSQPost():以:以FIFOFIFO方式向消息队列发送一个消息方式向消息队列发送一个消息INT8UOSQPost(OS_EVENT*pevent,void*msg);如果有任务在等待该消息队列,唤醒其中优先如果有任务在等待该消息队列,唤醒其中优先级最高的任务,并重新调度;级最高的任务,并重新调度;如果没有任务在等待该消息队列,而且此时消如果没有任务在等待该消息队列,而且此时消息队列未满,则以息队列未满,则以FIFO方式插入这个消息。方式插入这个消息。lOSQPostFrontOSQPostFront()():以:以LIFOLIFO方式向消息队列发送一方式向消息队列发送一个消息个消息INT8UOSQPostFront(OS_EVENT*pevent,void*msg);153清空操作与查询操作清空操作与查询操作lOSQFlush()OSQFlush():清空一个消息队列:清空一个消息队列INT8UOSQFlush(OS_EVENT*pevent);删除一个消息队列中的所有消息;删除一个消息队列中的所有消息;lOSQQueryOSQQuery()():查询一个消息队列的状态:查询一个消息队列的状态INT8UOSQQuery(OS_EVENT*pevent,OS_Q_DATA*pdata);154样例程序(样例程序(1 1)OSQCreate()函数函数OS_EVENT*CommQ;void*CommMsg10;voidmain(void).OSInit();.CommQ=OSQCreate(&CommMsg0,10);.OSStart();OSQPend()函数函数voidCommTask(void*pdata)INT8Uerr;void*msg;for(;).msg=OSQPend(CommQ,100,&err);if(err=OS_NO_ERR)/*在在100个个ticks内收到消息内收到消息*/else/*超时,未收到消息超时,未收到消息*/155样例程序(样例程序(2 2)OSQPost()函数函数OS_EVENT*CommQ;INT8UCommRxBuf100;voidCommTaskRx(void*pdata)INT8Uerr;.for(;).err=OSQPost(CommQ,(void*)&CommRxBuf0);.156第三章、实时操作系统第三章、实时操作系统C/OS-II1 13 32 24 4 C/OS-II概述概述任务管理任务管理中断和时间中断和时间管理管理任务之间的通信与任务之间的通信与同步同步5 5存储管理存储管理157概述概述l C/OSC/OS中是中是实模式存储管理实模式存储管理不划分不划分内核内核空间和用户空间空间和用户空间,整个系统只有一,整个系统只有一个地址空间,即物理内存空间,应用程序和内个地址空间,即物理内存空间,应用程序和内核程序都能直接对所有的内存单元进行访问;核程序都能直接对所有的内存单元进行访问;系统中的系统中的“任务任务”,实际上都是线程,实际上都是线程只有运只有运行上下文和栈是独享的,其他资源都是共享的。行上下文和栈是独享的,其他资源都是共享的。l内存布局内存布局代码段代码段(text)、数据段、数据段(data)、bss段、堆段、堆空间、栈空间;空间、栈空间;内存管理,管的是谁?内存管理,管的是谁?堆!堆!158malloc/free?l在在ANSI CANSI C中可以用中可以用malloc()malloc()和和free()free()两个函数动态地分配两个函数动态地分配内存和释放内存。在嵌入式实时操作系统中,容易产生碎内存和释放内存。在嵌入式实时操作系统中,容易产生碎片。片。 l由于内存管理算法的原因,由于内存管理算法的原因,malloc()malloc()和和free()free()函数执行时函数执行时间是不确定的。间是不确定的。C/OS-II C/OS-II 对对malloc()malloc()和和free()free()函数进行函数进行了改进,使得它们可以分配和释放固定大小的内存块。这了改进,使得它们可以分配和释放固定大小的内存块。这样一来,样一来,malloc()malloc()和和free()free()函数的执行时间也是固定的了函数的执行时间也是固定的了3Kb堆初始状态堆初始状态A(1Kb)B(1Kb)C(1Kb)3个申请个申请1KbB(1Kb)1Kb释放释放A,C159 C/OSC/OS中的存储管理中的存储管理l C/OSC/OS采用的是固定分区采用的是固定分区的存储管理方法的存储管理方法C/OS把连续的大块内存按分区来管理把连续的大块内存按分区来管理,每个每个分区包含有整数个大小相同的块分区包含有整数个大小相同的块;在一个系统中可以有多个内存分区在一个系统中可以有多个内存分区,这样,用这样,用户的应用程序就可以从不同的内存分区中得到户的应用程序就可以从不同的内存分区中得到不同大小的内存块。但是,特定的内存块在释不同大小的内存块。但是,特定的内存块在释放时必须重新放回它以前所属于的内存分区放时必须重新放回它以前所属于的内存分区;采用这样的内存管理算法,上面的内存碎片问采用这样的内存管理算法,上面的内存碎片问题就得到了解决。题就得到了解决。160内存分区示意图内存分区示意图分区分区1分区分区2分区分区3分区分区4内存块内存块161内存控制块内存控制块l为了便于管理,在为了便于管理,在C/OSC/OS中使用内存控制块中使用内存控制块MCBMCB(Memory Control BlockMemory Control Block)来跟踪每一个内存)来跟踪每一个内存分区,系统中的每个内存分区都有它自己的分区,系统中的每个内存分区都有它自己的MCBMCB。typedefstructvoid*OSMemAddr; /*分区起始地址分区起始地址*/void*OSMemFreeList;/下一个空闲内存块下一个空闲内存块INT32UOSMemBlkSize;/*内存块的大小内存块的大小*/INT32UOSMemNBlks;/*内存块数量内存块数量*/INT32UOSMemNFree;/*空闲内存块数量空闲内存块数量*/OS_MEM;162内存管理初始化内存管理初始化l如果要在如果要在C/OS-IIC/OS-II中使用内存管理,需要在中使用内存管理,需要在OS_CFG.HOS_CFG.H文件中将开关量文件中将开关量OS_MEM_ENOS_MEM_EN设置为设置为1 1。这。这样样C/OS-II C/OS-II 在系统初始化在系统初始化OSInit()OSInit()时就会调用时就会调用OSMemInitOSMemInit()(),对内存管理器进行初始化,建立空闲的内存,对内存管理器进行初始化,建立空闲的内存控制块链表。控制块链表。OSMemAddrOSMemFreeListOSMemBlkSizeOSMemNBlksOSMemNFreeOSMemAddrOSMemFreeListOSMemBlkSizeOSMemNBlksOSMemNFreeOSMemAddrOSMemFreeListOSMemBlkSizeOSMemNBlksOSMemNFreeOSMemFreeList0OS_MAX_MEM_PART163创建一个内存分区创建一个内存分区lOSMemCreateOSMemCreate()()OS_MEM*OSMemCreate(void*addr,/内存分区的起始地址内存分区的起始地址INT32Unblks,/分区内的内存块数分区内的内存块数INT32Ublksize,/每个内存块的字节数每个内存块的字节数INT8U*err);/指向错误码的指针指向错误码的指针l例子例子OS_MEM*CommTxBuf;INT8UCommTxPart10032;CommTxBuf=OSMemCreate(CommTxPart,100,32,&err);164lOSMemCreateOSMemCreate()()从系统的空闲内存控制块中取得一个从系统的空闲内存控制块中取得一个MCB;将这个内存分区中的所有内存块链接成一个单向链表;将这个内存分区中的所有内存块链接成一个单向链表;在对应的在对应的MCB中填写相应的信息。中填写相应的信息。MCB165分配一个内存块分配一个内存块lvoid*OSMemGet(OS_MEM*pmem,INT8U*err);l功能:从已经建立的内存分区中申请一个内功能:从已经建立的内存分区中申请一个内存块。该函数的唯一参数是指向特定内存分存块。该函数的唯一参数是指向特定内存分区的指针。如果没有空闲的内存块可用,返区的指针。如果没有空闲的内存块可用,返回回NULLNULL指针。指针。l应用程序必须知道内存块的大小,并且在使应用程序必须知道内存块的大小,并且在使用时不能超过该容量。用时不能超过该容量。166释放一个内存块释放一个内存块lINT8UOSMemPut(OS_MEM*pmem,void*pblk);l功能:将一个内存块释放并放回到相应的内功能:将一个内存块释放并放回到相应的内存分区中。存分区中。l注意:用户应用程序必须确认将内存块放回注意:用户应用程序必须确认将内存块放回到了正确的内存分区中,因为到了正确的内存分区中,因为OSMemPut()OSMemPut()并并不知道一个内存块是属于哪个内存分区的不知道一个内存块是属于哪个内存分区的。167等待一个内存块等待一个内存块l如果没有空闲的内存块,如果没有空闲的内存块,OSMemGet()立即立即返回返回NULL。能否在没有空闲内存块的时候。能否在没有空闲内存块的时候让任务进入等待状态?让任务进入等待状态?lC/OS-IIC/OS-II本身在内存管理上并不支持这项本身在内存管理上并不支持这项功能,如果需要的话,可以通过为特定内存功能,如果需要的话,可以通过为特定内存分区增加信号量的方法,来实现此功能。分区增加信号量的方法,来实现此功能。l基本思路:当基本思路:当应用程序应用程序需要需要申请内存块申请内存块时时,首先要得到一个相应的信号量,然后才能调首先要得到一个相应的信号量,然后才能调用用OSMemGet()OSMemGet()函数函数。168OS_EVENT*SemaphorePtr;OS_MEM*PartitionPtr;INT8UPartition10032;OS_STKTaskStk1000;voidmain(void)INT8Uerr;OSInit();.SemaphorePtr=OSSemCreate(100);PartitionPtr=OSMemCreate(Partition,100,32,&err);OSTaskCreate(Task,(void*)0,&TaskStk999,&err);OSStart();169voidTask(void*pdata)INT8Uerr;INT8U*pblock;for(;)OSSemPend(SemaphorePtr,0,&err);pblock=OSMemGet(PartitionPtr,&err);/*使用内存块使用内存块*/.OSMemPut(PartitionPtr,pblock);OSSemPost(SemaphorePtr);170谢谢谢谢各各位位
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号