UCOSII培训材料

上传人:沈*** 文档编号:99418672 上传时间:2022-05-31 格式:DOC 页数:25 大小:501.50KB
收藏 版权申诉 举报 下载
UCOSII培训材料_第1页
第1页 / 共25页
UCOSII培训材料_第2页
第2页 / 共25页
UCOSII培训材料_第3页
第3页 / 共25页
资源描述:

《UCOSII培训材料》由会员分享,可在线阅读,更多相关《UCOSII培训材料(25页珍藏版)》请在装配图网上搜索。

1、内容介绍1、介绍 uC/OS-II 嵌入式操作系统2、基于 uC/OS-II 的用电管理终端软件的设计 书籍:嵌入式实时操作系统 uC/OS-II 作者: Jean LabrosseuC/OS-ll V2.52通过了美国航空航天管理局(FAA)的安全认证; 安全性、可靠性是得到认证的。我们为什么会选择 uC/OS-ll 嵌入式操作系统? 1、与终端硬件平台相适应全部源代码5500行,可裁减定制,生成的可执行代码占 1520k, 可以移植到多种系列单片机上,包括 ARM ;2、考虑成本,免费的源代码公开;3、uC/OS-ll 代码简单,容易掌握和使用;具有多任务调度的基本功能;uC/OS-ll

