《嵌入式实时操作系统分析.ppt》由会员分享,可在线阅读,更多相关《嵌入式实时操作系统分析.ppt(162页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、嵌入式系统设计与实例开发 基于32位微处理器与实时操作系统 第五讲实时操作系统C/OS-分析 华北电力大学 控制与计算机工程学院,实时操作系统C/OS-II,1,3,2,4,C/OS-II概述,任务管理,中断和时间管理,任务之间的通信与同步,5,存储管理,通用操作系统和嵌入式(实时)操作系统,通用操作系统:Windows/NT/XP、Linux、UNIX等,用于PC机、服务器, 嵌入式(实时)操作系统:用于嵌入式设备的操作系统,具有通用操作系统的基本特点,又具有系统实时性、硬件的相关依赖性、软件固态化以及应用的专用性等特点; 嵌入式(实时)操作系统通常包括与硬件相关的底层驱动软件、系统内核、设
2、备驱动接口、通信协议、图形界面、标准化浏览器Browser等; 嵌入式(实时)操作系统的重要指标:实时性(中断响应时间、任务切换时间等)、尺寸(可裁剪性 )、可扩展性(内核、中间件);,嵌入式操作系统的发展,常见的嵌入式操作系统,实时嵌入式操作系统的种类繁多,大体上可分为两种,商用型和免费型。 商用型的实操作系统功能稳定、可靠,有完善的技术支持和售后服务,但往往价格昂贵,如Vxworks、QNX、WinCE、Palm OS等。 免费型的实时操作系统在价格方面具有优势,目前主要有Linux,C/OS是一种源码开放的商业RTOS;,C/OS是商业操作系统,学习嵌入式操作系统,学习一种实时操作系统R
3、TOS,如uc/OS,掌握实时系统的概念和设计方法; 嵌入式系统以应用为中心,应用时选择“适用”的操作系统; 嵌入式Linux; 自己“写”RTOS一种学习态度;,RTOS在嵌入式系统中的位置,嵌入式硬件平台,BSP,KERNEL,FS,TCP/IP,设备驱动,设备I/O,调试工具,其它组件,应用,RTOS,C/C+,C/OS简介,1、C/OSMicro Controller O S,微控制器操作系统 2、 C/OS简介 美国人Jean Labrosse 1992年完成 应用面覆盖了诸多领域,如照相机、医疗器械、音响设备、发动机控制、高速公路电话系统、自动提款机等 1998年C/OS-II,目
4、前的版本C/OS -II V2.61,2.72 2000年,得到美国航空管理局(FAA)的认证,可以用于飞行器中 网站www.ucos-II.com(),公开源代码 可移植性(Portable) 绝大部分 C/OS-II的源码是用移植性很强的ANSI C写的。和微处理器硬件相关的那部分是用汇编语言写的。汇编语言写的部分已经压到最低限度,使得 C/OS-II便于移植到其他微处理器上。 C/OS-II可以在绝大多数8位、16位、32位以至64位微处理器、微控制器 、数字信号处理器(DSP)上运行。 可固化(ROMable) C/OS-II是为嵌入式应用而设计的,这就意味着,只要读者有固化手段(C编
5、译、连接、下载和固化), 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个给系统。应用程序最多可以有256个任务 可确定性 全部 C/OS-II的函数调用与服务的执行时间
6、具有可确定性。 任务栈 每个任务有自己单独的栈, C/OS-II允许每个任务有不同的栈空间,以便压低应用程序对RAM的需求。 系统服务 C/OS-II提供很多系统服务,例如邮箱、消息队列、信号量、块大小固定的内存的申请与释放、时间相关函数等。 中断管理 中断可以使正在执行的任务暂时挂起,如果优先级更高的任务被该中断唤醒,则高优先级的任务在中断嵌套全部退出后立即执行,中断嵌套层数可达255层。 稳定性与可靠性,C/OS的性能特点(二),C/OS-II图书,描述了C/OS-II内部的工作原理 随书的CD中包含了源代码 工业界最清晰的源代码 除英文版外,有中文和韩文版,Chinese,Korean,
7、English,ISBN 1-57820-103-9 美国CMP BOOK,ISBN 7-81077-290-2 北京航空航天大学出版社,ISBN 89-951540-5-5,C/OS-II的各种商业应用,全世界有数百种产品在应用: Avionics Medical Cell phones Routers and switches High-end audio equipment Washing machines and dryers UPS (Uninterruptible Power Supplies) Industrial controllers GPS Navigation Syste
8、ms Microwave Radios Instrumentation Point-of-sale terminals 更多,C/OS-II提供的系统服务,信号量 带互斥机制的信号量 减少优先级倒置的问题 事件标志 消息信箱 消息队列 内存管理 时钟管理 任务管理,C/GUI and C/FS,C/GUI 嵌入式的用户界面 用ANSI C书写 支持任何8, 16, 32-bits CPU 彩色,灰、度,等级或黑白显示 代码尺寸小 C/FS 嵌入式的文件系统Written in ANSI C 用ANSI C书写 支持任何8, 16, 32-bits CPU 支持SMC, MMC, SD, CF,
9、 IDE, Flash, RAM其他介质,可移植的数据类型,typedef unsigned char BOOLEAN; typedef unsigned char INT8U; typedef signed char INT8S; typedef unsigned int INT16U; typedef signed int INT16S; typedef unsigned long INT32U; typedef signed long INT32S; typedef float FP32; typedef double FP64;,C/OS-II的文件结构,1,3,2,4,C/OS-II
10、概述,任务管理,中断和时间管理,任务之间的通信与同步,5,存储管理,任务的实现,创建任务的系统服务 OSTaskCreate() INT8U OSTaskCreate (void (*task)(void *pd), /任务代码指针 void *pdata, /任务参数指针OS_STK *ptos, /任务栈的栈顶指针 INT8U prio /任务的优先级); OSTaskCreateExt(),提问:C/OS-II中的任务是进程还是线程?,任务主函数,一个任务通常是一个无限循环(返回值类型void) void MyTask(void *pdata) while (1) do somethin
11、g; waiting; do something; ,Why?,任务也可以自我删除(并非真的删除,只是内核不再知道该任务) void MyTask (void *pdata) . /* 用户代码 */ OSTaskDel(OS_PRIO_SELF); ,C/OS-可以管理多达64个任务; 每个任务被赋以不同的优先级,取值从0到OS_LOWEST_PRIO-2,数值越小,优先级越高; 系统保留了优先级为0、1、2、3、OS_LOWEST_PRIO-3、OS_LOWEST_PRI0-2,OS_LOWEST_PRI0-1以及OS_LOWEST_PRI0这8个任务以被将来使用,用户可以有56个应用任务
12、; 任务的优先级同样也是它的标识号ID。,OS_CFG.H中定义63,空闲任务和统计任务,内核总是创建一个空闲任务OSTaskIdle(); 总是设置为最低优先级,OS_LOWEST_PRIOR; 当所有其他任务都未在执行时,空闲任务开始执行; 应用程序不能删除该任务; 空闲任务的工作就是把32位计数器OSIdleCtr加1,该计数器被统计任务所使用; 统计任务OSTaskStat(),提供运行时间统计。每秒钟运行一次,计算当前的CPU利用率。其优先级是OS_LOWEST_PRIOR-1,可选。,任务控制块TCB,任务控制块 OS_TCB是描述一个任务的核心数据结构,存放了它的各种管理信息,包
13、括任务堆栈指针,任务的状态、优先级,任务链表指针等; 一旦任务建立了,任务控制块OS_TCB将被赋值。,任务控制块TCB,typedef struct os_tcb 栈指针; INT16U OSTCBId; /*任务的ID*/ 链表指针; OS_EVENT *OSTCBEventPtr; /*事件指针*/ void *OSTCBMsg; /*消息指针*/ INT8U OSTCBStat; /*任务的状态*/ INT8U OSTCBPrio; /*任务的优先级*/ 其他 OS_TCB;,栈指针,OSTCBStkPtr:指向当前任务栈顶的指针,每个任务可以有自己的栈,栈的容量可以是任意的; OST
14、CBStkBottom:指向任务栈底的指针; OSTCBStkSize:栈的容量,用可容纳的指针数目而不是字节数(Byte)来表示。,链表指针,所有的任务控制块分属于两条不同的链表,单向的空闲链表(头指针为OSTCBFreeList)和双向的使用链表(头指针为OSTCBList); OSTCBNext、OSTCBPrev:用于将任务控制块插入到空闲链表或使用链表中。每个任务的任务控制块在任务创建的时候被链接到使用链表中,在任务删除的时候从链表中被删除。双向连接的链表使得任一成员都能快速插入或删除。,空闲TCB链表,所有的任务控制块都被放置在任务控制块列表数组OSTCBTbl中,系统初始化时,所
15、有TCB被链接成空闲的单向链表,头指针为OSTCBFreeList。当创建一个任务后,就把OSTCBFreeList所指向的TCB赋给了该任务,并将它加入到使用链表中,然后把OSTCBFreeList指向空闲链表中的下一个结点。,系统初始化后,指针数组,指向相应TCB,任务的状态休眠,休眠状态(Dormant):任务存在于内存空间中,但内核不可见; 可以通过以下函数通知内核,使之变为就绪状态: OSTaskCreate()或OSTaskCreateExt() 可以通过以下函数返回到休眠状态: OSTaskDel(),任务的状态就绪,就绪状态(Ready):万事具备,只欠CPU; 在所有的就绪任
16、务当中,具有最高优先级的任务被选中去运行; 如果任务在运行的时候被抢占了CPU,则又回到就绪状态。,任务的状态运行,运行状态(Running):任务在CPU上运行; 当一个任务在运行时,如果没有关闭中断,则有可能被中断所打断; 当一个任务在运行时,可能因为各种原因进入阻塞状态。 OSMBoxPend(),OSQPend(),OSSemPend() OSTaskSuspend(), OSTimeDly(),任务的状态ISR,中断服务状态(ISR):该任务原来在CPU上运行,后来被中断所打断,由中断服务程序ISR接管了CPU; 当中断服务程序运行完毕后,内核要判断是否有新的、更高优先级的任务就绪,
17、如果有,则原有的任务被抢占;如果没有,则原有的任务重新运行。,任务的状态阻塞,阻塞/等待状态(Waiting):任务由于正在等待某个事件(信号量、邮箱或队列)而被挂起; 当任务等待的事件发生时,回到就绪状态。 OSMBoxpost(), OSQPost(), OSSemPost(), OSTaskResume(), OSTimeDlyResume()或OSTimeTick(),状态的转换,删除任务,任务就绪表,每个任务的就绪态标志放入在就绪表中,就绪表中有两个变量OSRdyGrp和OSRdyTbl。 在OSRdyGrp中,任务按优先级分组,8个任务为一组。OSRdyGrp中的每一位表示8组任务
18、中每一组中是否有进入就绪态的任务。任务进入就绪态时,就绪表OSRdyTbl中的相应元素的相应位也置位。,任务就绪表,优先级最低任务,(空闲任务),优先级最高任务,任务优先级号,对于整数OSRdyTbli(0i7),若它的某一位为1,则OSRdyGrp的第i位为1。 任务的优先级由X和Y确定,根据优先级确定就绪表(1),假设优先级为12的任务进入就绪状态,12=1100b,则OSRdyTbl1的第4位置1,且OSRdyGrp的第1位置1,相应的数学表达式为: OSRdyGrp |=0 x02; OSRdyTbl1 |=0 x10; 而优先级为21的任务就绪21=10 101b,则OSRdyTbl
19、2的第5位置1,且OSRdyGrp的第2位置1,相应的数学表达式为: OSRdyGrp |=0 x04; OSRdyTbl2 |=0 x20;,根据优先级确定就绪表(2),从上面的计算可知:若OSRdyGrp及OSRdyBbl的第n位置1,则应该把OSRdyGrp及OSRdyBbl的值与2n 相或。uC/OS中,把2n的n=0-7的8个值先计算好存在数组OSMapTbl7中,也就是: OSMapTbl0 = 20 = 0 x01(0000 0001) OSMapTbl1 = 21 = 0 x02(0000 0010) OSMapTbl7 = 27 = 0 x80(1000 0000),使任务进
20、入就绪态,如果prio是任务的优先级,即任务的标识号,则将任务放入就绪表,即使任务进入就绪态的方法是: OSRdyGrp |= OSMapTblprio3; OSRdyTblprio3 |= OSMapTblprio,使任务脱离就绪态,将任务就绪表OSRdyTblprio3相应元素的相应位清零,而且当OSRdyTblprio3中的所有位都为零时,即该任务所在组的所有任务中没有一个进入就绪态时,OSRdyGrp的相应位才为零。 if(OSRdyTblprio3 ,任务的调度,C/OS是可抢占实时多任务内核,它总是运行就绪任务中优先级最高的那一个。 C/OS中不支持时间片轮转法,每个任务的优先级要
21、求不一样且是唯一的,所以任务调度的工作就是:查找准备就绪的最高优先级的任务并进行上下文切换。 C/OS任务调度所花的时间为常数,与应用程序中建立的任务数无关。,确定哪个任务的优先级最高,应该选择哪个任务去运行,这部分的工作是由调度器(Scheduler)来完成的。 任务级的调度是由函数OSSched()完成的; 中断级的调度是由另一个函数OSIntExt()完成的。,根据就绪表确定最高优先级,两个关键: 将优先级数分解为高三位和低三位分别确定; 高优先级有着小的优先级号;,根据就绪表确定最高优先级,通过OSRdyGrp值确定高3位,假设OSRdyGrp0 x08=0 x00001000,第3位
22、为1,优先级的高3位为011; 通过OSRdyTbl3的值来确定低3位,假设OSRdyTbl30 x3a,第1位为1,优先级的低3位为001,3*8+1=25,任务优先级,任务调度器,void OSSched (void) INT8U y; OS_ENTER_CRITICAL(); if (OSLockNesting | OSIntNesting) = 0) y = OSUnMapTblOSRdyGrp; OSPrioHighRdy = (INT8U)(y 3) + OSUnMapTblOSRdyTbly); if (OSPrioHighRdy != OSPrioCur) OSTCBHighR
23、dy=OSTCBPrioTblOSPrioHighRdy; OSCtxSwCtr+; OS_TASK_SW(); OS_EXIT_CRITICAL(); ,检查是否中断调用和允许任务调用,找到优先级最高的任务,该任务是否正在运行,源代码中使用了查表法,查表法具有确定的时间,增加了系统的可预测性,uC/OS中所有的系统调用时间都是确定的 Y = OSUnMapTblOSRdyGrp; X = OSUnMapTblOSRdyTblY; Prio = (Y3) + X;,参见OS_CORE.C,INT8U const OSUnMapTbl = 0, 0, 1, 0, 2, 0, 1, 0, 3, 0
24、, 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
25、, 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
26、, 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,举例: 如OSRdyGrp的值为01101000B,即0X68,则查得OSUnMapTblOSRdyGrp的值是3,它相应于OSRdyGrp中的第3位置1; 如OSRdyTbl3的值是11100100B,即0XE4,则查OSUnMapTblOSRdyTbl3的值是2,则进入就绪
27、态的最高任务优先级 Prio=3*8+2=26,任务切换,将被挂起任务的寄存器内容入栈; 将较高优先级任务的寄存器内容出栈,恢复到硬件寄存器中。,任务级的任务切换OS_TASK_SW(),通过sc系统调用指令完成 保护当前任务的现场 恢复新任务的现场 执行中断返回指令 开始执行新的任务,调用OS_TASK_SW()前的数据结构,低优先级任务 OS_TCB,OSTCBCur (1),存贮器低地址,存贮器高地址,堆栈方向,SP,R1,R2,R3,R4,PC,PSW,存贮器低地址,存贮器高地址,高优先级任务 OS_TCB,OSTCBHighRdy (3),(2),CPU,(4),(5),保存当前CP
28、U寄存器的值,低优先级任务 OS_TCB,OSTCBCur,存贮器低地址,存贮器高地址,堆栈方向,SP,R1,R2,R3,R4,PC,PSW,存贮器低地址,存贮器高地址,高优先级任务 OS_TCB,OSTCBHighRdy (3),(2),CPU,(4),(5),(1),(3),重新装入要运行的任务,低优先级任务 OS_TCB,OSTCBCur,存贮器低地址,存贮器高地址,堆栈方向,SP,R1,R2,R3,R4,PC,PSW,存贮器低地址,存贮器高地址,高优先级任务 OS_TCB,OSTCBHighRdy OSTCBCur (1),(2),CPU,(4),(4),(1),(3),(3),(4)
29、,任务切换OS_TASK_SW()的代码,Void OSCtxSw(void) 将R1,R2,R3及R4推入当前堆栈; OSTCBCurOSTCBStkPtr = SP; OSTCBCur = OSTCBHighRdy; SP = OSTCBHighRdy OSTCBSTKPtr; 将R4,R3,R2及R1从新堆栈中弹出; 执行中断返回指令; ,给调度器上锁,OSSchedlock():给调度器上锁函数,用于禁止任务调度,保持对CPU的控制权(即使有优先级更高的任务进入了就绪态); OSSchedUnlock():给调度器开锁函数,当任务完成后调用此函数,调度重新得到允许; 当低优先级的任务要
30、发消息给多任务的邮箱、消息队列、信号量时,它不希望高优先级的任务在邮箱、队列和信号量还没有得到消息之前就取得了CPU的控制权,此时,可以使用调度器上锁函数。,任务管理的系统服务,创建任务 删除任务 修改任务的优先级 挂起和恢复任务 获得一个任务的有关信息,创建任务,创建任务的函数 OSTaskCreate(); OSTaskCreateExt(); OSTaskCreateExt()是OSTaskCreate()的扩展版本,提供了一些附加的功能; 任务可以在多任务调度开始 (即调用OSStart() 之前创建,也可以在其它任务的执行过程中被创建。但在OSStart()被调用之前,用户必须创建至
31、少一个任务; 不能在中断服务程序(ISR)中创建新任务。,OSTaskCreate(),INT8U OSTaskCreate (void (*task)(void *pd), /任务代码指针 void *pdata, /任务参数指针OS_STK *ptos, /任务栈的栈顶指针 INT8U prio /任务的优先级); 返回值 OS_NO_ERR:函数调用成功;OS_PRIO_EXIT:任务优先级已经存在;OS_PRIO_INVALID:任务优先级无效。,OSTaskCreate()的实现过程,任务优先级检查 该优先级是否在0到OS_LOWSEST_PRIO之间? 该优先级是否空闲? 调用OS
32、TaskStkInit(),创建任务的栈帧; 调用OSTCBInit(),从空闲的OS_TCB池(即OSTCBFreeList链表)中获得一个TCB并初始化其内容,然后把它加入到OSTCBList链表的开头,并把它设定为就绪状态; 任务个数OSTaskCtr加1; 调用用户自定义的函数OSTaskCreateHook(); 判断是否需要调度(调用者是正在执行的任务),OSTaskCreateExt(),INT8U OSTaskCreateExt(前四个参数与OSTaskCreate相同,INT16U id, /任务的IDOS_STK *pbos, /指向任务栈底的指针 INT32U stk_s
33、ize, /栈能容纳的成员数目void *pext,/指向用户附加数据域的指针INT16U opt /一些选项信息); 返回值:与OSTaskCreate()相同。,任务的栈空间,每个任务都有自己的栈空间(Stack),栈必须声明为OS_STK类型,并且由连续的内存空间组成; 栈空间的分配方法 静态分配:在编译的时候分配,例如:static OS_STK MyTaskStackstack_size;OS_STK MyTaskStackstack_size; 动态分配:在任务运行的时候使用malloc()函数来动态申请内存空间;,OS_STK *pstk; pstk = (OS_STK *)ma
34、lloc(stack_size); /* 确认malloc()能得到足够的内存空间 */ if (pstk != (OS_STK *)0) Create the task; ,动态分配,内存碎片问题,在动态分配中,可能存在内存碎片问题。特别是当用户反复地建立和删除任务时,内存堆中可能会出现大量的碎片,导致没有足够大的一块连续内存区域可用作任务栈,这时malloc()便无法成功地为任务分配栈空间。,3Kb,堆初始状态,3个任务,删除A,C,内碎片/外碎片?,栈的增长方向,栈的增长方向的设置 从低地址到高地址:在OS_CPU.H中,将常量 OS_STK_GROWTH设定为 0; 从高地址到低地址:
35、在OS_CPU.H中,将常量 OS_STK_GROWTH设定为 1; OS_STK TaskStackTASK_STACK_SIZE; OSTaskCreate(task, pdata, ,删除任务,OSTaskDel():删除一个任务,其TCB会从所有可能的系统数据结构中移除。任务将返回并处于休眠状态(任务的代码还在)。 如果任务正处于就绪状态,把它从就绪表中移出,这样以后就不会再被调度执行了; 如果任务正处于邮箱、消息队列或信号量的等待队列中,也把它移出; 将任务的OS_TCB从OSTCBList链表当中移动到OSTCBFreeList。,OSTaskChangePrio():在程序运行期
36、间,用户可以通过调用本函数来改变某个任务的优先级。 INT8U OSTaskChangePrio(INT8U oldprio, INT8U newprio) OSTaskQuery():获得一个任务的有关信息 获得的是对应任务的OS_TCB中内容的拷贝。,OSTaskSuspend():挂起一个任务 如果任务处于就绪态,把它从就绪表中移出; 在任务的TCB中设置OS_STAT_SUSPEND标志,表明该任务正在被挂起。 OSTaskResume():恢复一个任务 恢复被OSTaskSuspend()挂起的任务; 清除TCB中OSTCBStat字段的OS_STAT_SUSPEND位,挂起和恢复任
37、务,第三章、实时操作系统C/OS-II,1,3,2,4,C/OS-II概述,任务管理,中断和时间管理,任务之间的通信与同步,5,存储管理,6,C/OS-II的移植,中断处理,中断:由于某种事件的发生而导致程序流程的改变。产生中断的事件称为中断源。 CPU响应中断的条件: 至少有一个中断源向CPU发出中断信号; 系统允许中断,且对此中断信号未予屏蔽。,中断服务程序ISR,中断一旦被识别,CPU会保存部分(或全部)运行上下文(context,即寄存器的值),然后跳转到专门的子程序去处理此次事件,称为中断服务子程序(ISR)。 C/OS-中,中断服务子程序要用汇编语言来编写,然而,如果用户使用的C语
38、言编译器支持在线汇编语言的话,用户可以直接将中断服务子程序代码放在C语言的程序文件中。,(1)保存全部CPU寄存器的值; (2)调用OSIntEnter(),或直接把全局变量OSIntNesting(中断嵌套层次)加1; (3)执行用户代码做中断服务; (4)调用OSIntExit(); (5)恢复所有CPU寄存器; (6)执行中断返回指令。,用户ISR的框架,OSIntEnter(),/* 在调用本函数之前必须先将中断关闭 */ void OSIntEnter (void) if (OSRunning = TRUE) if (OSIntNesting 255) OSIntNesting+;
39、,OSIntExit的意义,OSIntExit(),void OSIntExit (void) OS_ENTER_CRITICAL(); /关中断 if (-OSIntNesting|OSLockNesting) = 0) /判断嵌套是否为零 /把高优先级任务装入 OSIntExitY = OSUnMapTblOSRdyGrp; OSPrioHighRdy=(INT8U)(OSIntExitY 3) + OSUnMapTblOSRdyTblOSIntExitY); if (OSPrioHighRdy != OSPrioCur) OSTCBHighRdy = OSTCBPrioTblOSPrio
40、HighRdy; OSCtxSwCtr+; OSIntCtxSw(); OS_EXIT_CRITICAL(); /开中断返回 ,OSIntCtxSw(),在任务切换时,为什么使用OSIntCtxSw()而不是调度函数中的OS_TASK_SW()? 原因有二点 一半的任务切换工作,即CPU寄存器入栈,已经在前面做完了; 需要保证所有被挂起任务的栈结构是一样的。,OSIntExit的关键OSIntCtxSw,实现中断级的任务切换 ARM在栈指针调整过程中的优势,调用中断切换函数OSIntCtxSw() 后的堆栈情况,时钟节拍,时钟节拍是一种特殊的中断,相当于操作系统的心脏起搏器; C/OS需要用户
41、提供周期性信号源,用于实现时间延时和确认超时。节拍率应在10到100Hz之间,时钟节拍率越高,系统的额外负荷就越重; 时钟节拍的实际频率取决于用户应用程序的精度。时钟节拍源可以是专门的硬件定时器,或是来自50/60Hz交流电源的信号。,时钟节拍ISR,void OSTickISR(void) (1)保存处理器寄存器的值; (2)调用OSIntEnter()或将OSIntNesting加1; (3)调用OSTimeTick(); /*检查每个任务的时间延时*/ (4)调用OSIntExit(); (5)恢复处理器寄存器的值; (6)执行中断返回指令; ,时钟节拍函数 OSTimtick(),时间
42、管理,与时间管理相关的系统服务: OSTimeDLY() OSTimeDLYHMSM() OSTimeDlyResmue() OStimeGet() OSTimeSet(),OSTimeDLY(),OSTimeDLY():任务延时函数,申请该服务的任务可以延时一段时间; 调用OSTimeDLY后,任务进入等待状态; 使用方法 void OSTimeDly (INT16U ticks); ticks表示需要延时的时间长度,用时钟节拍的个数来表示。,OSTimeDLY(),void OSTimeDly (INT16U ticks) if (ticks 0) OS_ENTER_CRITICAL();
43、 if (OSRdyTblOSTCBCur-OSTCBY ,OSTimeDLY(1)的问题,OSTimeDlyHMSM(),OSTimeDlyHMSM():OSTimeDly()的另一个版本,即按时分秒延时函数; 使用方法 INT8U OSTimeDlyHMSM( INT8U hours, / 小时 INT8U minutes, / 分钟 INT8U seconds, / 秒 INT16U milli / 毫秒 );,OSTimeDlyResume(),OSTimeDlyResume():让处在延时期的任务提前结束延时,进入就绪状态; 使用方法 INT8U OSTimeDlyResume (I
44、NT8Uprio); prio表示需要提前结束延时的任务的优先级/任务ID。,系统时间,每隔一个时钟节拍,发生一个时钟中断,将一个32位的计数器OSTime加1; 该计数器在用户调用OSStart()初始化多任务和4,294,967,295个节拍执行完一遍的时候从0开始计数。若时钟节拍的频率等于100Hz,该计数器每隔497天就重新开始计数; OSTimeGet():获得该计数器的当前值; INT32U OSTimeGet (void); OSTimeSet():设置该计数器的值。 void OSTimeSet (INT32U ticks);,何时启动系统定时器,如果在OSStart之前启动定
45、时器,则系统可能无法正确执行完OSStartHighRdy OSStart函数直接调用OSStartHighRdy去执行最高优先级的任务,OSStart不返回。 系统定时器应该在系统的最高优先级任务中启动 使用OSRunning变量来控制操作系统的运行 在我们的移植版本中,使用了uCOS-II中的保留任务1作为系统任务。负责启动定时器,时钟节拍的启动,用户必须在多任务系统启动以后再开启时钟节拍器,也就是在调用OSStart()之后; 在调用OSStart()之后做的第一件事是初始化定时器中断。,void main(void) . OSInit(); /* 初始化uC/OS-II*/ /* 应用
46、程序初始化代码. */ /* 调用OSTaskCreate()创建至少一个任务*/ 允许时钟节拍中断; /* 错误!可能crash!*/ OSStart(); /* 开始多任务调度 */ ,系统的初始化与启动,在调用C/OS-II的任何其它服务之前,用户必须首先调用系统初始化函数OSInit()来初始化C/OS的所有变量和数据结构; OSInit()建立空闲任务OSTaskIdle(),该任务总是处于就绪状态,其优先级一般被设成最低,即OS_LOWEST_PRIO;如果需要,OSInit()还建立统计任务OSTaskStat(),并让其进入就绪状态; OSInit()还初始化了4个空数据结构缓
47、冲区:空闲TCB链表OSTCBFreeList、空闲事件链表OSEventFreeList、空闲队列链表OSQFreeList和空闲存储链表OSMemFreeList。,系统初始化后的状态,C/OS-II的启动,多任务的启动是用户通过调用OSStart()实现的。然而,启动C/OS-之前,用户至少要建立一个应用任务。,void main (void) OSInit(); /* 初始化uC/OS-II */ . 通过调用OSTaskCreate()或OSTaskCreateExt() 创建至少一个任务; . OSStart(); /*开始多任务调度! 永不返回*/ ,OSStart(),void
48、 OSStart (void) INT8U Y; INT8U X; if (OSRunning = FALSE) y = OSUnMapTblOSRdyGrp; x = OSUnMapTblOSRdyTbly; OSPrioHighRdy = (INT8U)(Y3) + X); OSPrioCur = OSPrioHighRdy; OSTCBHighRdy = OSTCBPrioTblOSPrioHighRdy; OSTCBCur = OSTCBHighRdy; OSStartHighRdy(); ,统计任务初始化函数OSStatInit (void),统计任务初始化,系统启动后的状态,假设用户创建的 任务优先级为6,第三章、实时操作系统C/OS-II,1,3,2,4,C/OS-II概述,任务管理,中断和时间管理,任务之间的通信与同步,5,存储管理,任务间通信与同步,任务间通信的管理:事件控制块ECB; 同步与互斥 临界区(Critical Sections); 信号量(Semaphores); 任务间通信 邮箱(Message Mailboxes); 消息队列(Message Queues)。,事件控制块ECB,ECB数据结构 typedef struct