uCOS简介

μC/OS-III(Micro C OS Three 微型的 C 语言编写的操作系统第三版)是由 Micrium 于 2009 年推出的一款可升级的、可固化的、开源的、基于优先级的抢占式实时内核。它提供了 高档实时内核所需要的所有功能,例如任务管理、时间管理、信号量、事件标志组、互斥信 号量、消息队列、软件定时器、内存管理等。μC/OS-III 对任务数量、任务大小、优先级数 量无限制,只限制于处理器所能提供的内存大小。μC/OS-III 也提供了很多其他实时内核中 所没有的,比如能在运行时测量运行性能,直接发送信号或消息给任务,任务能同时等待多 个信号量和消息队列。μC/OS-III 被设计用于 32 位处理器, 但是它也能在 16 位或 8 位 处理器中很好地工作。

μC/OS-III 是一个软件实时内核,主要负责任务的管理和任务间的交流,任务的管理也 叫做多任务处理,其作用是协调和切换多个任务依次享用 CPU,它能使 CPU 的利用率达到 最大,让我们从宏观上感觉是多个 CPU 在同时运行,但是在微观上,对于单核处理器,同 一时刻只能处理一个任务,即任务间是串行执行的。把系统功能分成多个在独自的循环体内 运行的小任务,可以实现模块化管理,程序员可以简单的维护和升级产品。

μ C/OS-III 是一款依据优先级的高低来执行任务,μ C/OS-III 支持多达 OS_CFG_PRIO_MAX 种不同的优先级,优先级越高的任务,其优先级数值越小,最小为零,优先级 OS_CFG_PRIO_MAX-1 的优先级最低,优先级高的任务可以抢断优先级低的任务, 这样就会出现优先级较低的任务可能无法及时的执行,因此μC/OS-III 是一款软件实时系统, 超时不会导致严重后果。

μC/OS-III 也是一个高级的前后台系统,微处理器的外设中断仍然作为前台系统,作用是实时响应外设的中断需求,提高系统的实时性,在中断服务子程序中不能执行过长的程序段,一般做简单的 I/O 操作、状态更改、μC/OS-III 服务标记等操作。长程序段应该放在后台系统执行,而后台系统则是多个任务,任务是一个个简单的程序段,任务的程序代码都在任务内部的无限循环中执行,任务是系统功能的主要实现方式,任务间通过有机的沟通, 最后积少成多,实现了系统功能

μC/OS-III 相当于给你的应用配上一个“管家婆”,让程序员不用再疲于底层的操作, 不再局限于传统单片机的前后台系统的操作习惯,而是让程序员站在巨人的肩膀上做顶层的软件设计。不过在增加了操作系统后,对硬件也是有要求的,系统中加入内核需要额外的支出,因为内核提供服务时需要时间去处理。内核占用 CPU 的时间介于 2% 到 4% 之间。 因为 μC/OS-III 是一个软件,添加到目标系统中需要额外的 ROM 和 RAM。μC/OS-III 内 核需要 1K 到 4K 之间的 RAM,加上每个任务自己所需的堆栈控件,至少有 4K 大小的 RAM 的处理器才可能成功移植μC/OS-III。

uC/OS时一个软实时系统,即任务没有被及时响应也不会出现致命的后果。

uCOS软件组成

状态转移方式

任务是操作系统创建的,其有优先级先后;外设中断依旧存在,且比任务的优先级高。

如上图所示,为包含μC/OS-III 在内的系统软件组成,里面包含μC/OS-III 的内部 实现代码,以及μC/OS-III 对上层应用程序和对下层硬件的接口。里面有三种文件格式:C 文件、H 文件、asm 汇编文件,其中 C 文件功能(函数、变量等)的定义文件,H 文件 是 C 文件对外的接口文件,asm 文件是与 CPU 相关寄存器操作