2、嵌入式操作系统的缺点:1、缺少技术支持,相关的支持软件少;64 等);对2、和商业软件比,功能较弱(如不支持时间片轮转,最大任务数为 应用开发的支持不够;1uC/OS 内核介绍和基于 RTOS 的设计介绍一、概述使用嵌入式 RTOS 的优点1 将复杂的系统分解为多个相对独立的任务, 采用“分而治之” 的方法降低系统的复杂 度。通过将应用程序分割成若干独立的任务, RTOS 使得应用程序的设计过程大为简化;2 使得应用程序的设计和扩展变得容易,无需较大的改动就可以增加新的功能;3 用户给系统增加一些低优先级的任务, 则用户系统对高优先级的任务的响应时间几乎 不受影响;4 实时性能得到提高。 使用

3、可剥夺型内核, 所有时间要求苛刻的事件都得到了尽可能快 捷有效的处理;5 通过有效的服务,如信号量、邮箱、队列、延时及超时等, RTOS 使资源得到更好的 利用;使用嵌入式 RTOS 的缺点1 使用 RTOS 增加了系统的内存和 CPU 等使用开销,例如任务之间的通讯、 RTOS 的 调度程序等;2 需要采用一些新的软件设计方法, 对系统设计人员的要求高一些。 例如驱动程序的设 计要考虑到共享资源的互斥问题;3 系统任务的划分是比较复杂的过程,需要设计人员对业务和 RTOS 操作系统都很熟 悉。uC/OS 操作系统的特点uC/OS 是一个完成的,可移植、可固化、可裁减的抢占式实时多任务操作系统

4、内核。主要用 ANSI 的 C 语言编写,少部分代码是汇编语言。 uC/OS 主要有以下特点:1、可移植性 可以移植到多个 CPU 上,包括三菱单片机。2、可固化 可以固化到嵌入式系统中3、可裁减可以定制 uC/OS ,使用少量的系统服务4、可剥夺性uC/OS是完全可剥夺的实时内核,uC/OS总是运行优先级最高的就绪任务。5、 多任务运行uC/OS 可以管理最多 64 个任务。不支持时间片轮转调度法,所以要 求每个任务的优先级不一样。6、可确定性 uC/OS 的函数调用和系统服务的执行时间可以确定。7、任务栈 每个任务都有自己的单独的栈,而且每个任务栈空间的大小可以不一样。8、系统服务 uC/

5、OS 有很多系统服务,如信号量、时间标志、消息邮箱、消息队列、时 间管理等等。二、 uC/OS 内核介绍基本概念1、前后台系统 也称为超循环系统。应用程序是一个无限的循环,循环中实现相应的操作, 这部分看成后台行为。 用中断服务程序处理异步事件, 处理实时性要求很强的操作, 这部分 可以看成前台行为。2、共享资源 可以被一个以上任务使用的资源叫做共享资源。3、任务:一个任务是一个线程,一般是一个无限的循环程序。一个任务可以认为CPU 资源完全只属于自己。任务可以是以下五种状态之一:休眠态,就绪态,运行态,挂起态和被 中断态。 uC/OS-II 提供的系统服务可以使任务从一种状态变为另一种状态。

6、4、任务切换:任务切换就是上下文切换,也是CPU 寄存器内容切换。当内核决定运行另外的任务时,它保存正在运行任务的当前状态( CPU 寄存器的内容)到任务自己的栈区。 入栈完成后,就把下一个将要运行的任务状态从该任务的栈中重新装入 CPU 寄存器,并开 始下一个任务的运行,这个过程叫做任务切换。5、内核 多任务系统中内核负责管理和调度各个任务,为每个任务分配 CPU 时间,并负 责任务间的通信。 内核总是调度就绪态的优先级最高的任务。 内核本身增加了系统的额外负 荷,因为内核提供的服务需要一定的执行时间。6、 可剥夺型内核 uC/OS II 以及绝大多数商业实时内核都是可剥夺型内核。最 高优先

7、级的任务一旦就绪,就抢占运行着的低优先级的任务,得到 CPU 的使用 权。7、 可重入函数:可以被多个任务调用,并且不用担心数据会被破坏的函数。8、 优先级反转 优先级反转问题是使用实时内核系统中出现最多的问题。 描述如下: 假设 当前系统有任务 3 在运行,并且低优先级的任务 3 占用了共享资源, 而高优先级任务 1就绪 得到 CPU 使用权后,也要使用任务 3 占用的共享资源,任务 1 只能挂起等待任务 3 使用完 共享资源。任务 3 继续运行时,优先级在任务 1 和任务 3 之间的任务 2 就绪并抢占了任务 3 的 CPU 使用权,直到运行完后才把 CPU 使用权还给任务 3 。任务 3

8、 继续运行,在释放了共 享资源后任务 1才得以运行。 这样,任务 1实际上降到了任务 3 优先级的水平。 这种情况就是优先级反转问题。uC/OS-ll中,可以利用互斥信号量来这个解决。9、 互斥方法使用共享数据结构进行任务间通信时,要求对其进行互斥。保证互斥的方法 有:关中断、使用测试变量、禁止任务切换和利用信号量。10、 同步 可以利用信号量使任务与任务,任务与ISR之间同步。任务之间没有数据交换。11、 事件标志:当任务要与多个事件同步时,需要使用事件标志(event flag)。事件标志同步分为独立型同步(逻辑“或”关系)和关联型同步(逻辑“与”关系)。12、 任务间通信:任务间信息的传

9、递有两个途径,通过全局变量或者通过内核发消息给另一个任务。通过内核服务发送的消息包括:消息邮箱、消息队列。任务或者ISR可以把一个指针放到消息邮箱中,让另一个任务接收。消息队列实际上是邮箱阵列。13、 时钟节拍:是特定的周期性的定时器中断。 时钟节拍是系统的心脏脉动, 提供周期性的 信号源,是系统进行任务调度的频率依据和任务延时依据。时钟节拍越快,系统开销就越大。 我们移植过程中采用的方法:初始化定时器 TA0,周期是20ms,作为操作系统时钟节拍。uC/OS-ll内核结构1、uC/OS-II是以源代码形式提供的实时操作系统内核,其包含的文件结构如下:应用软件(用户代码)uC/OS-ll内核文

10、件(与处理器类型无关的代码 )OS_CORE.COS_TASK.COS_FLAG.COS_TIME.COS_MBOX.CuCOS-II.COS_MEM.CuCOS-II.HOS_MUTEX.COS_SEM.COS Q.CuC/OS-ll配置文件(与应用程序有关)OS_CFG.HINCLUDES.H移植 uC/OS-ll(与处理器类型有关的代码)软件OS_CPU.HOS_CPU_C.COS_CPU_A.ASMCPU定时器硬件35图1、uC/OS-ll的文件结构#说明:基于 uC/OS-II 操作系统进行应用系统时,设计任务的主要任务是将系统合理划分成多 个任务,并由 RTOS 进行调度,任务之间

11、使用 uC/OS-II 提供的系统服务进行通信,以配合 实现应用系统的功能。上图中应用代码部分主要是设计人员设计的业务代码。与前后台系统一样, 基于 uC/OS-II 的多任务系统也有一个 main 主函数, main 函数由编 译器所带的 C 启动程序调用。在 main 主函数中主要实现 uC/OS-II 的初始化 OSInit() 、任务 创建、一些任务通信方法的创建、uC/OS-ll的多任务启动 OSStart()等常规操作。另外,还有一些应用程序相关的初始化操作,例如:硬件初始化、数据结构初始化等。在使用 uC/OS-ll 提供的任何功能之前,必须先调用 OSlnit() 函数进行初始

12、化。在 main 主函数中调用OSStart()启动多任务之前,至少要先建立一个任务。否则应用程序会崩溃。OSInit()初始化uC/OS-ll所有的变量和数据结构,并建立空闲任务OS_Taskldle(),这个任务总是处于就绪态。例子:一个典型的应用程序 main 主函数如下void main(void)/* 硬件初始化,等用户代码初始化 */init_mcu();init_lcd();init_hdtimer();OSlnit(); /* 初始化 uC/OS-ll */* 通过调用 OSTaskCreate ( ) 或 OSTaskCreateExt ( )创建至少一个任务; */OSTa

13、skCreate(sample_Task, (void*)0, &sample_TaskStkTASK_STK_SlZE - 1, 2 );/* 通过调用 OSSemCreate() 创建信号量等任务通信方式; */CalcSem = OSSemCreate(0);OSStart(); /*开始多任务调度!OSStart()永远不会返回 */调用OSStart()后,uC/OS-ll就运行main函数所创建任务中优先级最高的一个就绪任务。用户应该在uC/OS-ll启动运行后的第1个任务中调用时钟节拍启动函数。在uC/OS-ll移植到M16C62的过程中实现了函数 init_timer_taO(

14、),来初始化时钟 TA0。本文后面有关部分讨论 了时钟节拍的问题。上例中如果创建了多个(n个)任务,在 main函数调用OSStart()后,操作系统就启动 了多任务调度,接管了 CPU和其他资源的使用权,负责为每个任务分配 CPU使用权和使用 时间,同时对共享资源进行管理。从宏观上看,整个系统就象有多个执行的程序并行运行, 每个程序都是无限循环的main函数。如下图所示:7#ISRnISR1ISR2图2由多个任务和多个中断组成的实时多任务系统文件OS_CFG.H是与应用程序有关的配置文件,主要是对操作系统进行设置。包括:设置系统的最多任务数 OS_MAX_TASKS ;最多事件控制块设置 O

15、S_MAX_EVENTS ;堆栈方向的设置 OS_STK_GROWTH ( 1为递减、0为递增);是否支持堆栈检验 OS_TASK_CREATE_EXT ;是否支持任务统计 OS_ASK_STAT_EN ;是否支持事件标志组 OS_FLG_EN文件INCLUDES.H 是主控头文件,包含了整个系统需要的所有头文件。包括操作系统的头文件和用户设计的应用系统的头文件。OS_CPU.H、OS_CPU_A.ASM等文件是与移植 uC/OS-ll有关的文件,包含了与处理器类型有关的代码。这几个文件的介绍参见何博士的uC/OS-ll移植文档。2、uC/OS-II内核体系结构图uC/OS-ll内核主要对用户

16、任务进行调度和管理, 并为任务间共享资源提供服务。 包含的 模块有任务管理、任务调度、任务间通信、时间管理、内核初始化等。uC/OS-ll内核体系结构如下所示:应用程序任务1任务2任务3多任务应用程序任务n任务管理任务调度内存管理任务间通信uC/OS-II 初 始化OSInit任务创建任务删除任务切换/亠口 曰. 信号量挂起任务OS_TASK_SW()OSl ntCtxSw()事件控制块互斥信号量事件标志组uC/OS-II 启 动 OSStart恢复任务时间管理任务控制块消息邮箱消息队列操作系统硬件任务延时任务堆栈任务延时恢复TT时钟节拍中断服务ISRISRISRCPU串行l/O定时器RAMR

17、OM图3、uC/OS-II内核体系结构3、任务状态及其转换关系在多任务系统中,任务是设计者实现应用系统的基本形式,也是uC/OS-II系统进行调度的基本单元。任务可以是一个无限的循环, 也可以在一次执行后被操作系统删除。 任务函 数和任何C函数一样,具有一个返回类型和一个参数, 但是它决不返回。任务必须是以下2 种结构之一:void Y ourTask(void pdata)for ( ; ; ) /* 用户代码 */或void Y ourTask(void *pdata)/* 用户代码 */OSTaskDel(OS_PRIO_SELF);在任一给定的时刻, uC/OS-II 的任务状态只能是

18、以下 5 种之一: 睡眠态:指任务驻留在程序空间( ROM 或 RAM ),还没有交给 uC/OS-II 来管理。通过 创建任务将任务交给 uC/OS-II 。任务被删除后就进入睡眠态。就绪态: 任务创建后就进入就绪态。 任务的建立可以在多任务运行之前, 也可以动态的 由一个运行的任务建立。运行态:占用 CPU 资源运行的任务,该任务为进入就绪态的优先级最高的任务。任何 时刻只能有一个任务处于运行态。等待状态: 由于某种原因处于等待状态的任务。 例如, 任务自身延时一段时间, 或者等 待某一事件的发生。中断服务态: 任务运行时被中断打断, 进入中断服务态。 正在执行的任务被挂起, 中断 服务子

19、程序控制了 CPU 的使用权。uC/OS-II 控制下的任务状态转换图如下:OSQPostOOSQPostFro nt()OSSemPost()OSTaskResume()OSTimeDlyResumeOOSFlagPe nd() OSMboxPe nd() OSMutexPe nd()OSQPe nd()OSSemPe nd() OSTaskSuspe nd() OSTimeDly()OSTimeDlyHMSM()OSStart()OSTaskCreate()OSIHL EXil()OSTaskCreateExQOS_TASK_SW()OSTaskDel()就绪态任 务中断OSTaskDel

20、()睡眠态任务任务的CP使用权被剥夺OSTaskDel()运行态任务OSIn tExit()中断服务态任务图4、uC/OS-ll的任务状态转换图3、任务控制块(OS_TCB )任务控制块(TCB )是一个数据结构 OS_TCB,旦一个任务创建,就有一个和它关联 的TCB被赋值。当任务的 CPU使用权被剥夺时,它用来保存该任务的状态。这样,当任务 重新获得CPU使用权时,可以从 TCB中获取任务切换前的信息,准确的继续运行。任务控制块包含了许多任务信息,主要有:.OSTCBStkPtr指向当前任务堆栈栈顶的指针。uC/OS-ll允许每个任务有自己的堆栈,每个任务堆栈的大小可以不一样。.OSTCB

21、Next和.OSTCBPrev指向OS_TCB双向链表的前、后连接。.OSTCBEventPtr 指向事件控制块的指针;.OSTCBDly保存任务的延时节拍数,或允许等待事件发生的最多节拍数。.OSTCBPrio 任务的优先级;文件OS_CFG.H中定义的最多任务数 OS_MAX_TASKS决定了分配给用户程序的任务 控制块的数目。所有的任务控制块都放在任务控制块数组OSTCBTbl中。uC/OS-ll初始化时,所有OS_TCB都被链接成单向空任务链表。任务一旦建立,就将链表开头的OS_TCB赋给该任务。一旦任务被删除,OS_TCB就还给空任务链表。任务建立时,函数OS_TCBInit() 初

22、始化任务控制块。4、任务调度器uC/OS-II 总是运行进入就绪态的优先级最高的任务。 任务调度器的功能是: 在就绪表中 查找最高优先级的任务, 然后进行必要的任务切换, 运行该任务。 uC/OS-II 的任务调度有两 种情况:任务级的任务调度由 OS_Sched() 完成;中断级的任务调度由 OSIntExt() 完成。这两 种任务调度情况调用的任务切换函数不同:任务级的任务调度 OS_Sched() 调用了任务切换 函数 OS_TASK_SW() ,而中断级的调度 OSIntExt() 调用了任务切换函数 OSIntCtxSw() 。任务级的任务调度是由于有更高优先级的任务进入就绪态,当前

23、的任务的 CPU 使用权 被剥夺,发生了任务到任务的切换;中断级的调度是指当前运行的任务被中断打断,由于 ISR 运行过程中有更高优先级的任务被激活进入就绪态。而中断返回前 ISR 调用 OSIntExt() 函数, 该函数查找就绪表发现有必要进行任务切换,从而被中断的任务进入等待状态, 运行被激活的高优先级的任务。任务切换任务切换有两种: OS_TASK_SW() 和 OSIntCtxSw() 。任务级的任务切换 OS_TASK_SW() 是宏调用, 通过软中断指令来实现 CPU 寄存器内容 切换。例如: #define OS_TASK_SW() asm(“int #32 ”),具体实现参见

24、移植文档。任务级的任务切换过程:1) 保存当前运行的任务的 CPU 寄存器值到该任务的堆栈。如:堆栈指针,程序计数器, 状态寄存器等。2) 将要运行的高优先级的任务的寄存器值从堆栈恢复到 CPU 寄存器。3) 进行 TCB 的切换,并运行任务。中断级的任务切换 OSIntCtxSw() 是在 OSIntExt() 中调用的, 我们一般在用户 ISR 中调用 OSIntExt() 以实现中断返回前的任务调度。 由于 ISR 已经将 CPU 寄存器的值存入被中断的任 务的堆栈中,所以 OSIntCtxSw() 的实现和 OS_TASK_SW() 不一样,具体参见移植文档。 就绪表每个就绪的任务都放

