《嵌入式系统——基础知识.doc》由会员分享,可在线阅读,更多相关《嵌入式系统——基础知识.doc(65页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、【精品文档】如有侵权,请联系网站删除,仅供学习与交流嵌入式系统基础知识.精品文档.嵌入式系统基础知识操作系统OS 控制和管理计算机软硬件资源,合理组织计算机工作流程,方便用户使用计算机的系统软件。 可将OS看成是应用程序与硬件间的接口或虚拟机。 OS功能:进程管理、存储管理、文件管理、设备管理、网络和通信管理等。嵌入式操作系统EOS 运行在嵌入式硬件平台上,对整个系统及其所操作的部件装置等资源进行统一协调、指挥和控制的系统软件。 EOS特点:微型化、可裁剪性、实时性、高可靠性、易移植性 重点关注:高实时性、硬件相关依赖性、软件固化、应用专用性、网络功能。实时操作系统TROS 能使计算机及时响应
2、外部事件请求,并能及时控制所有实时设备与实时任务协调运行,且能在规定时间内完成事件处理的OS。 RTOS基本要求: 1、逻辑功能正确:RTOS的计算必须产生正确的结果; 2、时间正确:RTOS的计算必须在预定的周期内完成。 RTOS应满足条件: 1、多任务系统; 2、任务的切换时间应与系统中的任务书无关; 3、中断延时的时间可预知并尽可能短。 无论在什么情况下,OS完成任务所需的时间应该是在程序设计时就可预知的。嵌入式实时操作系统ERTOS 用于嵌入式系统,对系统资源和多个任务进行管理,且具有高可靠性、良好可裁剪性等优良性能的,为应用程序提供运行平台和实时服务的微型系统软件。 ERTOS最重要
3、的三项服务: 1、多任务管理 2、内存管理 3、外围资源管理嵌入式微处理器(特点) 1、对实时多任务OS有很强的支持能力; 2、具有功能很强的存储区域保护功能; 3、处理器结构可扩展; 4、低功耗; 微处理器主要发展方向:小体积、高性能、低功耗 微处理器分类:MCU、MPU、DSP、SOC嵌入式系统发展方向 1、嵌入式开发是一项系统工程,嵌入式系统厂商不仅要提供嵌入式软硬件系统本身,还需要提供强大的硬件开发工具与软件支持包; 2、网络化、信息化的要求随着因特网技术的成熟、宽带的提高而日益提高,使得以往单一功能的设备功能不再单一,结构更加复杂; 3、网络互连成为必然趋势(IEEE1394、USB
4、、CAN、Bluetooth等网络接口); 4、精简系统内核、算法、降低功耗和软硬件成本; 5、提供友好的多媒体人机界面。嵌入式系统特点 机软硬件于一体,可独立工作的计算机系统。 1、专用性强; 2、可裁剪性; 3、实时性与可靠性; 4、功耗低; 5、系统内核小; 6、系统精简; 7、实时多任务OS; 8、专门开发工具与环境; 嵌入式系统的核心往往是一个只有几KB到几十KB的微内核。 通常把嵌入式系统概念的重心放在“系统”上,指能够运行OS的软硬件总体。 嵌入式系统构成,硬件:微处理器、外围接口和存储器;中间层:BSP/HAL;软件:RTOS及其上运行的应用软件。 嵌入式系统框架可分为4部分:
5、处理器、存储器、I/O、软件。 嵌入式CPU将通用CPU中许多由板卡完成的任务集成到芯片内部。 多数嵌入式设备的应用软件和OS紧密结合。嵌入式软件体系结构 1、无OS情形 (1)循环轮转方式:把系统功能分成若干不同的任务,然后把它们包含在一个无限的循环语句中,按照顺序逐一执行,之后再循环。 缺点:过于简单,无法处理异步事件,缺乏并发处理能力。 (2)前后台系统:在循环轮转的基础上,增加了中断处理功能; foreground(前台程序:事件处理级程序):中断服务程序ISR,处理异步事件; background(后台程序:任务级程序):系统管理调度程序,无限循环,负责嵌入式系统软硬件资源的分配、管
6、理及任务调度。 2、有OS情形 (1)提高了系统可靠性; (2)提高了系统开发效率,降低了开发成本,缩短了开发周期; (3)有利于系统的扩展和移植; 对不同的嵌入式操作系统,所包含的组件可能各不相同。一般来说,所有的OS都会有一个内核Kernel,内核指OS中的一个组件,包含了OS的主要功能,即OS的各种特性及其相互间的依赖关系。(任务管理、存储管理、文件管理、设备管理、网络管理)嵌入式操作系统分类 1、按“系统类型”分类:商用系统、专业系统、开源系统; 2、按“响应时间”分类:RTOS、非RTOS; 3、按“软件结构”分类:单体结构、分层结构、微内核结构; 差别体现在两方面:(1)内核的设计
7、,即内核中包含了哪些功能组件;(2)系统中集成了哪些其他的系统软件。 (1)单体结构(eg:linux):在单体结构的OS中,中间件和设备驱动程序通常集成在系统内核中,整个系统通常只有一个可执行文件,包含了所有的功能组件。整个OS由一组功能模块构成,这些功能模块间可以相互调用。 优点:性能较好,系统各模块间可以相互调用,通信开销小; 缺点:OS体积庞大,高度集成,在系统裁剪、修改和调试等方面较为困难。 (2)分层结构:在分层结构中,一个OS被划分为若干个层次,各层间的调用关系是单向的。分层结构的OS也只有一个大的可执行文件,包含设备驱动程序和中间件。要求在每个层次上都要提供一组API接口函数。
8、 (3)微内核结构(eg:VxWorks):在内核中,把OS的大部分功能都剥离出去,只保留最核心的功能单元。内核非常小,大部分的系统功能都位于内核之外。在微内核OS中,新的功能组件可以被动态地添加进来,具有易于扩充、调试方便和易于移植等特点。核内组件与核外组件间的通信是消息传递,而不是直接的函数调用。嵌入式操作系统重要概念 1、先占式内核:当前最高优先级任务一旦就绪,就立即获得CPU控制权,且控制权可知; 2、调度策略分析:(强实时、弱实时) 3、任务优先级分配:(静态优先级、动态优先级) 4、时间的可确定性: 强RTOS的函数调用与服务的执行时间具有可确定性。系统服务的执行时间不依赖于应用程
9、序任务的多少。系统完成某个确定任务的时间可预测。 5、任务切换时间:(取决于CPU有多少Reg要入栈) 6、中断响应时间:在先占式内核中,中断响应时间 = 关中断最长时间 + 保护CPU内部寄存器时间 + 进入中段服务函数的执行时间 + 开始执行ISR第一条指令的时间; 7、优先级反转:(解决方法:优先级继承、优先权极限) 8、任务执行时间的抖动 9、任务划分:(原则:I/O原则、优先级原则、大量原则、功能耦合、偶然耦合、频率组合)uC/OS-II内核架构解析(1)-嵌入式RTOS1. 嵌入式系统基本模型2. RTOS设计原则 采用各种算法和策略,始终保持系统行为的可预测性。即在任何情况下,在
10、系统运行的任何时刻,OS的资源配置策略都能为争夺资源(包括CPU、内存、网络带宽等)的多个实时任务合理地分配资源,使每个实时任务的实时性要求都能得到满足。3. GPOS与RTOS GPOS:注重每次执行的平均响应时间,而不是某次特定执行的响应时间。 RTOS:除满足应用功能需求外,还要满足实时性要求,始终保证系统行为的可预测性(predictability)。 与GPOS不同,RTOS注重的不是系统的平均表现,而是要满足每个实时任务在最坏情况下的实时性要求。也就是说,RTOS注重的是个体表现,更准确地说是个体最坏情况表现。 RTOS与GPOS的差别主要表现在: a)任务调度策略不同; b)内存
11、管理方式不同; c)中断处理方式不同; d)系统管理方式不同;4.嵌入式开发模式 单片机系统的前后台程序:不使用OS,将应用程序设计成死循环,系统轮流处理各事件,对时间响应要求高的异步事件采用中断进行处理。 基于任务(进程)的软件设计方法:使用OS,由OS管理硬件资源,任务只是在需要资源时申请即可,至于when/which,完全由OS决定。 5.(不)可重入 (1) 可重入函数:指函数代码在运行过程中可以被中断,中断返回后仍能够恢复到原来的状态,并能准确无误执行的函数。 可重入函数可以被一个以上的任务调用,而不必担心数据被破坏。可重入函数或者只使用局部变量,即变量保存在CPU寄存器或堆栈中;或
12、者使用全局变量,则要对全局变量予以保护。 (2) 不可重入函数:函数在运行过程中不可以被中断。6.互斥条件实现任务间通信最简便的办法是使用共享数据,但要保证任务在处理共享数据时的排它性。使共享资源满足互斥条件,最一般的方法有: (1)关中断 使用某种实时内核,一般情况下关中断的时间最长不超过内核本身的关中断时间,这样就不会影响系统中断延迟。 (2)使用测试并置位指令 Test&Set操作可能是微处理器一条不会被中断的指令,否则应该在程序中关中断做TAS操作再开中断。 (3)禁止做任务切换 此时任务切换虽然是禁止的,但仍允许中断。如果这时中断来了,ISR会在这一临界区内立即执行。 (4)利用信号
13、量;7.临界状态 临界状态指当前程序处于不可中断状态。一般情况下,在调用不可重入函数前或在修改全局变量数据时,都需要先进入临界状态。进入临界状态的主要操作是关闭所有可以屏蔽的中断;而退出临界状态的主要操作是恢复到上次进入临界状态时前中断管理的状态。 在uC/OS-II中,宏OS_ENTER_CRITICAL()描述进入临界状态所完成的操作,宏OS_EXIT_CRITICAL()描述退出临界状态的操作。uC/OS-II提供了3种进入和退出临界状态的办法,可以根据CPU类型由宏OS_CRITICAL_MOTHOD指定具体的临界状态处理办法。uC/OS-II内核架构解析(2)-uC/OS-II基本介
14、绍1.uC/OS-II文件结构2.uC/OS-II组成部分 uC/OS-II大致可以分成系统核心(包含任务调度)、任务管理、时间管理、多任务同步与通信、内存管理、CPU移植等部分。 (1)核心部分(OSCore.c) :uC/OS-II处理核心,包括初始化、启动、中断管理、时钟中断、任务调度及事件处理等用于系统基本维持的函数。 (2) 任务管理(OSTask.c) :包含与任务操作密切相关的函数,包括任务建立、删除、挂起及恢复等,uC/OS II以任务为基本单位进行调度。 (3) 时钟部分(OSTime.c) :uC/OS-II中最小时钟单位是timetick(时钟节拍),其中包含时间延迟、时
15、钟设置及时钟恢复等与时钟相关的函数。 (4) 多任务同步与通信(OSMbox.c, OSQ.c, OSSem.c, OSMutex.c, OSFlag.c):包含事件管理函数,涉及Mbox、msgQ、Sem、Mutex、Flag等。 (5) 内存管理部分(OSMem.c):主要用于构建私有的内存分区管理机制,其中包含创建memPart、申请/释放memPart、获取分区信息等函数。 (6) CPU接口部分:uC/OS-II针对特定CPU的移植部分,由于牵涉到SP等系统指针,通常用汇编语言编写,包括任务切换、中断处理等内容。3.uC/OS-II任务状态 在uC/OS-II中,一个任务就是一个线程
16、,该任务可以认为CPU完全属于它自己。任务有自己的堆栈和CPU寄存器,并且被赋予一定的优先级。任务可能处于睡眠、就绪、运行、等待或中断服务状态之一。4. uC/OS-II与VxWorks的比较uC/OS-II内核架构解析(3)-uC/OS-II系统核心1.uC/OS-II任务调度(1)uC/OS-II调度算法 uC/OS-II采用基于优先级的调度算法,总是选择当前处于就绪状态的优先级最高的任务进行调度。uC/OS-II是可抢占性的强实时性OS,在完成中断后允许进行新的任务调度。 uC/OS-II有两种调度方式:任务级任务调度、中断级任务调度。(2)任务就绪表 INT8U const OSUnM
17、apTbl256 = ; OS_EXT INT8U OSRdyGrp; OS_EXT INT8U OSRdyTblOS_RDY_TBL_SIZE; 添加就绪任务至就绪表; 从就绪表删除就绪任务; 查找最高优先级就绪任务OS_SchedNew(); (3)任务级任务调度 指在非中断返回时进行任务调度,一般发生在当前任务因时间延迟或等待某事件而阻塞或被挂起,或有更高优先级的任务处于就绪状态。 任务的基本信息: CPU的PC寄存器:任务当前执行的位置; CPU的通用寄存器:任务当前执行涉及的临时数据; CPU的状态寄存器:存储当前CPU的状态。 任务级任务切换:从一个任务直接切换至另一个任务,不涉及
18、CPU状态的切换,OS_TASK_SW()既保存当前任务上下文,又恢复新任务上下文。 过程:OS_Sched() - OS_SchedNew() - OS_TASK_SW()(4)中断级任务调度 中断级任务切换:在中断处理完成后,通过OSIntExit()判断是否有更高优先级就绪任务。如果有,调用OSIntCtxSW()恢复新任务上下文。注意:在中断处理中,已经保存了被中断任务的上下文,所以这里仅仅恢复。 过程:OSIntExt() OSIntEnter() - ISR OSIntExit() - OSIntCtxSW()(5)调度器上锁与解锁 uC/OS-II提供调度器锁定功能,在锁定期间不
19、能进行任务调度。uC/OS-II使用全局变量OSLockNesting标识是否锁定了任务调度器。 OS_EXT INT8U OSLockNesting; void OSSchedLock(void); void OSSchedUnlock(void); (6)中断管理函数 在中断处理中,不允许进行任务管理、事件管理及任务调度等操作。uC/OS-II通过全局变量OSIntNesting标识当前是否处于中断状态。在所有任务及事件管理的程序中,都有对OSIntNesting进行判断的语句。 void OSIntEnter(void); void OSIntExit(void); (7)中断相关问题
20、OS_ENTER_CRITICAL() OS_EXIT_CRITICAL() 关中断使得uC/OS-II能够同时避免有其他任务或中断服务进入临界代码段。调用uC/OS-II功能函数时,中断总应当是开着的。 uC/OS-II如何禁止调度? 在中断中允许调度吗?为什么? uC/OS-II如何屏蔽中断? 2.uC/OS-II系统启动 uC/OS-II首先调用OSInit()进行初始化,然后创建任务(此时还未启动系统,仅仅为其分配资源),然后调用OSStart()启动系统,将CPU控制权交给uC/OS-II,OS根据任务优先级选择由哪个任务开始执行,或创建新的任务。(1)初始化函数OSInit() O
21、SInit()主要完成初始化操作,包括初始化全局变量(在OS_InitMisc()中)、任务就绪表、TCB、ECB、FCB、内存单元、消息队列,并创建空闲任务。如果有必要,创建统计任务。 OS_InitMisc(); /初始化部分全局变量 OS_InitRdyList(); /初始化任务就绪表 OS_InitTCBList(); /初始化空闲TCB链表 OS_InitEventList(); /初始化ECB链表 OS_FlagInit(); /初始化事件组标志结构 OS_MemInit(); /初始化内存管理 OS_QInit(); /初始化消息队列 OS_InitTaskIdle(); /创
22、建空闲任务 OS_InitTaskStat(); /创建统计任务 uC/OS-II初始化了5个空的数据结构缓冲区,每个缓冲区都是单向链表,允许uC/OS-II从缓冲区中迅速取得或释放一个缓冲区中的元素。 uC/OS-II调用OSInit()后的变量与数据结构如下图所示:(2)启动函数OSStart() OSStart()在一切准备就绪且需要首先创建的任务都被创建后,启动uC/OS-II。它从就绪表中查找最高优先级就绪任务,并恢复其上下文开始执行。 过程:OSStart() - OS_SchedNew() - OSStartHighRdy() 问题:任务第一次被调用时,哪来的上下文供其恢复呢?创
23、建任务时,调用了OSTaskStkInit()初始化任务堆栈,可此函数中没有涉及任务的上下文呀? uC/OS-II调用OSStart()后的变量和数据结构如下图所示:(3)统计任务OSTaskStat OSTaskStat用于计算CPU利用率。设置OS_CFG.H中的OS_TASK_STAT_EN为1,创建统计任务,在系统启动后一直处于就绪状态。刚开始时,空闲任务运行1S,为计算CPU利用率提供一个基准值,并保存在统计任务的堆栈中,这个值不会改变除非重新启动CPU。此后空闲任每次被其它任务抢去CPU时,它里面的计数器就会直接记录下CPU空闲的时间。3.uC/OS-II系统时钟 任何实时系统的时
24、钟硬件设备每隔一段时间(一个系统tick)产生一个硬件中断,OS接收到该中断后,更新时间计数器,更新所有对时钟依赖的程序代码,从而维持系统有序稳定的运行。 主要包含在C源文件OS_TIME.C中。 #define OS_TICKS_PER_SEC 100 /系统时钟中断间隔 OS_EXT volatile INT32U OSTime; /系统运行的时间值 void OSTimeTick(void); /时钟中断服务程序 void OSTimeDly(INT16U ticks); /延迟指定时钟节拍 INT8U OSTimeDlyHMSM(); /延迟指定时间长度 INT8U OSTimeDly
25、Resume(prio); /恢复等待(时延/阻塞)任务 INT32U OSTimeGet(void); /读取当前时间 void OSTimeSet(INT32U ticks); /设置当前时间 4.uC/OS-II事件管理(1) 事件控制块 INT8U OSEventType; /事件类型 void *OSEventPtr; /指向MBox或Queue INT16U OSEventCnt; /信号量计数器(注:Mutex) INT8U OSEventGrp; /事件等待组标志 INT8U OSEventTbl; /时间任务等待表 INT8U OSEventName; /时间名称 (2) E
26、CB管理机制 OS_EXT OS_EVENT *OSEventFreeList; /空闲ECB链表指针 OS_EXT OS_EVENT OSEventTbl; /ECB结构体数组 (3) ECB管理函数 OS_InitEventList():初始化ECB; OS_EventWaitListInit():在创建事件时调用,初始化ECB任务等待表; OS_EventTaskRdy():在事件发生时调用,修改此事件中最高优先级任务的TCB成员变量,在任务就绪表中添加此任务,将相应信息传递给该任务TCB,并将此任务从事件的任务等代表中删除; OS_EventTaskWait():在申请资源失败而暂停当
27、前任务时被调用,将任务从任务就绪表中删除,并添加到事件的任务等代表中; OS_EventTO():在事件等待超时时调用,将此任务从事件的任务等代表中删除,并修改该任务的TCB成员变量; uC/OS-II内核架构解析(4)-uC/OS-II任务管理1.C可执行代码结构 (1)代码段.text:存放CPU执行的机器指令,通常.text是可共享且只读的。 (2)数据段.data:.rodata(常量数据)、.rwdata(已初始化全局变量、静态变量)。 (3)未初始化数据段.bss:未初始化的全局变量、静态变量。 (4)栈.stack:存放函数参数、局部变量及任务切换时的上下文。(5)堆.heap:
28、用于动态内存分配。2. 任务结构 在uC/OS-II中,任务是事件运行和管理的基本单元。一个uC/OS-II任务至少包含程序代码、栈和TCB,还可选择性使用相当于堆的动态内存空间。程序运行时,uC/OS-II中的任务相当于可执行代码(可单独运行的单元)。 uC/OS-II任务的各部分如何管理?3.任务栈 任务栈数据类型:typedef unsigned short OS_STK 任务栈增长方向:#define OS_STK_GROWTH 0/1 任务栈基本功能:? 4.任务控制块(1)TCB描述 主要用来存储任务的当前属性。(问:任务第一次被调度时,该如何运行?)(2)TCB主要成员 任务栈空
29、间位置:OSTCBStkPtr、OSTCBStkBottom、OSTCBStkSize; 任务通信与同步:OSTCBEventPtr、OSTCBMsg; 任务事件组标志:OSTCBFlagNode、OSTCBFlagsRdy; 任务等待/阻塞:OSTCBDly、OSTCBPendTO; 任务当前状态:OSTCBStat; 任务优先级:OSTCBPrio; (3)TCB全局变量 OS_EXT OS_TCB OSTCBTblOS_MAX_TASKS + OS_N_SYS_TASKS; OS_EXT OS_TCB OSTCBPrioTblOS_LOWEST_PRIO + 1; OS_EXT OS_T
30、CB *OSTCBFreeList; OS_EXT OS_TCB *OSTCBList; OS_EXT OS_TCB *OSTCBHighRdy; OS_EXT OS_TCB *OSTCBCur; 5.任务状态切换6.任务管理函数 OS_TASK.C:11个函数 OSTaskCreate(); OSTaskCreateExt(); OSTaskDel(); OSTaskDelReq(); OSTaskChangePrio(); OSTaskSuspend(); OSTaskResume(); OSTaskNameGet(); OSTaskNameSet(); OSTaskStkChk(); O
31、S_TaskStkClr(); OSTaskQuery(); uC/OS-II内核架构解析(5)-uC/OS-II通信与同步1. 消息邮箱Mbox Mbox用于多任务间单一消息的传递,uC/OS-II使用ECB管理Mbox的基本信息,OSEventPtr指向创建Mbox时指定的内存空间。事件的创建由具体的事件管理程序实现。主要包含在C源文件OS_MBOX.C中。 OS_EVENT *OSMboxCreate(void *msg); void *OSMboxPend(OS_EVENT *pevent, INT16U timeout, INT8U *err); void *OSMboxAccept
32、(OS_EVENT *pevent); INT8U OSMboxPost(OS_EVENT *pevent, void *msg); INT8U OSMboxPostOpt(OS_EVENT *pevent, void *msg, INT8U opt); OS_EVENT *OSMboxDel(OS_EVENT *pevent, INT8U opt, INT8U *err); INT8U OSMboxQuery(OS_EVENT *pevent, OS_MBOX_DATA *); 2.消息队列msgQ(1)msgQ基本内容 msgQ是uC/OS-II任务间通信的机制,可实现多条消息传递,即可以
33、同时存储多条消息。uC/OS-II使用循环队列管理机制。主要包含在C源文件OS_Q.C中。 msgQ管理:使用指针数组存储所有消息的位置;使用QCB标识指针数组中消息的基本信息;使用ECB管理整个msgQ。QCB在编译时分配空间,即当前系统中可用的msgQ个数是预先设置的,系统运行时不能修改。(2)msgQ全局变量 OS_EXT OS_Q *OSQTblOS_MAX_QS; /QCB结构体数组 OS_EXT OS_Q *OSQFreeList;/空闲QCB头指针 typedef struct os_q/消息队列控制块 struct os_q *OSQPtr; /用于构建空闲QCB链表void
34、*OSQStart; /指向msgQ指针数组的起始位置void *OSQEnd; /指向msgQ指针数组的结束位置void *OSQIn; /指向msgQ指针数组下一个可以插入消息的位置void *OSQOut; /指向msgQ指针数组下一个可以读出消息的位置INT16U OSQSize; /msgQ指针数组的大小 INT16U OSQEntries; /msgQ指针数组当前可以读取的消息个数 OS_Q;(3)msgQ管理函数 OS_EVENT *OSQCreate(void *start, INT16U size); INT8U OSQPost(OS_EVENT *pevent, void
35、*msg); /发送消息到队尾 INT8U OSQPostFront(OS_EVENT *pevent, void *msg); /msg至队首 INT8U OSQPostOpt(OS_EVENT *pevent, void *msg, INT8U opt); void *OSQPend(OS_EVENT *pevent, INT16U timeout, INT8U *err); void *OSQAccept(OS_EVENT *pevent, INT8U *err); OS_EVENT *OSQDel(OS_EVENT *pevent, INT8U opt, INT8U *err); IN
36、T8U OSQQuery(OS_EVENT *pevent, OS_Q_DATA*); INT8U OSQFlush(OS_EVENT *pevent); (4)msgQ几个问题uC/OS-II中,什么是事件?事件是uC/OS-II管理任务间同步与通信的机制。事件是处理事件的对象感兴趣的,能够感知或捕获到一种事件状态的改变。3.信号量Sem Sem主要用来实现任务间同步及标识某类资源的可用个数,即某个特定资源可供多少任务同时使用。主要包含在C源文件OS_SEM.C中。 OS_EVENT *OSSemCreate(INT16U cnt); void OSSemPend(OS_EVENT *pev
37、ent, INT16U timeout, INT8U *err); INT16U OSSemAccept(OS_EVENT *pevent); INT8U OSSemPost(OS_EVENT *pevent); OS_EVENT *OSSemDel(OS_EVENT *pevent, INT8U opt, INT8U *err); INT8U OSSemQuery(OS_EVENT *pevent, OS_SEM_DATA*); void OSSemSet(OS_EVENT *pevent, INT16U cnt, INT8U *err); 4.互斥锁Mutex(1)Mutex基本原理 Mu
38、tex用来实现对资源的排他性访问,可能引起优先级反转。任何任务在占有某个互斥锁事件时,都不能阻塞等待其它任何事件,否则会造成死锁。主要包含在C源文件OS_MUTEX.C中。 优先级反转是指,低优先级任务占有高优先级任务运行所需的资源,而使高优先级不得不等低优先级任务把资源释放才能执行。 uC/OS-II使用ECB管理Mutex,其成员变量OSEventCnt:高8位存储Mutex被使用时提供给任务的prio;低8位在没有任务占有Mutex时为0xFF,否则为占有任务的prio。 优先级反转及优先级反转避免分别如下图所示:(2)提升/恢复优先级 a)提升Mutex拥有者任务的优先级的相关操作:
39、如果该任务原来处于就绪状态,则从就绪表中将其删除;如果该任务正在等待某个事件,则从该事件的任务等待表中将其删除; 修改拥有Mutex的TCB,将其OSTCBPrio修改为欲提升的优先级; 如果该任务处于就绪状态,则将提升的优先级加载到任务就绪表中;如果该任务未就绪且正在等待某个事件,则将提升的优先级添加到该事件的任务等待表中,并修改TCB中OSTCBEventPtr; 修改TCB中与优先级相关的成员变量。 b)恢复Mutex拥有任务的优先级的相关操作: 从任务就绪表中删除提升过的优先级值,修改当前TCB中与优先级相关的所有成员变量; 再次保留提升的优先级值控制块入口,避免将其分配给其它任务。
40、(3)Mutex管理函数 #define OS_MUTEX_KEEP_LOWER_8 0x00FF #define OS_MUTEX_KEEP_UPPER_8 0xFF00 #define OS_MUTEX_AVAILABLE 0x00FF OS_EVENT *OSMutexCreate(INT8U prio, INT8U *err); void OSMutexPend(OS_EVENT *pevent, INT16U timeout, INT8U *err); INT8U OSMutexAccept(OS_EVENT *pevent, INT8U *err); INT8U OSMutexPo
41、st(OS_EVENT *pevent); OS_EVENT *OSMutexDel(OS_EVENT*, INT8U opt, INT8U *err); INT8U OSMutexQuery(OS_EVENT*, OS_MUTEX_DATA*); 5.事件组标志Flag(1)Flag基本原理 uC/OS-II提供事件组标志实现多事件管理。Flag只是使用0/1来表示某个事件是否发生过,而不能直接被用来传递数据和消息。可以选择性地设置一个Flag最多可以管理的任务同步状态。主要包含在C源文件OS_FLAG.C中。(2)Flag数据结构 #define OS_FLAGS_NBITS 8/16/32 /定义OS_FLAGS的位数 FCB结构体: typedef struct os_flag_grp INT8U OSFlagType; /事件类型 void *OSFlagWaitList; /指向等待的任务链表 OS_FLAGS OSFlagFlags; /信号列表 INT8U OSFlagNameOS_FLAG_NAME_SIZE;OS_FLAG_GRP; 事件标志等待链表结点 typedef struct os_flag_node