本章主要对 uC/OS-III 实时操作系统做一些概要介绍,使读者对 uC/OS-III 有个整体的浅
认识,为后面的章节的详细讲解做一个铺垫。
下图是 uC/OS-III 系统从底层到上层的文件结构。
①配置文件,通过定义这些文件里宏的值可以轻易地裁剪 uC/OS-III 的功能。
②用户应用文件, 定义和声明应用任务。
③内核服务文件,其代码与 CPU 无关,可以不做任何修改移植到任何 CPU。 本书主要讲解这部分内容。
④底层函数库,比如字符串的常规操作, 常用的数学计算, 等等。
⑤CPU 移植文件, 用户如果想要移植 uC/OS-III 到不同平台上,需要修改这部分代码。
⑥CPU 配置文件,主要是 CPU 的一些工作模式和服务函数。
⑦其他 CPU 相关文件。
uC/OS-III 数据结构
uC/OS-III 中的内核对象大多都是以结构体的形式存在的,例如出现最多的任务的任务控
制块的数据结构如下所示,结构体中的每个成员代表任务具有的一种属性。在结构体中,可
以看到很多宏,通过定义这些宏,就可以轻易地裁剪任务控制块具有的属性(任务的功能)。
不再一一列举。
在 uC/OS-III 中,对内核对象的管理大多采用线性链表的数据结构,包括单向链表和双
向链表。链表就是将要管理的对象按照方便管理的规则一个接一个串联在一起,提高管理效
率。
任务
在 uC/OS-III 中,可以创建无数多个任务, 让这些任务并发运行,就好像有多个主函数
在运行一样。 在 uC/OS-III 初始化的时候, 至少会创建空闲任务 OS_IdleTask()和时基任务
OS_TickTask()这两个任务, 另外还有三个可选择的内部任务,软件定时器任务
OS_TmrTaks() 、中断延迟提交任务 OS_IntQTask()和统计任务 OS_StatTask()。
从用户的角度来看, uC/OS-III 中的任务可以分为 5 种状态, 分别是休眠态、就绪态、
运行态、挂起态和中断态, 如下表所示。
从 uC/OS-III 任务管理的角度来看, uC/OS-III 中的任务 9 种状态, 如下表所示。 分别是
休眠态、就绪态、运行态、挂起态和中断态,如下表所示。
软件定时器
软件定时器的功能跟硬件定时器一样,主要用于定时,但其精度达不到硬件定时器的标
准,可以用于定时一些精度要求不是特别严格的事件。理论上, uC/OS-III 可以创建无数个
软件定时器,这是硬件定时器无法媲美的。
多值信号量
多值信号量主要用于管理资源和标志事件的发生。管理资源的一个常用仿例就是停车场,
把总停车位看做信号量,每次申请一个停车位信号量就减 1,如果停车位为 0,就申请不到,
但可以等待其它汽车释放停车位。 标志事件的发生类似于裸机里常用的事件标志变量,就是
标志某事是否发生,然后通知任务。
互斥信号量
互斥信号量的作用是保护共享资源,避免共享资源正在被重写时被其它任务读取,这样
读取到的数据就有错误。 互斥信号量的作用跟多值信号量的作用有些重叠,多值信号量的执
行时间少于互斥信号量,但多个任务访问共享资源时,容易出现优先级反转的问题,这会降
低系统的可预知性, 而互斥信号量可以防止优先级反转,所以建议在互斥信号量可以解决需
要时,就优先使用互斥信号量。
消息队列
消息队列是由多个消息串联而成的一个机制,需要消息的任务就从消息队列的出口端获
取,如果消息队列里没有消息了,可以选择等待或者不等待消息的到来。消息可以比信号量
携带更丰富的信息, 可以是任意长度的消息内容。
事件标志组
事件标志组用于标志若干个事件否发生的组合。这个功能可以轻易地实现键盘的按键组合。
任务信号量
任务信号量的作用与多值信号量的一样,但多值信号量是所有任务都可以申请使用,而
任务信号量却只能给一个特定任务使用,也就是说任务信号量是一个任务本身的属性,但其
他任务都可以给这个任务发送任务信号量。
任务消息队列
任务消息队列的作用与(普通)消息队列的一样,但(普通)消息队列是所有任务都可
以申请它的消息,而任务任务消息队列的消息却只能给一个特定任务使用,也就是说任务消
息队列是一个任务本身的属性,但其他任务都可以给这个任务发送任务消息。
内存管理(分区)
内存管理(分区)主要是为了尽量减少内存在不断分配和释放过程造成的内存碎片,避
免过多的浪费内存。 内存分区就是一次性开辟一大块连续内存,然后将内存分区平均分成若
干个内存块,需要使用内存时就申请一个内存块,用完了再释放回内存分区, 这样就实现内
存块的循环使用。
uC/OS-III 常用程序段
临界段
临界段主要是为了某段代码在执行时避免被其它任务或中断打断。临界段根据是否是使
能了中断延迟提交(OS_CFG_ISR_POST_DEFERRED_EN) 大体可以分为两种。当使能中断延迟提交时,中断级任务会转换成任务级任务,这种情况下进入和退出临界
段主要分别是锁调度器和解锁调度器。当禁用中断延迟提交时,进入和退出临界段的方式分
别是关中断和开中断。
OS_CRITICAL_ENTER()和 OS_CRITICAL_ENTER_CPU_EXIT() 为进入临界段,
OS_CRITICAL_EXIT() 和 OS_CRITICAL_EXIT_NO_SCHED() 为 退 出 临 界 段 ,
CPU_CRITICAL_ENTER()为关中断, CPU_CRITICAL_EXIT()为开中断。
为方便 uC/OS对中断的管理,在进入中断服务函数时需要调用 OSIntEnter() 函数将中断嵌套计数
OSIntNestingCtr 加 1,并且在退出中断服务函数时需要调用 OSIntExit() 函数将中断嵌套计
数 OSIntNestingCtr 减 1