25、在就绪表中,就绪表有两个变量: OSRdyGrp 和 OSRdyTbl 。 OSRdyGrp 中,将任务按优先级分组,八个为一组。 OSRdyGrp 的每一位代表每组任务是否 有进入就绪态的任务。在就绪表中查找优先级最高的任务不需要扫描整个 OSRdyTbl ,只要查优先级判定表 OSUnMapTbl 。 OSUnMapTbl 是常量表,所以查找优先级最高的任务的执行时间为常量, 和就绪表的任务数无关。5、中断服务在用户的ISR中可以调用 OSIntEnter()和OSIntExit()通知uC/OS-ll发生了中断,这样可以实现ISR返回前的任务调度。uC/OS-ll中的中断服务子程序示例:

26、用户中断服务子程序:保存CPU寄存器;调用 OSIntEnter();if( OSI ntNest ing = 1) OSTCBCur - OSTCBStkPtr = SP;清中断源;重新开中断;执行用户ISR代码;调用 OSIntExit();恢复CPU寄存器;执行中断返回指令;6、时钟节拍uC/OS-II要求用户提供一个周期性的时钟源,来实现时间的延迟和超时功能,时钟节拍应该每秒发生10100次/秒。时钟节拍率越高,系统的额外负荷就越重。应该在多任务系统启动后,也就是调用OSStartO后再开启时钟节拍器。系统设计者可以在第1个开始运行的任务中调用时钟节拍启动函数。假设用定时器TA0作为时