μC/OS-III 的内部文件分成了以下几类:

  • 用户应用代码文件 APP.c 和 APP.h 这是系统的顶层应用文件,里面包含 main()以及各任务的实现代码。
  • μC/OS-III 配置文件 OS_CFG.H、OS_CFG_APP.H 这里包含两个头文件,OS_CFG.h 包含了μC/OS-III 的功能配置文件,而 OS_CFG_APP.h 定义了μC/OS-III 所需的变量类型大小、数据结构、空闲任务堆栈的 大小、时钟速率、内存大小等。
  • 与 CPU 无关的文件 OS_CFG_APP.C 等 这些文件与 CPU 无关,在移植μC/OS-III 时一般不会被修改,但这些代码都是高度遵 循 ANSIC 标准。
  • μC/OS-III 库文件 LIB_ASCII.C、LIB_ASCII.H 等 这些文件提供了常用基本的功能如内存拷贝、字符串、ASCII 相关的函数。其中一些 可以替代编译器提供的 stdlib 功能,这些文件在应用于应用间,编译器与编译器间可 移植,μC/OS-III 不需要这些文件,但是μC/CPU 需要。
  • 与 CPU 相关的文件 OS_CPU.H、OS_CPU_A.ASM、OS_CPU_C.C 这些μC/OS-III 代码用于适应不同架构的 CPU,在名为 port 的文件夹中,μC/OS-III 源于μC/OS-II,μC/OS-II 能成功移植的,只要稍有改动便能移植μC/OS-III。
  • 板级支持包 BSP.C、BSP.H 在这里主要是对初始化目标板,包括微处理器的外设初始化,外围设备或模块初始 化,μC/OS-III 初始化等。
  • 微处理器提供的固件库 .C、.H 这里由于不同的微处理器厂商提供的库没有统一的规范,故以*.C 和*.H 来命名。

两种思维(裸机、操作系统)

对比表格

对比表格

uCOS-III 特点

μC/OS –III 的特点有很多,这里仅列出以下显著特点:

  • 源代码开放。这是区别于其他商业实时操作系统的一个优势,开源但不省质量,μC/OS –III 完全根据 ANSI-C 标准写的,代码的规范是 Micrium 团队的一种文化,通过阅读μ C/OS –III 的代码,你能通过函数名(或变量名)知道该函数(或变量)的作用,你也能 通过函数上方的注释语句了解函数中的参数要怎样选取。
  • 抢占式多任务处理。μC/OS –III 是一个抢占式多任务处理内核,因此,μC/OS –III 正 在运行的经常是最重要的就绪的任务。
  • 时间片轮转调度。μC/OS –III 允许多个任务拥有相同的优先级,当多个相同优先级的 任务就绪时,并且这个优先级时目前最高的,μC/OS –III 会分配用户定义的时间片给 每个任务去运行,每个任务可以定义不同的时间片,当任务用不完时间片时可以让出 CPU 给另一个任务。
  • 任务数、优先级数、内核对象数无限制。μC/OS –III 对任务数、优先级数量、内核对象 数都无限制,仅限制于处理器能提供的内存大小。
  • 提供的服务。μC/OS –III 提供了高档实时内核所需要的所有功能,例如任务管理、时 间管理、信号量、时间标志组、互斥信号量、消息队列、软件定时器、内存分区等。
  • 可定制。μC/OS –III 的内核对象(信号量,内部任务、互斥信号量、任务信号量、事件 标志组、消息队列等)可以根据需要选择开启或关闭,主要是在 OS_CFG.H 中的 40 个 #define 中修改。
  • 用户可定义钩子函数。μC/OS –III 允许程序员定义 hook 函数,hook 函数允许用户扩展 μC/OS –III 的功能,比如软件定时器在运行时会给用户提供一个函数接口,让用户自 由填充想要的功能,如控制闪灯、开关等。又如μC/OS -III 内部任务中有一个统计任务, 在统计到 CPU 总的使用率后,会调用一个 hook 函数 OSStatTaskHook(),在里面,用户 可以显示出 CPU 的总使用率。

基于μC/OS-III 的系统开发流程

基于μC/OS-III 的系统开发流程有如下几个步骤:

  1. 研究总结系统功能需求,并分解成若干个功能模块
  2. 把各个模块分解成单独的任务
  3. 根据任务的轻重缓急确定任务的优先级
  4. 各个任务内部实现
  5. 合理的上下文切换
  6. ISR(中断服务程序)与任务以及任务与任务间的通信与同步设计、临界资源的保护;