27、钟中断源,那么,在移植过程中实现了函数init_timer_taO(),此函数用来初始化定时器TA0,并将其打开。uC/OS-II中的时钟节拍服务是在ISR中调用OSTimeTick()实现的。OSTimeTick()跟踪所有任务的定时器以及超时时限。7、uC/OS-II的初始化和启动调用uC/OS-II的服务之前要先调用系统初始化函数OSInit()。OSInit()初始化uC/OS-II所有的变量和数据结构,并建立空闲任务。uC/OS-II初始化任务控制块、事件控制块、消息 队列缓冲、标志控制块等数据结构的空缓冲区。多任务的启动是通过调用 OSStart() 实现的。启动之前要至少创建一个

28、任务。 OSStart() 调用就绪任务启动函数 OSStartHighRdy() ,其功能是将任务栈的值恢复到 CPU 寄存器,并 执行中断返回指令,强制执行该任务代码。任务管理uC/OS-II 可以管理最多 64 个任务。任务管理包括创建任务、删除任务、改变任务的优 先级及挂起和恢复任务等。1、建立任务, OSTaskCreate ( ) 、OSTaskCreateExt ( )OSTaskCreate ( )需要四个参数: void (*task)(void *pd),void *pdata,OS_STK *ptos,INT8U prio 。 task 是指向任务函数的指针;pdata

29、是任务开始执行时,传递给任务的参数指针;ptos 是分配给任务的堆栈的栈顶指针;prio 是分配给任务的优先级。OSTaskCreateExt ( ) 是 OSTaskCreate ( )的扩展, 需要的参数比 OSTaskCreate ( )更多,共九个, 前 4 个和 OSTaskCreate ( ) 的参数一样。其余的参数是为了系统进行堆栈检验和任务统计等 扩展服务功能提供的参数。2、任务堆栈每个任务都有自己的堆栈空间,为 OS_STK 类型,并且由连续的内存空间组成。可以 静态分配堆栈空间,也可以动态分配。uC/OS-II 支持的处理器的堆栈既可以是递减的, 也可以是递增的。 在创建任

30、务时必须知 道堆栈是递减 还是递增的,因为 必须把堆栈的栈顶传递给 OSTaskCreate ( )和 OSTaskCreateExt ( ) 。可以在文件 OS_CPU.H 中的 OS_STK_GROWTH 进行堆栈方向的设置。3、删除任务, OSTaskDel()删除任务是指任务处于休眠状态,不再被 RTOS 调用。4、请求删除任务, OSTaskDelReq()为了避免删除任务时,任务占用 的资源因为没有被释放而丢失,可以调用OSTaskDelReq(),让拥有这些资源的任务使用完资源后,先释放资源,再删除自己。5、改变任务优先级, OSTaskChangePrio()调用 OSTask

31、ChangePrio(INT8U oldprio, INT8U newprio) 可以动态改变任务的优先级。6、挂起任务, OSTaskSuspend()调用 OSTaskSuspend(INT8U prio) 可以挂起一个任务,被挂起的任务只有通过调用OSTaskResume()函数来恢复。7、恢复任务, OSTaskResume()恢复因为调用 OSTaskSuspend(INT8U prio)挂起的任务。三、 uC/OS-II 任务间通信方式1 、 信号量信号量由两部分组成:一部分是 16 位的无符号整型信号量的计数值;另一部分是由等 待该信号量的任务组成的等待任务表;信号量用于对共享资

32、源的访问, 用钥匙符号, 符号旁数字代表可用资源数, 对于二值信 号量该值为 1;信号量还可用于表示某事件的发生, 用旗帜符号表示, 符号旁数字代表事件已经发生的 次数;提供服务:OSSemCreate(),建立一个信号量,对信号量赋予初始计数值。如信号量是用于表示一个或多个事件的发生的,其初始值通常为0;如信号量用于对共享资源的访问,则该值赋为1;如信号量用于表示允许任务访问n个相同的资源,则该值赋为 n,并把该信号量作为一个可计数的信号量使用;OSSemDel(),删除一个信号量,在删除信号量前必须首先删除操作该信号量的所有任务;OSSemPend(),等待一个信 号量;OSSemPost

33、(),发出一个信号量;OSSemAccept() ,无等待地请求一个信号量;OSSemQuery() ,查询一个信号量的当前状态; 不推荐任务和中断服务子程序共享信号量,因为信号量一般用于任务级。如果确实要在任务和中断服务子程序中传递信号量,则中断服务子程序只能发送信号量;OSSemDel()和OSSemPend()服务不能被中断服务子程序调用;2、 互斥型信号量( mutex)互斥型信号量用于处理共享资源;由于终端硬件平台的某些实现特性, 例如单片机管脚的复用, 多个任务需要对硬件资源 进行独占式访问。 所谓独占式访问, 指在任意时刻只能有一个任务访问和控制某个资源, 而 且必须等到该任务访

34、问完成后释放该资源,其他任务才能对此资源进行访问。操作系统进行任务切换时, 可能被切换的低优先级任务正在对某个共享资源进行独占式 访问, 而任务切换后运行的高优先级任务需要使用此共享资源,此时会出现优先级反转的问题。即, 高优先级的任务需要等待低优先级的任务继续运行直到释放该共享资源, 高优先级 的任务才可以获得共享资源继续运行。可以在应用程序中利用互斥型信号量(mutex )解决优先级反转问题。互斥型信号量是二值信号量。由于 uC/OS-II 不支持多任务处于同一优先级,可以把占有 mutex 的低优先级 任务的优先级提高到略高于等待 mutex 的高优先级任务的优先级。 等到低优先级任务使

35、用完 共享资源后,调用 OSMutexPost() ,将低优先级任务的优先级恢复到原来的水平。互斥型信号量( mutex )的操作:建立一个互斥型信号量OSMutexCreate (INT8U prio, INT8U *err)等待一个互斥型信号量(挂起)OSMutexPend (OS_EVENT * pevent, INT16U timeout, INT8U * err )释放一个互斥型信号量OSMutexPost (OS_EVENT * pevent)优先级反转问题。优先级反转问题发生于高优先级的任务需要使用某共享资源, 而该资源已被一个低优先 级的任务占用的情况。为了降解优先级反转, 内

36、核可以将低优先级任务的优先级提升到高于高优先级任务的优 先级,直到低优先级的任务使用完占用的共享资源。优先级继承优先级 PIP ,略高于最高优先级任务的优先级;例: OSMutexCreate(9,&err) ;建立互斥型信号量, 9 为 PIP ;其它服务:OSMutexDel (),删除互斥型信号量,在删除信号量之前应先删除可能用到该信号量的 所有任务;OSMutexPend (),等待一个互斥型信号量(挂起) ,定义超时值为 0 时则无限期等待;OSMutexPost (),释放一个互斥型信号量;OSMutexAccept (),无等待地获取互斥型信号量(不挂起) ;OSMutexQue

37、ry (),获取互斥型信号量的当前状态;所有服务只能用于任务与任务之间,不能用于任务与中断服务子程序之间;3、事件标志组 ( event flag)事件标志组由 2 部分组成:一是保存各事件状态的标志位;二是等待这些标志位置位或 清除的任务列表。可以用 8 位、 16 位或 32 位的序列表示事件标志组,每一位表示一个事件 的发生。要使系统支持事件标志组功能,需要在 OS_CFG.H 文件中打开 OS_FLAG_EN 选项。 应用场合 : 如果一个任务需要等待多个事件的同时发生或者多个事件的中的某个事件发生 才能转为就绪态,就可以考虑事件标志组进行任务的同步通信。操作集合:OSFIagCrea

38、te(),建立一个事件标志组;事件标志组数据结构包括: 指针类型, 等待事件标志组的任务列表, 以及表明当前事件 标志状态的位;OSFIagDeI(),删除一个事件标志组,在删除事件标志组前必须首先删除操作该事件标 志组的所有任务;OSFIagPend(),等待事件标志组的事件标志位;OSFIagPost(),置位或清0事件标志组中的事件标志;OSFIagAccept() ,无等待地获得事件标志组中的事件标志,可以被 ISR 调用; OSFIagQuery() ,查询事件标志组的状态;其中OSFIagCreate()、OSFIagDel()、OSFIagPend()只能被任务调用,不能被中断调