这里举一个日常生活小事,做卫生。假设我们要给自己的房间做一次大扫除,那么我们 会在做之前先对所要做的劳动进行划分,可以分为以下几个任务:

  • 任务一:扫地。
  • 任务二:拖地。
  • 任务三:擦窗户。
  • 任务四:洗衣服。

任务分配完后,哪个任务优先开始做呢?一般的思维就是哪件事情紧急重要就要优先做, 非紧急的事情可以适当的缓缓,放到后面做。如果同样的紧迫程度,哪件事执行的时间越少 (即任务越简单),就要优先做。在这里扫地和和拖地是有先后关系的,只有把地上的垃圾 清扫完毕,才可以拖地,故扫地要优先做;而洗衣服一般在做完所有劳动之后再把衣服换洗, 故洗衣服放到最后完成;扫地和擦窗户之间没有必然的联系,故处于同等的优先级。但事情 总有先做与后做,这里暂定扫地的优先级大于擦窗户的优先级。

于是完成任务的先后顺序依次是:扫地、擦窗户、拖地、洗衣服。

在脑中先规划好要做事的先后顺序后就可以开始劳动了。

其中,每个任务都会有独立的时间,即在一个时间段内就做本职工作,在另一个时间段内就做其他的工作,当然,如果中间有其他突发事件,比如手机响了,就要停下现在的工作, 接完电话后再返回来继续完成剩下的工作。就这样,我们有条不紊的把卫生做完。

不过μC/OS-III 和做卫生有一点不一样,就是各个任务通常是无限循环的执行的,而后者是一次性的。

这里先假设你已经搭建好了μC/OS-III 软硬件系统,并且已经有了“凌智 WinnerI 双 4 代核开发板”的 STM32 部分的裸机程序基础。

再进行μC/OS-III 开发时,有一个程序框架可供参考。如图 1.7.1 所示。

μC/OS-III 程序设计流程

不管是裸机程序还是μC/OS-III,程序的执行的入口点都是从 main 函数开始,先是调用 BSP_Init()初始化系统的各个外设,然后调用 OSInit()初始化μC/OS-III,并且建立一个起始 任务,这里命名为AppTastStart,在起始任务中会根据需要建立其他任务。最后再调用OSStart() 启动μC/OS-III。这样就把 CPU 的管理权交由μC/OS-III 内核控制,μC/OS-III 内核会根据 任务优先级的大小以及任务的就绪情况让 CPU 在各个任务间轮流执行,如果把时间放快, 就形成了我们看到的多任务是并行运行的假象。而用户就只需要把系统功能分解成若干个任 务,并且处理好任务与任务任务与中断间的通信或同步即可。

AppTastStart()中,首先会建立 5 个μC/OS-III 内部任务,然后可以根据需要建立μ C/OS-III 的若干个内核对象(消息队列、信号量、事件标志组、互斥信号量等),接下来再建 立其他若干个应用任务。最后可以根据需要选择在起始任务中执行某个任务实体,还是删除 起始任务。

注意,起始任务的优先级要设置的足够的高(但不能用 0,因为这是μC/OS-III 保留的, 是给中断处理用的),否则在建立其他任务时,就有可能被其他任务中断,导致无法预料的 后果,当然,在初始化时为了保证不被中断,可以使用开关中断来独占 CPU 的使用权。 在建立一个任务时需要定义一下几个变量:任务控制块 OS_TCB、任务堆栈数组 CPU_STK, 以及在 app_cfg.h 中定义 2 个宏定义:任务优先级、任务堆栈大小。每个任务一般都是在无 限循环中执行,任务间的调度就是通过μ C/OS-III 的延时函数 OSTimeDly() 、 OSTimeDlyHMSM()以及μC/OS-III 的各种服务(如同步、消息、信号量等)实现的。任务间或任务与中断间很经常都是需要通信与同步的,这样几个任务就能有机地组合成一个更大的功能。否则,任务间就只能是独立运行的个体。

本文由凌智电子提供文档进行的整理。