39、用;其它 服务任务和中断都可调用;4、消息邮箱一种通信机制, 可以使一个任务或者中断服务子程序向另一个任务发送一个指针型的变 量,通常该指针指向一个包含了消息的特定数据结构。提供的服务:OS_EVENT * OSMboxCreate(void * msg),建立一个邮箱, 并对邮箱须定义指针的初始 值。一般情况下该值为 NULL ,但也可以初始化一个邮箱,使其在最开始就包含一条消息。 如使用邮箱的目的是通知一个事件的发生(发送一个消息) ,则初始化该邮箱为空,即 nuII,因为在开始时很有可能事件没有发生;如用邮箱共享某些资源, 则要初始化该邮箱为一个非空的值, 此时邮箱被当做一个二值信号量使

40、用;OSMboxDel() ,删除一个邮箱,在删除邮箱前必须首先删除操作该邮箱的所有任务; OSMboxPend() ,等待邮箱中的消息;OSMboxPost() ,向邮箱发送一则消息;OSMboxPostOpt() ,向邮箱发送一则消息,增强功能,可以广播;OSMboxAccept() ,无等待地从邮箱得到一则消息;OSMboxQuery() ,查询一个邮箱的状态;其中: OSMboxDel() 、OSMboxPend() 、 OSMboxQuery() 只有任务可以调用,中断不能调 用;其它服务两者均可调用;邮箱的使用: 可使用的最大邮箱数由配置文件决定; 用邮箱作为二值信号量,可在其与信

41、号量之间选择其一; 用邮箱实现延时,可取代 OSTimeDly ()服务;5、消息队列另一种通信机制, 允许一个任务或者中断服务子程序向另一个任务发送以指针方式定义 的变量或其它任务, 因具体应用不同, 每个指针指向的包含了消息的数据结构的变量类型也 有所不同。提供服务:OSQCreate(),建立一个消息队列,并给它赋给两个参数:指向消息数组的指针和数组 的大小。OSQDel(),删除一个消息队列,在删除一个消息队列前必须首先删除所有可能用到这 个消息队列的任务;OSQPend(),等待消息队列中的消息,返回消息指针;OSQPost(),向消息队列发送一则消息(基于FIFO,先进先出);OS

42、QPostFront(),向消息队列发送一则消息(基于 LIFO,后进先出);OSQPostOpt(),向消息队列发送一则消息(FIFO或LIFO);OSQAccept() ,无等待地从消息队列获得消息;OSQFlush() ,清空消息队列,清空队列中的所有消息以重新使用;OSQQuery() ,查询消息队列的状态;其中:OSQDel()、OSQPend()、OSQQuery()只有任务可以调用,中断不能调用;其它服务两者均可调用;消息队列的使用:使用消息队列读取模拟量的值;消息队列用作计数型信号量;使用消息队列的方式消耗的是消息队列指针指向的数据类型的变量, 原来可以用信号量 来管理的每个共

43、享资源都需要占用一个队列控制块, 因此消息队列与信号量相比, 节省了代 码空间,而牺牲了 RAM 空间;此外,当用计数型信号量管理的共享资源很多时,消息队列的方式效率非常低;四、多任务系统中驱动程序的实现方法系统在运行多任务时, 由于任务切换的存在, 驱动程序库的实现与以前基于前后台系统 的实现方法有区别。 因为一个硬件驱动在对硬件接口进行操作时可能会发生任务切换, 正在 执行的硬件接口操作会被打断,而任务切换后运行的任务可能对同一个硬件接口进行操作, 从而破坏任务切换前的接口操作状态。 为了防止出现这种情况, 驱动程序必须考虑到对硬件 操作的原子性,即一个底层的操作序列完成前不能被另一个操作

44、打断。例如,由于 xRam 读写和 LCD 显示数据线的复用,向 LCD 显示一个字节数据的操作 ( lcd_draw_byte )不能被 xRam 读写操作 wr_abyte 和 rd_abyte 打断。同样,在向外部 RAM 读写一个字节数据时也不能被 LCD 显示操作打断。另外,两个调用 xRam 读写操作的任务 在进行 xRam 读写字节操作时也不能相互打断。在 uC/OS-II 中,保护一个原子操作的手段有:关闭中断、禁止任务切换和利用互斥信 号量。例如,在函数 void lcd_draw_byte(int ix,int iy,char data) 中使用互斥信号量保证此函数 执行完

45、成才能进行任务切换。例:在 xRam 读写函数中使用互斥信 号量/* 功能 :向外部 RAM 写一个字节,入口参数 : addr 外部 RAM 地址, data 写入的字节 */ void wr_abyte(UBYTE data,addr_t addr)INT8U err ;OSMutexPend (xRamMutex , 0,&err);/等待一个互斥信号量写 W24100 xram过程OSMutexPost (xRamMutex ,);/释放一个互斥信号量多任务系统中,不仅硬件复用的驱动程序之间需要互斥信号量保证操作的正确,而且相同的驱动被不同的任务调用时也会出现独占访问的问题。除了LCD

46、显示和xRam,系统中其他需要互斥信号量保护的驱动程序,包括EEPROM读写子程序(模拟IIC总线)、dataflash读写操作驱动(模拟 spi总线)。对于uart通讯驱动和rtc4553时钟芯片读写驱动可以考虑在一个任务中调用,因此不存 在互斥访问的问题。无论是不同驱动程序之间的硬件资源共享问题,还是同一个驱动被不同任务调用时的共享问题,都可以采用隐含的信号量才实现,即将信号量放在驱动内部。任务在与某一资源打交道的时候并不知道相应的驱动内有一个互斥信号量。任务在调用一个驱动函数时,实际在申请得到一个信号量。如下图所示:图5、用互斥信号量实现一个EEPROM驱动五、键盘驱动和 LCD显示的实

47、现LCD显示驱动作为功能子程序实现。LCD显示驱动程序必须考虑显示驱动对硬件资源进行操作时有可能进行任务切换,进行xRam读写而出现硬件访问错误。可以考虑利用互斥信号量将LCD显示驱动和xRam驱动程序实现为可重入函数。键盘处理程序作为任务来实现, 任务通常是一个无限的循环, 相当于一个线程, 当一个 任务运行时,该任务单独占用 CPU 资源,直到被其他高优先级的任务剥夺运行权利而转为 就绪态任务。键盘用两个任务来实现,一个是键盘扫描任务KeyboardScanTask,定时对按键状态进行 扫描,并将健值放到缓冲中; 另一个是 键盘处理任务 KeyboardProcTask,定期从键盘缓冲获

48、取健值, 并进行相应处理。 键盘处理任的执行周期比扫描任务长, 但是比扫描任务优先级高。键盘扫描任务是定时任务。以前的前后台系统实现时是将键盘扫描驱动keyProcess放到20ms定时器中断服务队列中。20ms定时器中断发生时,进行键盘处理keyProcess。KeyProcess 调用 scanfkey 函数, scanfkey 函数实现键盘按键状态的扫描, 并返回当前按键值。 KeyProcess 同时处理键盘抖动的因素, 采取的方法是连续两次 20ms 定时器任务时判断按键的值是否一 样,如果是, 则说明操作员在进行按键操作。 所以设置定时器的间隔时间不能太长, 否则键 盘需要按下很长

49、时间才能对其响应,键盘的响应就会很慢。将键盘keyProcess加入20ms定时器中断任务队列中的方法如下:void init_keyboard(void)insert_task(keyProcess);现在, 在多任务调度系统中为了提高系统的实时性, 应该尽量减少中断服务子程序的操 作内容,借鉴以前系统将键盘驱动加入 20ms 定时器中断任务队列的实现,我们可以采取两 种方法来实现 键盘扫描任务 。一个是采用操作系统的任务延迟, 一个是利用定时中断服务子 程序发送信号量。第一种方法的实现比较简单,也比较节省内存资源。但是由于操作系统的调度等原因, 延迟时间不够精确。第二种方法实现一个 20m

50、s 的定时中断服务子程序, 在中断服务子程序中发出一个信号 量(post)给键盘扫描任务。如果键盘扫描任务处于就绪状态,在得到信号量时,键盘驱动 就继续运行, 运行结束后挂起, 继续等待下一次信号量。 这种方法延时比较精确, 但实现复 杂些,消耗内存多些。键盘处理任务 的实现相对简单, 就是定时的从键盘缓冲读取按键值。 如果有按键值, 就 根据相应的值进行逻辑处理。键盘处理任务比键盘扫描任务的优先级高。原系统中的20ms定时任务有:1、键盘任务insert_task(keyProcess);2、LED 显示 insert_task(lmp_proc);3、延时和计数任务 unsigned ch

51、ar insert_timer(int *cnt)系统中的 5ms 定时任务有:1. 电表通讯任务 insert_ctask(cch_mt_ctask);2. 电台通信通讯任务 insert_ctask(cch_rd_ctask);六、交流采集中断和计算任务的通信交流采样模块采用中断驱动模式,分别用定时器 TA2 作为采样定时器,定时器 TB0 、 TB1、TB2 为三相测频定时器, 定时器 TA2 工作于定时方式 (用于采样) ,定时器 TB0 、TB1 、 TB2 工作于脉冲周期测量方式(用于 A、B、C 三相工频测频) 。采样周期是每 16 个电网频率周期,采集一个周期的数据,即隔15

52、个周期采一个周期。采集频率是一个周期内采 64 个点。由于电网频率是在一定范围内波动的,所以采样模块对 每个工频进行频率测量, 第 16 个周期(采样周期) 的工频是根据前 16 个周期的工频进行的 估算,以便确定出将要进行采样的时间间隔。估算公式如下:number_next = (nub_acc/16+ number)/2;number : 表示当前工频周期 f8 计数器的计数值。nub_acc : 表示前 16 个工频周期的 f8 计数器累计值。number_ next:估算的将要进行采样的工频周期的频率。交采表的精度也是整个测试项目主要考虑的问题。 为了满足表计精度要求, 交采表部分 的

53、交流采样要求实时性强,响应快,所以应该用中断服务子程序(ISR )来实现,并且将中断优先级设置为最高( 7 级)。交采表计算部分作为一个任务来实现,优先级主要实现电流 电压和电网频率的信号采集, 然后根据三相电表的计算公式进行有效电流、 电压、功率等数 据相的计算。整个系统中, 除了交流采样的实时性要求最高外, 为了能够达到 1 级电能表的要求, 交 采表的电表数据计算任务的优先级高于系统其他任务的优先级。因此设置交采计算任务的优先级为 0级(最高级)。这样可以满足 15个工频周期内将交流采样的 64 个电流、电压值计 算完成。交流采样中断服务子程序( ISR )与电表数据计算任务之间的同步

54、采用信号量的通信方法,交流采样 ISR 完成以后发出一个信号给等待的数据计算任务,21计算任务完成以后挂起,等待下一个交流采集信号量。表示信口 曰.号量表示消息流向#图6、用信号量使任务与中断服务同步七、多任务系统中任务划分原则和任务优先级设定任务划分的原则1、I/O依赖性:如果变换依赖于I/O ,那么它运行的速度常常受限于与它互操作的I/O设备的速度,这种情况下变换应成为一个独立的任务;在系统中创建多个与I/O设备相当数目的I/O任务;I/O任务只实现与设备相关的代码;I/O任务的执行只受限于I/O设备的速度,而不是处理器;在任务中分离设备相关性;如键盘显示任务、数据存储任务等;2、时间关键

55、性的功能:将有时间关键性(deadli ne)的功能分离出来,组成独立运行的任务;赋予这些任务高的优先级,以满足对时间的需要;如交采任务;3、计算功能;计算功能占用CPU的时间多;捆绑计算功能成任务, 赋予它们较低优先级运行,能被高优先级的任务抢占,消耗CPU的剩余时间;保持高优先级的任务是轻量级的(负荷较轻)如统计计算任务;4、功能内聚:各紧密相关的功能,不能分别对应不同的任务; 将这些紧密相关的功能组,组成一个任务,使各功能共享资源或相同事件的驱动; 组成一个任务会减小通信的开销, 而且不仅保证了模块级的功能内聚, 也保证了任务级 的功能内聚;如通信任务,将通信驱动和通信规约在一个任务中实

56、现;5、时间内聚:将在同一时间内完成的各功能, 即使这些功能是不相关的, 组成功能组, 形成一个任务; 功能组的各功能是由相同的外部时间驱动的(如时钟等) ,这样每次任务接收到一个事 件,它们都可以同时执行;组成一个任务,减小了系统的开销; 时间内聚在结构化设计中并不被认为是一个好的模块分解原则, 但在任务级是可以接受 的;每个功能都作为一个独立的模块来实现, 从而达到了模块级的功能内聚, 这些模块组合 在一起,又达到了任务级的时间内聚;6、周期执行的功能:将在相同周期内执行的各功能组成一个任务;频率高的赋予高优先级;优先级设定的约定uc/OS-II 中最高优先级为 0 级,数字越大优先级越低

57、。考虑到采用互斥信号量时优先级继承优先级的问题,便于系统灵活扩展,我们使用偶数作为任务优先级,如:0, 2, 4需要时,采用奇数作为优先级继承优先级。23八、uC/OS内核程序错误修改记录相关文件名:OS_MUTEX.C函数名:OS_EVENT *OSMutexCreate (INT8U prio, INT8U *err)改动原因:内核在创建互斥信号量的函数 OSMutexCreate中,由于数据类型不匹配产生了PIP参数不能保存的错误。在函数OSMutexCreate创建一个互斥信号量时,调用函数传递一个PIP作为函数实参(PIP是优先级继承优先级,其作用是利用互斥信号量解决多任务系统中可能

58、出现的优先级反转问题。即把占用共享资源的低优先级任务的优先级暂时提高到PIP,等其释放共享资源后再恢复到原来的优先级)。函数OSMutexCreate将实参prio保存到.OSEventCnt的高八位。由于prio是INT8U数据类型的变量,其长度是八位,prio左移八位后就等于 0。所以应该将prio强制转换为16位类型的数据,再左移8位,然后与0xFF相或”并保存到.OSEventCnt。F图表示 OSMutexCreate返回的事件控制块 ECB的数据结构。peventPIP的存储位置OS_EVENT_TYPE_MUTEXprio0xFF(void*)00x007654321031OS

59、EVENT.OSEventT ype .OSEventCnt .OSEventPtr .OSEventGrp .OSEventTbl图7、OSMutexCreate返回前的 OS EVENT 据结构内容改动前后的程序对比:改动前:OS_EVENT *OSMutexCreate (INT8U prio, INT8U *err)pevent-OSEventCnt = (prio OSEventPtr = (void *)0;改动后:OS_EVENT *OSMutexCreate (INT8U prio, INT8U *err)INT16U pip = (INT16U) prio;/强制类型转换pe

60、vent-OSEventCnt = (pip OSEventPtr = (void *)0;内核错误发现的经过和背景:我们在做可行性系统测试时, 利用互斥信号量来保证驱动程序对资源的独占访问 (参见 “四、多任务系统中驱动程序实现的问题和方法” )。测试系统在 main 函数中成功创建了一 个 MUTEX ,并传递了 PIP 为 3 的参数值。同时测试系统创建了一个优先级为 0 级的任务, 这个任务运行一次后就调用 OSTaskDel(OS_PRIO_SELF) 将自己删除。任务将自己删除以后 操作系统应该永远不会再调度该任务(参见uC/OSII 书籍),可是测试发现这个优先级为0 的任务继续运行。通过调试跟踪发现,调用 OSMutexCreate 函数创建 MUTEX 时,传递的 PIP 参数值(值为 3)没有被函数保存到 ECB 结构中,而是将 0保存到 ECB 中,从而使操 作系统认为创建 MUTEX 时传递了 PIP 为 0 的参数。这样,在后面调用 OSMutexPend 的函 数中将优先级为 0的任务又改变成就绪状态并得以继续运行,使uC/OS - II操作系统出现了调度错误。这个错误在 uC/OSII 后续的版本中做了修改。例如 V2.88 就没有这个问题。25

展开阅读全文
温馨提示:
1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
2: 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
3.本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
关于我们 - 网站声明 - 网站地图 - 资源地图 - 友情链接 - 网站客服 - 联系我们

copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!