uC_OS-II内核实验指导书
µC_OS-II实验指导书
1
.............................................. 5 1 实验系统的目的 ................................................................................................................................. 5 2 实验系统的构成 ................................................................................................................................. 5 3 操作系统简介 ..................................................................................................................................... 5
3.1 µC/OS-II概述 ........................................................................................................................... 5
3.2 µC/OS-II的特点 ....................................................................................................................... 6
3.3 µC/OS-II主要源代码文件介绍 ............................................................................................... 7
4 LambdaTOOL集成开发环境简介 ..................................................................................................... 7
5 µC/OS-II实验内容简介 ...................................................................................................................... 8
5.1 任务管理实验 .......................................................................................................................... 8
5.2 优先级反转实验 ...................................................................................................................... 8
5.3 优先级继承实验 ...................................................................................................................... 9
5.4 哲学家就餐实验 ...................................................................................................................... 9
5.5 内存管理实验 .......................................................................................................................... 9
5.6 时钟中断实验 .......................................................................................................................... 9
5.7 消息队列实验 .......................................................................................................................... 9
µC/OS-II .................................................... 10 1 ........................................................ 10 1 实验目的 ........................................................................................................................................... 10 2 实验原理及程序结构 ....................................................................................................................... 10
2.1 实验设计 ................................................................................................................................ 10
2.2 操作系统配置 ........................................................................................................................ 11
2.3 源程序说明 ............................................................................................................................ 13 3 运行及观察应用输出信息 ............................................................................................................... 15
4 本实验中所用到的µC/OS-II相关函数 .......................................................................................... 17
4.1 OSTaskCreate() .................................................................................................................. 17
4.2 OSTaskSuspend() ............................................................................................................... 17
4.3 OSTaskResume()................................................................................................................ 18
2 ................................................................ 19 1 实验目的 ........................................................................................................................................... 19 2 原理及程序结构 ............................................................................................................................... 19
2.1 实验设计 ................................................................................................................................ 19
2.2 操作系统配置 ........................................................................................................................ 21
2.3 源程序说明 ............................................................................................................................ 22 3 运行及观察应用输出信息 ............................................................................................................... 25
4 本实验中所用到的µC/OS-II相关函数 .......................................................................................... 25
4.1 OSSemCreate() .................................................................................................................. 25
4.2 OSSemPend() ..................................................................................................................... 26
2
4.3 OSemPost() ........................................................................................................................ 26
4.4 OSTimeDly() ...................................................................................................................... 27
3 .............................................................. 28 1 实验目的 ........................................................................................................................................... 28 2 原理及程序结构 ............................................................................................................................... 28
2.1 实验设计 ....................................................................................................................... 28
2.2 操作系统配置 ........................................................................................................................ 31
3 运行及观察应用输出信息 ............................................................................................................... 32
4 本实验中所用到的µC/OS-II相关函数 .......................................................................................... 33
4.1 OSMutexCreate() .................................................................................................................... 33
4.2 OSMutexPend() ....................................................................................................................... 33
4.3 OSMutexPost() ........................................................................................................................ 34 5 应用调试过程 ................................................................................................................................... 35 4 ............................. 37 1 实验目的 ........................................................................................................................................... 37 2 原理及程序结构 ............................................................................................................................... 37
2.1 实验设计 ................................................................................................................................ 37
2.2 操作系统配置 ........................................................................................................................ 38
3运行及观察应用输出信息 ................................................................................................................ 39
4 本实验中所用到的µC/OS-II相关函数 .......................................................................................... 41
5 µC/OS-II.............................................. 42 1 实验目的 ........................................................................................................................................... 42 2 原理及程序结构 ............................................................................................................................... 42
2.1实验设计 ................................................................................................................................. 42
2.2 操作系统配置 ........................................................................................................................ 48
3 本实验中所用到的µC/OS-II相关函数 .......................................................................................... 49
3.1 OSMemCreate() ................................................................................................................. 49
3.2 OSMemGet() ...................................................................................................................... 50
3.3 OSMemPut() ...................................................................................................................... 50
3.4 OSMemQuery() ................................................................................................................. 51
6 .................................................................... 52 1 实验目的 ........................................................................................................................................... 52 2 原理及程序结构 ............................................................................................................................... 52
2.1 实验设计 ................................................................................................................................ 52
2.2 操作系统配置 ........................................................................................................................ 54
3 运行及观察应用输出信息 ........................................................................................................... 56
4 本实验中所用到的µC/OS-II相关函数 .......................................................................................... 57
7 .................................................................... 58 1 实验目的 ........................................................................................................................................... 58
3
2 原理及程序结构 ............................................................................................................................... 58
2.1 实验设计 ................................................................................................................................ 58
2.2 源程序说明 ............................................................................................................................ 58
2.3 操作系统配置 ........................................................................................................................ 63
3 运行及观察应用输出信息 ............................................................................................................... 64
4 本实验中所用到的µC/OS-II相关函数 .......................................................................................... 68
4.1 OSQCreate()....................................................................................................................... 68
4.2 OSQPend() ......................................................................................................................... 68
4.3 OSQPostFront() ....................................................................................................................... 69
4.4 OSQPost() ............................................................................................................................... 69
4.5 OSQFlush () ............................................................................................................................ 70
4.6 OSQQuery() ............................................................................................................................ 70
4.7 OSQDel()................................................................................................................................. 71
4.8 OSTimeDlyHMSM() ............................................................................................................... 71
4
1
通过此实验系统,读者可以了解嵌入式实时操作系统µC_OS-II的内核机制和运行原理。本实
验系统展示了µCOS-II各方面的管理功能,包括信号量、队列、内存、时钟等。在各个实验中具体
介绍了µCOS-II的相关函数。读者在做实验的同时能够结合理论知识加以分析,了解各个函数的作
用和嵌入式应用程序的设计方法,最终对整个µCos和嵌入式操作系统的应用有较为清楚的认识。 2
本实验系统由以下各部分组成:
1. µCOS-II嵌入式实时操作系统。这个操作系统是开放源代码的;
2. LambdaTOOL。一个开发嵌入式软件的集成开发环境;
3. BSP。针对特定嵌入式硬件平台的板级支持包,提供板级初始化代码和一些基本的驱动程序; 4. 实验用例程序。基于特定的嵌入式操作系统(在本实验系统中是µCOS-II)的应用程序代码。 3
3.1 µC/OS-II
µC/OS-II是一个抢占式实时多任务内核。µC/OS-II是用ANSI的C语言编写的,包含一小部分
汇编语言代码,使之可以提供给不同架构的微处理器使用。至今,从8位到64位,µC/OS-II已经在40多种不同架构的微处理器上使用。世界上已经有数千人在各个领域中使用µC/OS,这些领域包括:照相机行业、航空业、医疗器械、网络设备、自动提款机以及工业机器人等。
µC/OS-II全部以源代码的方式提供给读者,大约有5500行。CPU相关的部分使用的是针对
Intel80x86微处理器的代码。虽然µC/OS-II可以在PC机上开发和测试,但是可以很容易地移植到
不同架构的嵌入式微处理器上。
5
3.2 µC/OS-II
1µC/OS-II全部以源代码的方式提供给使用者(约5500行)。该源码清晰易读,结构协调,且注解详尽,组织有序;
2portable µC/OS-II的源代码绝大部分是用移植性很强的ANSI C写的,与微处理器硬件相关的部分是用汇编语言写的。µC/OS-II可以移植到许许多多不同的微处理器上,条件是:
该微处理器具有堆栈指针,具有CPU内部寄存器入栈、出栈指令,使用的C编译器必须支持内嵌汇编,或者该C语言可扩展和可链接汇编模块,使得关中断和开中断能在C语言程序中实现;
3ROMable µC/OS-II是为嵌入式应用而设计的,意味着只要具备合适的系列软
件工具(C编译、汇编、链接以及下载/固化)就可以将µC/OS-II嵌入到产品中作为产品的一部分;
4scalable 可以只使用µC/OS-II中应用程序需要的系统服务。可裁减性是靠条件
编译实现的,只需要在用户的应用程序中定义那些µC/OS-II中的功能应用程序需要的部分就可以
了;
5preemptive µC/OS-II是完全可抢占型的实时内核,即µC/OS-II总是运行就绪条件下优先级最高的任务;
6 µC/OS-II可以管理64个任务。赋予每个任务的优先级必须是不相同的,这就是
说µC/OS-II不支持时间片轮转调度法(该调度法适用于调度优先级平等的任务);
7 绝大多数µC/OS-II的函数调用和服务的执行时间具有可确定性。也就是说用
户能知道µC/OS-II的函数调用与服务执行了多长时间。进而可以说,除了函数OSTimeTick()和某些事件
标志
禁止坐卧标志下载饮用水保护区标志下载桥隧标志图下载上坡路安全标志下载地理标志专用标志下载
服务,µC/OS-II系统服务的执行时间不依赖于用户应用程序任务数目的多少;
8 每个任务都有自己单独的栈。µC/OS-II允许每个任务有不同的栈空间,以便降低
应用程序对RAM的需求;
9 µC/OS-II提供许多系统服务,比如信号量、互斥信号量、事件标志、消息邮箱、
消息队列、时间管理等等;
10 中断可以使正在执行的任务暂时挂起。如果优先级更高的任务被该中断唤醒,
则高优先级的任务在中断嵌套全部退出后立即执行,中断嵌套层数可以达255层;
11 µC/OS-II的每一种功能、每一个函数以及每一行代码都经过了考验和
测试,具有足够的安全性与稳定性,能用于与人性命攸关、安全性条件极为苛刻的系统中。
6
3.3 µC/OS-II
µC/OS-II的源代码具体包括以下的文件:
PC.C
源文件PC.H包含了对函数和环境的一些定义。
OS_CORE.C OS_FLAG.C OS_MBOX.C OS_MEM.C OS_MUTEX.C
OS_Q.C OS_SEM.C OS_TASK.C OS_TIME.C µCOS-II.C
µCOS-II.H
这些文件是µC/OS-II中所有与处理器类型无关部分的源代码。
OS_CPU_A.S OS_CPU_C.C OS_CPU.H
这些文件是与处理器类型相关部分的源代码,在本实验系统中是面向80x86处
理器的。
INCLUDES.H
给整个内核库提供了总体的include文件。 OS_CFG..H
µC/OS-II的配置文件,定义使用µC/OS-II中的哪些功能。
4 LambdaTOOL
LambdaTOOL是一个通用、统一、开放的新一代32位嵌入式软件集成开发环境,支持多种嵌入式操作系统和32位嵌入式处理器,具备先进的新一代交叉开发环境和系统配置工具。本实验系统中
提供的LambdaTOOL是其面向教学的免费版本,具备支持嵌入式软件仿真开发的完整功能,具体由
下列内容组成:
, 编辑环境
, 系统配置
, 编译环境
, 目标机管理
, 调试环境
7
在本实验系统中,采用LambdaTOOL提供的一个PC虚拟机作为实验项目运行的仿真目标平台。
在LambdaTOOL上项目的开发流程如下图所示:
创建项目
编辑源码
配置项目
构建项目
调试应用
固化应用
有关开发流程的细节请看后面的“预备实验:嵌入式开发环境的建立”。 5 µC/OS-II
5.1
此实验的目的是让读者理解嵌入式操作系统中任务管理的基本原理,了解任务的各个基本状态
及其变迁过程;掌握µC/OS-II中任务管理的基本方法(创建、启动、挂起和解挂任务);熟练使用
µC/OS-II任务管理的基本系统调用。
5.2
通过此实验读者可以了解在基于抢占式嵌入式实时操作系统并有共享资源的应用中,出现优先
级反转现象的原理。优先级反转发生在有多个任务共享资源的情况下,高优先级任务被低优先级任
务阻塞,并等待低优先级任务执行的现象。
8
5.3
通过此实验读者可以了解嵌入式实时操作系统µC/OS-II解决优先级反转的策略——优先级继承的原理,以此解决低优先级任务在占用了共享资源的情况下,被高优先级任务抢占了CPU使用权而导致的优先级反转的问题。
5.4
通过经典的哲学家就餐应用,读者可以了解如何利用嵌入式实时操作系统µC/OS-II的信号量机制来对共享资源进行互斥访问。
5.5
通过此实验读者可以了解嵌入式实时操作系统µC/OS-II中的内存管理的原理,包括对内存的
分配和回收。
5.6
通过此实验读者可以了解嵌入式实时操作系统µC/OS-II中,时钟中断的使用情况。 5.7
通过此实验读者可以了解嵌入式实时操作系统µC/OS-II中的消息队列机制。读者可以了解一
个应用中的任务是如何进行通信的,如何能使它们相互协调工作。
9
µC/OS-II
1 1
, 理解任务管理的基本原理,了解任务的各个基本状态及其变迁过程;
, 掌握µC/OS-II中任务管理的基本方法(创建、启动、挂起、解挂任务);
, 熟练使用µC/OS-II任务管理的基本系统调用。
2
2.1
为了展现任务的各种基本状态及其变迁过程,本实验设计了Task0、Task1两个任务:任务Task0不断地挂起自己,再被任务Task1解挂,两个任务不断地切换执行。通过本实验,读者可以清晰地
了解到任务在各个时刻的状态以及状态变迁的原因。
起始
任务
Task0 Task0 Task0
Task1 Task1 Task1
t0 t1 t2 t3 t4 t5 t6 t7 t8
图1-1
图1
注意:图中的栅格并不代表严格的时间刻度,而仅仅表现各任务启动和执行的相对先后关系。 2.1.1
整个应用的运行流程如图1所示,其描述如下:
10
(1)系统经历一系列的初始化过程后进入boot_card()函数,在其中调用ucBsp_init()进行板级初始化后,调用main()函数;
(2)main()函数调用OSInit()函数对µC/OS-II内核进行初始化,调用OSTaskCreate创建起始任务TaskStart;
(3)main()函数调用函数OSStart()启动µC/OS-II内核的运行,开始多任务的调度,执行当
前优先级最高的就绪任务TaskStart;
(4)TaskStart完成如下工作:
a、安装时钟中断并初始化时钟,创建2个应用任务;
b、挂起自己(不再被其它任务唤醒),系统切换到当前优先级最高的就绪任务Task0。
之后整个系统的运行流程如下:
, t1时刻,Task0开始执行,它运行到t2时刻挂起自己;
, t2时刻,系统调度处于就绪状态的优先级最高任务Task1执行,它在t3时刻唤醒Task0,
后者由于优先级较高而抢占CPU;
, Task0执行到t4时刻又挂起自己,内核调度Task1执行;
, Task1运行至t5时刻再度唤醒Task0;
, ……
2.1.2 μC/OS-
一个任务通常是一个无限的循环 ,由于任务的执行是由操作系统内核调度的,因此任务是绝
不会返回的,其返回参数必须定义成void。在μC/OS-?中,当一个运行着的任务使一个比它优先级
高的任务进入了就绪态,当前任务的CPU使用权就会被抢占,高优先级任务会立刻得到CPU的控制权(在系统允许调度和任务切换的前提下)。μC/OS-?可以管理多达64个任务,但目前版本的μC/OS-?有两个任务已经被系统占用了(即空闲任务和统计任务)。必须给每个任务赋以不同的优
先级,任务的优先级号就是任务编号(ID),优先级可以从0到OS_LOWEST_PR10-2。优先级号越低,任务的优先级越高。μC/OS-?总是运行进入就绪态的优先级最高的任务。 2.2
操作系统配置的目的在于根据应用的需要,对操作系统的功能和规模进行设置,以便优化对系
统存储空间的使用。配置的方法为修改uC_OS-II源代码目录中的OS_CFG.h文件: #define OS_MAX_EVENTS 10 /*最多可以有10个事件*/
#define OS_MAX_FLAGS 5 /*最多可以有5个事件标志*/ #define OS_MAX_MEM_PART 5 /*最多可以划分5个内存块*/
11
#define OS_MAX_QS 2 /*最多可以使用2个队列*/ #define OS_MAX_TASKS 3 /*最多可以创建3个任务*/ #define OS_LOWEST_PRIO 14 /*任务优先级不可以大于14*/ #define OS_TASK_IDLE_STK_SIZE 1024 /*空闲任务堆栈大小*/ #define OS_TASK_STAT_EN 1 /*是否允许使用统计任务*/ #define OS_TASK_STAT_STK_SIZE 1024 /*统计任务堆栈大小*/
#define OS_FLAG_EN 0 /*是否允许使用事件标志功能*/ #define OS_FLAG_WAIT_CLR_EN 1 /*是否允许等待清除事件标志*/ #define OS_FLAG_ACCEPT_EN 1 /*是否允许使用OSFlagAccept()*/ #define OS_FLAG_DEL_EN 1 /*是否允许使用OSFlagDel()*/ #define OS_FLAG_QUERY_EN 1 /*是否允许使用OSFlagQuery()*/
#define OS_MBOX_EN 0 /*是否允许使用邮箱功能*/ #define OS_MBOX_ACCEPT_EN 1 /*是否允许使用 OSMboxAccept() */ #define OS_MBOX_DEL_EN 1 /*是否允许使用 OSMboxDel()*/ #define OS_MBOX_POST_EN 1 /*是否允许使用OSMboxPost()*/ #define OS_MBOX_POST_OPT_EN 1 /*是否允许使用OSMboxPostOpt() */ #define OS_MBOX_QUERY_EN 1 /*是否允许使用OSMboxQuery()*/
#define OS_MEM_EN 0 /*是否允许使用内存管理的功能*/ #define OS_MEM_QUERY_EN 1 /*是否允许使用OSMemQuery()*/
#define OS_MUTEX_EN 0 /*是否允许使用互斥信号量的功能*/ #define OS_MUTEX_ACCEPT_EN 1 /*是否允许使用OSMutexAccept()*/ #define OS_MUTEX_DEL_EN 1 /*是否允许使用OSMutexDel()*/ #define OS_MUTEX_QUERY_EN 1 /*是否允许使用OSMutexQuery()*/
#define OS_Q_EN 0 /*是否允许使用队列功能*/ #define OS_Q_ACCEPT_EN 1 /*是否允许使用OSQAccept()*/ #define OS_Q_DEL_EN 1 /*是否允许使用OSQDel()*/ #define OS_Q_FLUSH_EN 1 /*是否允许使用 OSQFlush()*/ #define OS_Q_POST_EN 1 /*是否允许使用 OSQPost()*/ #define OS_Q_POST_FRONT_EN 1 /*是否允许使用OSQPostFront()*/ #define OS_Q_POST_OPT_EN 1 /*是否允许使用OSQPostOpt()*/
12
#define OS_Q_QUERY_EN 1 /*是否允许使用OSQQuery()*/
#define OS_SEM_EN 0 /*是否允许使用信号量功能*/ #define OS_SEM_ACCEPT_EN 1 /*是否允许使用OSSemAccept()*/ #define OS_SEM_DEL_EN 1 /*是否允许使用 OSSemDel() */ #define OS_SEM_QUERY_EN 1 /*是否允许使用 OSSemQuery()*/
#define OS_TASK_CHANGE_PRIO_EN 0 /*是否允许使用 OSTaskChangePrio()*/ #define OS_TASK_CREATE_EN 1 /*是否允许使用OSTaskCreate()*/ #define OS_TASK_CREATE_EXT_EN 1 /*是否允许使用OSTaskCreateExt()*/ #define OS_TASK_DEL_EN 1 /*是否允许使用OSTaskDel()*/ #define OS_TASK_SUSPEND_EN 1 /*是否允许使用OSTaskSuspend() and OSTaskResume()*/
#define OS_TASK_QUERY_EN 1 /*是否允许使用OSTaskQuery()*/
#define OS_TIME_DLY_HMSM_EN 0 /*是否允许使用OSTimeDlyHMSM()*/ #define OS_TIME_DLY_RESUME_EN 1 /*是否允许使用OSTimeDlyResume()*/ #define OS_TIME_GET_SET_EN 1 /*是否允许使用OSTimeGet() 和 OSTimeSet()*/ #define OS_SCHED_LOCK_EN 1 /*是否允许使用OSSchedLock()和OSSchedUnlock()*/ #define OS_TICKS_PER_SEC 200 /*设置每秒之内的时钟节拍数目*/ 2.3
系统启动后,经历一系列的初始化过程,进入main()函数,这是我们编写实现应用程序的起点。
首先需要在main()函数里创建起始任务TaskStart:
OSTaskCreate(TaskStart, (void *)0, &TaskStartStk[TASK_STK_SIZE - 1], 4);
TaskStart
TaskStart任务负责安装操作系统的时钟中断服务例程、初始化操作系统时钟,并创建所有的应
用任务:
ucos_x86_idt_set_handler(0x20,(void *)OSTickISR,0x8e00);
/* Install uC/OS-II's clock tick ISR */
ucos_timer_init(); /*Timer 初始化*/
TaskStartCreateTasks(); /* Create all the application tasks */
OSTaskSuspend(OS_PRIO_SELF);
具体负责应用任务创建的TaskStartCreateTasks函数代码如下,它创建了两个应用任务Task0和Task1:
13
static void TaskStartCreateTasks (void)
{
INT8U i;
for (i = 0; i < N_TASKS; i++) { /* Create N_TASKS identical tasks */
TaskData[i] = i; /* Each task will display its own letter */
}
OSTaskCreate(Task0, (void *)&TaskData[i], &TaskStk[i][TASK_STK_SIZE - 1], 5);
OSTaskCreate(Task1, (void *)&TaskData[i], &TaskStk[1][TASK_STK_SIZE - 1], 6);
}
TaskStart任务完成上述操作后将自己挂起,操作系统将调度当前优先级最高的应用任务Task0运行。
应用任务Task0运行后将自己挂起,之后操作系统就会调度处于就绪状态的优先级最高的任务,具体代码如下:
void Task0 (void *pdata)
{
INT8U i;
INT8U err;
i=*(int *)pdata;
for (;;) {
…… /*此处为输出信息,显示任务运行的状态 */
err=OSTaskSuspend(5); /* suspend itself */
}
}
应用任务Task1运行后将Task0唤醒,使其进入到就绪队列中:
void Task1 (void *pdata)
{
INT8U i;
INT8U err;
i=*(int *)pdata;
for (;;) {
OSTimeDly(150);
…… /*此处为输出信息,显示任务运行的状态 */
14
OSTimeDly(150);
err=OSTaskResume(5); /* resume task0 */
}
}
3
按照本实验手册第一部分所描述的方法建立应用项目并完成构建,当我们在LambdaTOOL调
试器的控制下运行构建好的程序后,将看到在μC/OS-?内核的调度管理下,两个应用任务不断切换
执行的情形:
T
时刻的截图 1
15
T时刻的截图 2
T
时刻的截图 3
16
T时刻的截图 4
4 µC/OS-II
4.1 OSTaskCreate
建立一个新任务。任务的建立可以在多任务环境启动之前,也可以在正在运行的任务中建立。
中断处理程序中不能建立任务。一个任务可以为无限循环的结构。
INT8U OSTaskCreate(void (*task)(void *pd), void *pdata, OS_STK *ptos, INT8U prio);
task是指向任务代码首地址的指针。
Pdata指向一个数据结构,该结构用来在建立任务时向任务传递参数。
OSTaskCreate()的返回值为下述之一:
, OS_NO_ERR:函数调用成功。
, OS_PRIO_EXIST:具有该优先级的任务已经存在。
, OS_PRIO_INVALID:参数指定的优先级大于OS_LOWEST_PRIO。 , OS_NO_MORE_TCB:系统中没有OS_TCB可以分配给任务了。 4.2 OSTaskSuspend
无条件挂起一个任务。调用此函数的任务也可以传递参数OS_PRIO_SELF,挂起调用任务本
17
身。当前任务挂起后,只有其他任务才能唤醒被挂起的任务。任务挂起后,系统会重新进行任务调
度,运行下一个优先级最高的就绪任务。唤醒挂起任务需要调用函数OSTaskResume()。
任务的挂起是可以叠加到其他操作上的。例如,任务被挂起时正在进行延时操作,那么任务
的唤醒就需要两个条件:延时的结束以及其他任务的唤醒操作。又如,任务被挂起时正在等待信号
量,当任务从信号量的等待对列中清除后也不能立即运行,而必须等到被唤醒后。
INT8U OSTaskSuspend ( INT8U prio);
prio为指定要获取挂起的任务优先级,也可以指定参数OS_PRIO_SELF,挂起任务本身。此时,下一个优先级最高的就绪任务将运行。
OSTaskSuspend()的返回值为下述之一:
, OS_NO_ERR:函数调用成功。
, OS_TASK_ SUSPEND_IDLE:试图挂起μC/OS-II中的空闲任务(Idle task)。此为非法操作。 , OS_PRIO_INVALID:参数指定的优先级大于OS_LOWEST_PRIO或没有设定OS_PRIO_SELF
的值。
, OS_TASK_ SUSPEND _PRIO:要挂起的任务不存在。
4.3 OSTaskResume
唤醒一个用OSTaskSuspend()函数挂起的任务。OSTaskResume()也是唯一能“解挂”挂起任务的函数。
NT8U OSTaskResume ( INT8U prio);
prio指定要唤醒任务的优先级。
OSTaskResume ()的返回值为下述之一:
, OS_NO_ERR:函数调用成功。
, OS_TASK_RESUME_PRIO:要唤醒的任务不存在。
, OS_TASK_NOT_SUSPENDED:要唤醒的任务不在挂起状态。
, OS_PRIO_INVALID:参数指定的优先级大于或等于OS_LOWEST_PRIO。
18
2 1
掌握在基于优先级的可抢占嵌入式实时操作系统的应用中,出现优先级反转现象的原理。
2
2.1
2.1.1
在本实验中,要体现嵌入式实时内核的优先级抢占调度的策略,并显现由于共享资源的互斥
访问而出现的优先级反转现象。
优先级反转发生在有多个任务需要使用共享资源的情况下,可能会出现高优先级任务被低优
先级任务阻塞,并等待低优先级任务执行的现象。高优先级任务需要等待低优先级任务释放资源,
而低优先级任务又正在等待中等优先级任务,这种现象就被称为优先级反转。两个任务都试图访问
共享资源是出现优先级反转最通常的情况。为了保证一致性,这种访问应该是顺序进行的。如果高
优先级任务首先访问共享资源,则会保持共享资源访问的合适的任务优先级顺序;但如果是低优先
级任务首先获得共享资源的访问,然后高优先级任务请求对共享资源的访问,则高优先级任务被阻
塞,直到低优先级任务完成对共享资源的访问。
2.1.2
1)设计了3个应用任务TA0~TA2,其优先级逐渐降低,任务TA0的优先级最高。
2)除任务TA1外,其它应用任务都要使用同一种资源,该资源必须被互斥使用。为此,创建
一个二值信号量mutex来模拟该资源。虽然μC/OS-?在创建信号量时可以选择采用防止优先级反转的策略,但在本实验中我们不使用这种策略。
3)应用任务的执行情况如图2-1所示:
19
优先级
5 0 0 0 0
6
2 2 2 2 7
t1 t2 t3 t5 t6 t7 t8 t9 t10 t4 t11 t12 t13
2 0 任务2: 任务1: 任务0:
图2-1
注意:图中的栅格并不代表严格的时间刻度,而仅仅表现各个任务启动和执行的相对先后关
系。
2.1.3
1) 系统初始化,之后进入main函数;
2) 在main函数中,首先创建一个二值的信号量mutex;
3) 在main函数中创建TaskStart任务,由TaskStart任务创建所有的应用任务(TA0、TA1、TA2)。
优先级较高的任务TA0、TA1先延时若干个时钟节拍,以便低优先级任务TA2运行。 4) t1时刻,任务TA2运行并首先
申请
关于撤销行政处分的申请关于工程延期监理费的申请报告关于减免管理费的申请关于减租申请书的范文关于解除警告处分的申请
到信号量mutex;
5) t2时刻,任务TA1延时到期,任务TA1的优先级高于任务TA2的优先级,因此任务TA1
立刻抢占TA2执行,任务TA2由执行态转为就绪态;
6) t3时刻,任务TA0延时到期,任务TA0的优先级高于任务TA1的优先级,所以任务TA0
立刻抢占执行,任务TA1由执行态转为就绪态,任务TA0申请二值信号量mutex被阻赛; 7) t4时刻,任务TA1由就绪态转回为执行态;此时TA0在等待TA2保持的mutex , 而TA2
又因为优先级低于TA1被阻塞。如果TA1一直执行而TA2没有机会被调度的话,那么TA2
将一直等到TA1执行完后才能执行,而TA0更要等到TA2释放它所占有的信号量资源后才
能执行,这样就出现了优先级高的TA0任务等待优先级低的TA1任务的现象; 8) t5时刻,任务TA1挂起自己,而TA0又因为申请二值信号量mutex而处于阻塞状态,所以
任务TA2由就绪态转为执行态,任务TA2释放信号量mutex;
9) t6时刻,TA0获得信号量并立刻抢占执行,任务TA2由执行态转为就绪态;
20
10) t7时刻,任务TA0将自己延时一段时间,而TA1仍然处于挂起状态,TA2是当前最高优
先级的就绪任务,它又转为执行状态,任务TA2因申请二值信号量mutex而阻塞;
11) t8时刻,任务TA1延时到期转为执行态,任务TA1又因等待一个事件而阻塞;
12) t9时刻,任务TA0延时到,释放二值信号量mutex,mutex被TA2得到后,内核自动切换
任务;
13) t10时刻,在就绪队列中,TA0优先级最高,TA0执行,又因为任务TA0等待一事件而阻
塞;
14) t11时刻,任务TA1延时到期,立刻抢占执行,又由于任务TA1等待一事件而阻塞;;
15) t12时刻,任务TA2执行,保持信号量mutex;以后系统再次出现优先级反转现象;
16) 系统如此周而复始地运行……
2.2
uC_OS-II/OS_CFG.h
#define OS_MAX_EVENTS 10 /*最多可以有10个事件*/ #define OS_MAX_FLAGS 5 /*最多可以有5个事件标志*/ #define OS_MAX_MEM_PART 5 /*最多可以划分5个内存块*/ #define OS_MAX_QS 2 /*最多可以使用2个队列*/ #define OS_MAX_TASKS 9 /*最多可以创建9个任务*/ #define OS_LOWEST_PRIO 24 /*任务优先级不可以大于24*/ #define OS_TASK_IDLE_STK_SIZE 1024 /*空闲任务堆栈大小*/ #define OS_TASK_STAT_EN 1 /*是否允许使用统计任务*/ #define OS_TASK_STAT_STK_SIZE 1024 /*统计任务堆栈大小*/
#define OS_FLAG_EN 1 /*是否允许使用事件标志功能*/ #define OS_FLAG_WAIT_CLR_EN 1 /*是否允许等待清除事件标志*/ #define OS_FLAG_ACCEPT_EN 1 /*是否允许使用OSFlagAccept()*/
#define OS_FLAG_DEL_EN 1 /*是否允许使用OSFlagDel()*/
#define OS_FLAG_QUERY_EN 1 /*是否允许使用OSFlagQuery()*/
#define OS_MBOX_EN 0 /*是否允许使用邮箱功能*/
#define OS_MEM_EN 1 /*是否允许使用内存管理的功能*/ #define OS_MEM_QUERY_EN 1 /*是否允许使用OSMemQuery()*/
#define OS_MUTEX_EN 1 /*是否允许使用互斥信号量的功能*/
21
#define OS_MUTEX_ACCEPT_EN 1 /*是否允许使用OSMutexAccept()*/ #define OS_MUTEX_DEL_EN 1 /*是否允许使用OSMutexDel()*/ #define OS_MUTEX_QUERY_EN 1 /*是否允许使用OSMutexQuery()*/
#define OS_Q_EN 0 /*是否允许使用队列功能*/
#define OS_SEM_EN 1 /*是否允许使用信号量功能*/ #define OS_SEM_ACCEPT_EN 1 /*是否允许使用OSSemAccept()*/ #define OS_SEM_DEL_EN 1 /*是否允许使用 OSSemDel() */ #define OS_SEM_QUERY_EN 1 /*是否允许使用 OSSemQuery()*/
#define OS_TASK_CHANGE_PRIO_EN 1 /*是否允许使用 OSTaskChangePrio()*/ #define OS_TASK_CREATE_EN 1 /*是否允许使用OSTaskCreate()*/ #define OS_TASK_CREATE_EXT_EN 1 /*是否允许使用OSTaskCreateExt()*/ #define OS_TASK_DEL_EN 1 /*是否允许使用OSTaskDel()*/ #define OS_TASK_SUSPEND_EN 1 /*是否允许使用OSTaskSuspend() and OSTaskResume()*/
#define OS_TASK_QUERY_EN 1 /*是否允许使用OSTaskQuery()*/
#define OS_TIME_DLY_HMSM_EN 1 /*是否允许使用OSTimeDlyHMSM()*/ #define OS_TIME_DLY_RESUME_EN 1 /*是否允许使用OSTimeDlyResume()*/ #define OS_TIME_GET_SET_EN 1 /*是否允许使用OSTimeGet() 和 OSTimeSet()*/ #define OS_SCHED_LOCK_EN 1 /*是否允许使用OSSchedLock()和OSSchedUnlock()*/ #define OS_TICKS_PER_SEC 200 /*设置每秒之内的时钟节拍数目*/ 2.3
首先,在main()函数中创建一个二值信号量:
mutex=OSSemCreate(1);
然后,在main()函数中创建TaskStart任务。
TaskStart
在TaskStart任务中创建并启动所有的应用任务TA0, TA1,TA2。 static void TaskStartCreateTasks (void)
{
INT8U i;
for (i = 0; i
决定
郑伟家庭教育讲座全集个人独资股东决定成立安全领导小组关于成立临时党支部关于注销分公司决定
当前运行的任务是否仍然为最高优先级的就绪任务。
:INT8U OSSemPost(OS_EVENT *pevent);
26
pevent 是指向信号量的指针。该指针的值在建立该信号量时可以得到。(参考
OSSemCreate()函数)。
OSSemPost()函数的返回值为下述之一:
, OS_NO_ERR :信号量被成功地设置
, OS_SEM_OVF :信号量的值溢出
, OS_ERR_EVENT_TYPE :pevent 不是指向信号量的指针 4.4 OSTimeDly
该函数用于将一个任务延时若干个时钟节拍。如果延时时间大于0,系统将立即进行任务调度。延时时间的长度可从0到65535个时钟节拍。延时时间0表示不进行延时,函数将立即返回调用者。延时的具体时间依赖于系统每秒钟有多少个时钟节拍(由文件SO_CFG.H中的OS_TICKS_PER_SEC宏来设定)。
void OSTimeDly ( INT16U ticks);
ticks为要延时的时钟节拍数。
无
27
3
1
掌握嵌入式实时操作系统µC/OS-II解决优先级反转的策略——优先级继承的原理。 2
2.1
2.1.1
优先级继承的主要思想是:当高优先级任务因申请某共享资源失败被阻塞时,把当前拥有该
资源的、且优先级较低的任务的优先级提升,提升的高度等于这个高优先级任务的优先级。在
µC/OS-II中,在创建管理共享资源的互斥信号量时,可以指定一个PIP(优先级继承优先级),之后
可以把拥有共享资源的任务优先级提升到这个高度。具体过程如下:
1. 当任务A申请共享资源S时,首先判断是否有别的任务正在占用资源S,若无,则任务A
获得资源S并继续执行;
2. 如果任务A申请共享资源S时任务B正在使用该资源,则任务A被挂起,等待任务B释
放该资源;同时判断任务B的优先级是否低于任务A的,若高于任务A,则维持任务B
的优先级不变;
3. 如果任务B的优先级低于任务A的,则提升任务B的优先级到PIP,当任务B释放资源后,
再恢复其原来的优先级。
2.1.2
在本实验中设计了处于不同优先级的应用任务,如下图所示:
28
优先级
8 0
2 2 2 2 2 2 2 2 10
11
0 0 12
t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14
0 2 任务TASK0: 任务TASK1: 任务TASK2 :
图3-1
注意:图中的栅格并不代表严格的时间刻度,而仅仅表现各个任务启动和执行的相对先后关系。
这3个应用任务因为要竞争同一互斥资源mutex而相互制约。其中,任务TASK0的原始优先级最低,任务TASK1的原始优先级中等,任务TASK2的原始优先级最高。在使用mutex时采用优先级继承策略,并指定各任务在使用mutex时的PIP(优先级继承优先级)为8。
2.1.3
TaskStart任务首先运行,由它创建其他3个应用任务:
void TaskStartCreateTasks (void)
{
INT8U i;
for (i = 0; i OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE){}
pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8; /*Yes, Acquire the resource */
pevent->OSEventCnt |= OSTCBCur->OSTCBPrio; /* Save priority of owning task */
pevent->OSEventPtr = (void *)OSTCBCur; /* Point to owning task's OS_TCB */
pip = (INT8U)(pevent->OSEventCnt >> 8); /* No, Get PIP from mutex */
mprio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8); /* Get priority
of mutex owner */
33
ptcb = (OS_TCB *)(pevent->OSEventPtr); /* Point to TCB of mutex owner */
if (ptcb->OSTCBPrio != pip && mprio > OSTCBCur->OSTCBPrio) { /* Need to promote prio of owner?*/
ptcb->OSTCBPrio = pip; /* Change owner task prio to PIP */
ptcb->OSTCBY = ptcb->OSTCBPrio >> 3;
ptcb->OSTCBBitY = OSMapTbl[ptcb->OSTCBY];
ptcb->OSTCBX = ptcb->OSTCBPrio & 0x07;
ptcb->OSTCBBitX = OSMapTbl[ptcb->OSTCBX];
if (rdy == TRUE) { /* If task was ready at owner's priority ...*/
OSRdyGrp |= ptcb->OSTCBBitY; /* ... make it ready at new priority. */
OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
}
OSTCBPrioTbl[pip] = (OS_TCB *)ptcb;
}
PIP
4.3 OSMutexPost()
该函数用于释放互斥信号量,具体代码说明如下:
if (OSTCBCur->OSTCBPrio == pip) { /* Did we have to raise current task's priority? */
if ((OSRdyTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0) {
OSRdyGrp &= ~OSTCBCur->OSTCBBitY;
}
OSTCBCur->OSTCBPrio = prio;
OSTCBCur->OSTCBY = prio >> 3;
OSTCBCur->OSTCBBitY = OSMapTbl[OSTCBCur->OSTCBY];
OSTCBCur->OSTCBX = prio & 0x07;
OSTCBCur->OSTCBBitX = OSMapTbl[OSTCBCur->OSTCBX];
OSRdyGrp |= OSTCBCur->OSTCBBitY;
OSRdyTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX;
OSTCBPrioTbl[prio] = (OS_TCB *)OSTCBCur;
}
OSTCBPrioTbl[pip] = (OS_TCB *)1; /* Reserve table entry */
34
5
在LambdaTOOL的调试界面中,在“优先级继承.c”文件中Task任务代码调用函数OSMutexPend()和OSMutexPost()处设置断点。
当程序运行至断点处时,选择“单步跳入”运行模式,可以进入到OS_MUTEX.c文件中,查看OSMutexPend()和OSMutexPost()函数的运行过程,深入了解µC/OS-II操作系统的内核代码。
35
36
4
1
掌握在基于嵌入式实时操作系统µC/OS-II的应用中,任务使用信号量的一般原理。通过经典的哲学家就餐实验,了解如何利用信号量来对共享资源进行互斥访问。 2
2.1
五个哲学家任务(ph1、ph2、ph3、ph4、ph5)主要有两种过程:思考(即睡眠一段时间)和就餐。每个哲学家任务在就餐前必须申请并获得一左一右两支筷子,就餐完毕后释放这两支筷子。五
个哲学家围成一圈,每两人之间有一支筷子。一共有五支筷子,在该实验中用了五个互斥信号量来
代表。如图4-1所示:
图4-1 每个任务的代码都一样,如下所示:
INT8U err;
INT8U i;
INT8U j;
i=*(int *)pdata;
j=(i+1) % 5;
for (;;) {
37
TASK_Thinking_To_Hungry(i); /*首先哲学家处于thinking状态,然后执行TASK_Thinking_To_Hungry()函数进入hungry状态*/
printk("\n");
/*申请信号量,在获得两个信号量后执行TASK_Eat()函数进入eating状态*/
OSSemPend(fork[i], 0, &err);
OSSemPend(fork[j], 0, &err); /* Acquire semaphores to eat */
TASK_Eat(i);
printk("\n");
/*释放信号量*/
OSSemPost(fork[j]);
OSSemPost(fork[i]); /* Release semaphore */
OSTimeDly(200); /* Delay 200 clock tick */
}
2.2
uC_OS-II/OS_CFG.h
#define OS_MAX_EVENTS 10 /*最多可以有10个事件*/ #define OS_MAX_FLAGS 5 /*最多可以有5个事件标志*/ #define OS_MAX_MEM_PART 5 /*最多可以划分5个内存块*/ #define OS_MAX_QS 2 /*最多可以使用2个队列*/ #define OS_MAX_TASKS 8 /*最多可以创建8个任务*/ #define OS_LOWEST_PRIO 14 /*任务优先级不可以大于14*/ #define OS_TASK_IDLE_STK_SIZE 1024 /*空闲任务堆栈大小*/ #define OS_TASK_STAT_EN 1 /*是否允许使用统计任务*/ #define OS_TASK_STAT_STK_SIZE 1024 /*统计任务堆栈大小*/
#define OS_FLAG_EN 1 /*是否允许使用事件标志功能*/ #define OS_FLAG_WAIT_CLR_EN 1 /*是否允许等待清除事件标志*/ #define OS_FLAG_ACCEPT_EN 1 /*是否允许使用OSFlagAccept()*/ #define OS_FLAG_DEL_EN 1 /*是否允许使用OSFlagDel()*/ #define OS_FLAG_QUERY_EN 1 /*是否允许使用OSFlagQuery()*/
#define OS_MBOX_EN 0 /*是否允许使用邮箱功能*/
#define OS_MEM_EN 0 /*是否允许使用内存管理的功能*/
38
#define OS_MUTEX_EN 0 /*是否允许使用互斥信号量的功能*/
#define OS_Q_EN 0 /*是否允许使用队列功能*/
#define OS_SEM_EN 1 /*是否允许使用信号量功能*/ #define OS_SEM_ACCEPT_EN 1 /*是否允许使用OSSemAccept()*/ #define OS_SEM_DEL_EN 1 /*是否允许使用 OSSemDel() */ #define OS_SEM_QUERY_EN 1 /*是否允许使用 OSSemQuery()*/
#define OS_TASK_CHANGE_PRIO_EN 1 /*是否允许使用 OSTaskChangePrio()*/ #define OS_TASK_CREATE_EN 1 /*是否允许使用OSTaskCreate()*/ #define OS_TASK_CREATE_EXT_EN 1 /*是否允许使用OSTaskCreateExt()*/ #define OS_TASK_DEL_EN 1 /*是否允许使用OSTaskDel()*/ #define OS_TASK_SUSPEND_EN 1 /*是否允许使用OSTaskSuspend() and OSTaskResume()*/
#define OS_TASK_QUERY_EN 1 /*是否允许使用OSTaskQuery()*/
#define OS_TIME_DLY_HMSM_EN 1 /*是否允许使用OSTimeDlyHMSM()*/ #define OS_TIME_DLY_RESUME_EN 1 /*是否允许使用OSTimeDlyResume()*/ #define OS_TIME_GET_SET_EN 1 /*是否允许使用OSTimeGet() 和 OSTimeSet()*/ #define OS_SCHED_LOCK_EN 1 /*是否允许使用OSSchedLock()和OSSchedUnlock()*/ #define OS_TICKS_PER_SEC 200 /*设置每秒之内的时钟节拍数目*/ 3
开始,所有的哲学家先处于thinking状态,然后都进入hungry状态:
39
之后首先获得两个信号量的1、3号哲学家开始eating,待他们释放相关信号量之后,哲学家2、5、
4获得所需的信号量并eating:
应用如此这般地循环执行程序下去……
40
4 µC/OS-II
OSSemCreate()
OSSemPend()
OSSemPost()
OSTimeDly()
函数的具体介绍请参考实验“优先级继承”的相关内容。
41
5 µC/OS-II 1
掌握嵌入式实时操作系统µC/OS-II内存管理中内存分配和回收的功能。 2
2.1
2.1.1
在该实验中,需要用到µC/OS-II内存管理中内存分配和回收的功能。为此,设计了如下图所示
的应用:
试图申请内试图申请内存
存块3,失败。 内存块 块3,失败。
3
2
1
t11 t12 t6 t7 t8 t9 t10 时间 t1 t2 t3 t4 t5
未分配: 已分配:
图5-1
注意:根据程序中设定的时间延迟,图5-1中的每个栅格对应100个系统时钟周期。为了防止内存申请和释放的不合理导致的大块连续内存被分割成可用性小的小片的问题,µCos-II将用于动态内存分配的空间分成一些固定大小的内存块,根据应用申请的内存大小,分配适当数量的内存块。
图5-1的纵坐标就代表内存块。
42
2.1.2
在main()函数中,使用µCos-II的OSMemCreate()函数创建一个用于动态内存分配的区域。
通过传递适当的调用参数,我们在该区域中划分了2个128B的内存块。如果成功创建这些内存块,
µCos-II会在内部建立并维护一个单向链表。
static void MemoryCreate()
{
INT8U err; //为OSMemCreate函数设置包含错误码的变量的指针。
CommMem = OSMemCreate(&CommBuf[0][0], 2, 128, &err); //OSMemCreate()
函数建立并初始化一块内存区。2块,每块128字节。
}
以下就是刚刚初始化的内存区域的情况(为了表示方便,竖线右边表示已分配的内存块,竖线
左边表示未被分配的内存块,下同):
2 1
此时在虚拟机中可以观察到以下的情况:
应用任务使用函数OSMemGet(CommMem,&err)来申请内存块,根据当前内存区域的情况来判
断分配的结果:
if(i==0)
{
CommMsg1=OSMemGet(CommMem,&err); //申请内存区中的一块。
if (err == OS_NO_ERR)
{
printk("First memory application HAS accept.\n");
/* 内存块已经分配 */
}
else
{
printk("First memory alpplication NOT accept.\/n");
43
}
MemInfo(pdata); //得到内存区的信息。
DispShow(); //将内存区信息显示到屏幕上。
OSTimeDly(100); /* Wait 100tick */
i++;
}
申请过后,内存区域在t2时刻的状态如下:
2 1
也就是说,内存块1已经被分配出去了,它的首地址储存在OSMemGet()函数的返回参数中。
我们需要用一个变量(CommMsg1)
记录
混凝土 养护记录下载土方回填监理旁站记录免费下载集备记录下载集备记录下载集备记录下载
这个返回值,以便在使用完这个内存块之后能正确地释放
它。
在虚拟机中观察到的结果如下:
在t3时刻,内存块2也被分配了出去:
else if(i==1)
{
CommMsg2=OSMemGet(CommMem,&err); //申请内存区中的一块。
if (err == OS_NO_ERR)
{
printk("Second memory application HAS accept.\n");
/* 内存块已经分配 */
}
else
{
printk("Second memory alpplication NOT accept.\n");
}
2 1
44
在虚拟机中看到的结果:
接下来在t4时刻,应用试图申请内存块3,但此时系统因为没有足够的内存块可以分配,所以失败:
CommMsg3=OSMemGet(CommMem,&err);
if (err == OS_NO_ERR)
{
printk("Third memory application HAS accept.\n");
/* 内存块已经分配 */
}
else
{
printk("Third memory alpplication NOT accept.\n");
} 试图申请内 存块3,失败。
2 1
在虚拟机中看到的运行结果:
在t5、t6和t7时刻,应用相继将内存块3、2、1归还给系统,但是由于之前申请内存块3的操
作是失败的,所以其归还操作是无效的:
for(i=3;i>0;i--)
45
{
ReleaseMem(i); //释放第i个内存块。
MemInfo(pdata); //函数得到内存区的信息
DispShow(); //将内存区信息显示到屏幕上。
OSTimeDly(10); //延迟10个时钟周期
}
释放内存块的函数代码如下:
void ReleaseMem(int i)
{
INT8U err;
switch(i)
{
case 3:OSMemPut(CommMem,CommMsg3);
if (err == OS_NO_ERR)
{
printk("Third memory has been released.\n");
/* 释放内存块 */
}
else
{
printk("Third memory didn't been releasd.\n");
}
break;
case 2:OSMemPut(CommMem,CommMsg2);
if (err == OS_NO_ERR)
{
printk("Second memory has been released.\n");
/* 释放内存块 */
}
else
{
printk("Second memory didn't been releasd.\n");
}
break;
case 1:OSMemPut(CommMem,CommMsg1);
if (err == OS_NO_ERR)
{
printk("First memory has been released.\n");
/* 释放内存块 */
}
else
46
{
printk("First memory didn't been releasd.\n");
}
break;
}
}
过程如下: 试图归还内 存块3,无效。
2 1
2 1
2 1
在虚拟机中看到的运行结果:
这里应该注意,µCos-II的内存块归还函数是:OSMemPut(CommMem,CommMsg3); 它的返回值只有两种:OS_NO_ERR :成功归还内存块
OS_MEM_FULL :内存区已满,不能再接受更多释放的内存块。出现这种
情况说明用户程序出现了错误,归还了多于用OSMemGet()函数得到的内
存块。
如果先归还内存块1,后归还内存块2,则是如下情况:
1 2
47
虽然内存块的地址并没有变化,但是链表的结构发生了变化。也就是说,如果进行多次内存分
配和归还的话,那么最终的链表和初始化时的链表会完全不同。
另外,在这个应用中使用了两个函数:
MemInfo(pdata); //函数得到内存区的信息
DispShow(); //将内存区信息显示到屏幕上。
它们的代码如下:
static void DispShow()
{
INT8U err;
INT8U s[4][50];
OS_MEM_DATA mem_data;
OSMemQuery(CommMem, &mem_data);
printk( "the pointer to the begining of memory address is: %d\n",(int)(mem_data.OSAddr));
printk( "the size of blocks in this memory area is: %d\n",(int)(mem_data.OSBlkSize));
printk( "the number of free blocks in this memory area is: %d\n", (int)(mem_data.OSNFree));
printk( "the number of using blocks in this memory area is: %d\n", (int)mem_data.OSNUsed);
printk("\n\n\n");
OSTimeDlyHMSM(0,0,8,0);
}
void MemInfo(void *pdata) //内存空间信息。
{
INT8U err; //为函数设置包含错误码的变量指针。
pdata = pdata;
OS_MEM_DATA mem_data;
err = OSMemQuery(CommMem, &mem_data);
//OSMemQuery()函数得到内存区的信息。
}
2.2
uC_OS-II/OS_CFG.h:
#define OS_MAX_EVENTS 10 /*最多可以有10个事件*/ #define OS_MAX_FLAGS 5 /*最多可以有5个事件标志*/ #define OS_MAX_MEM_PART 5 /*最多可以划分5个内存块*/ #define OS_MAX_QS 2 /*最多可以使用2个队列*/ #define OS_MAX_TASKS 9 /*最多可以创建9个任务*/ #define OS_LOWEST_PRIO 24 /*任务优先级不可以大于24*/ #define OS_TASK_IDLE_STK_SIZE 1024 /*空闲任务堆栈大小*/
48
#define OS_TASK_STAT_EN 1 /*是否允许使用统计任务*/ #define OS_TASK_STAT_STK_SIZE 1024 /*统计任务堆栈大小*/
#define OS_FLAG_EN 0 /*是否允许使用事件标志功能*/
#define OS_MBOX_EN 0 /*是否允许使用邮箱功能*/
#define OS_MEM_EN 1 /*是否允许使用内存管理的功能*/ #define OS_MEM_QUERY_EN 1 /*是否允许使用OSMemQuery()*/
#define OS_MUTEX_EN 1 /*是否允许使用互斥信号量的功能*/
#define OS_Q_EN 0 /*是否允许使用队列功能*/
#define OS_SEM_EN 0 /*是否允许使用信号量功能*/
#define OS_TASK_CHANGE_PRIO_EN 0 /*是否允许使用 OSTaskChangePrio()*/ #define OS_TASK_CREATE_EN 1 /*是否允许使用OSTaskCreate()*/ #define OS_TASK_CREATE_EXT_EN 1 /*是否允许使用OSTaskCreateExt()*/ #define OS_TASK_DEL_EN 1 /*是否允许使用OSTaskDel()*/ #define OS_TASK_SUSPEND_EN 1 /*是否允许使用OSTaskSuspend() and OSTaskResume()*/
#define OS_TASK_QUERY_EN 1 /*是否允许使用OSTaskQuery()*/
#define OS_TIME_DLY_HMSM_EN 1 /*是否允许使用OSTimeDlyHMSM()*/ #define OS_TIME_DLY_RESUME_EN 1 /*是否允许使用OSTimeDlyResume()*/ #define OS_TIME_GET_SET_EN 1 /*是否允许使用OSTimeGet() 和 OSTimeSet()*/ #define OS_SCHED_LOCK_EN 1 /*是否允许使用OSSchedLock()和OSSchedUnlock()*/ #define OS_TICKS_PER_SEC 200 /*设置每秒之内的时钟节拍数目*/ 3 µC/OS-II
本实验涉及到µC/OS-II的4个相关内存管理的函数:
3.1 OSMemCreate
该函数建立并初始化一个用于动态内存分配的区域,该内存区域包含指定数目的、大小确定
49
的内存块。应用可以动态申请这些内存块并在用完后将其释放回这个内存区域。该函数的返回值就
是指向这个内存区域控制块的指针,并作为OSMemGet(),OSMemPut(),OSMemQuery()等相关调用的参数。
OSMemCreate( void *addr, INT32U nblks ,INT32U blksize, INT8U *err);
addr 建立的内存区域的起始地址。可以使用静态数组或在系统初始化时使用malloc()函数来分配这个区域的空间。
Nblks 内存块的数目。每一个内存区域最少需要定义两个内存块。
Blksize 每个内存块的大小,最小应该能够容纳一个指针变量。
Err 是指向包含错误码的变量的指针。Err可能是如下几种情况:
, OS_NO_ERR :成功建立内存区域。
, OS_MEM_INVALID_ADDR:非法地址,即地址为空指针。
, OS_MEM_INVALID_PART :没有空闲的内存区域。
, OS_MEM_INVALID_BLKS :没有为内存区域建立至少两个内存块。
, OS_MEM_INVALID_SIZE :内存块大小不足以容纳一个指针变量。
OSMemCreate()函数返回指向所创建的内存区域控制块的指针。如果创建失败,
函数返回空指针。
3.2 OSMemGet
该函数用于从内存区域分配一个内存块。用户程序必须知道所建立的内存块的大小,并必须
在使用完内存块后释放它。可以多次调用OSMemGet()函数。它的返回值就是指向所分配内存块
的指针,并作为OSMemPut()函数的参数。
OSMemGet(OS_MEM *pmem, INT8U *err);
pmem 是指向内存区域控制块的指针,可以从OSMemCreate()函数的返回值中得到。
Err 是指向包含错误码的变量的指针。Err可能是如下情况:
, OS_NO_ERR :成功得到一个内存块。
, OS_MEM_NO_FREE_BLKS :内存区域中已经没有足够的内存块。
OSMemGet()函数返回指向所分配内存块的指针。如果没有可分配的内存块,OSMemGet
()函数返回空指针。
3.3 OSMemPut
该函数用于释放一个内存块,内存块必须释放回它原先所在的内存区域,否则会造成系统错
误。
OSMemPut( OS_MEM *pmem, void *pblk);
pmem 是指向内存区域控制块的指针,可以从OSMemCreate()函数的返回值中得
到。
50
Pblk 是指向将被释放的内存块的指针。
OSMemPut()函数的返回值为下述之一:
, OS_NO_ERR :成功释放内存块
, OS_MEM_FULL :内存区域已满,不能再接受更多释放的内存块。这种情况说
明用户程序出现了错误,释放了多于用OSMemGet()函数得到的内存块。 3.4 OSMemQuery
该函数用于得到内存区域的信息。
OSMemQuery(OS_MEM *pmem, OS_MEM_DATA *pdata);
pmem 是指向内存区域控制块的指针,可以从OSMemCreate()函数的返回值中得到。
Pdata 是一个指向OS_MEM_DATA数据结构的指针,该数据结构包含了以下的域:
Void OSAddr; /*指向内存区域起始地址的指针 */
Void OSFreeList; /*指向空闲内存块列表起始地址的指针 */
INT32U OSBlkSize; /*每个内存块的大小 */
INT32U OSNBlks; /*该内存区域中的内存块总数 */
INT32U OSNFree; /*空闲的内存块数目 */
INT32U OSNUsed; /*已使用的内存块数目 */
51
6 1
掌握嵌入式实时操作系统µC/OS中中断的使用情况。
2
2.1
在本实验中,设计了三个任务Task1、Task2、Task3,创建了一个信号量InterruptSem。
整个系统的运行流程如下:
1) 系统初始化,在TaskStart任务中,创建并启动任务Task1、Task2、Task3,优先级分别为
12,13,14。
2) 在TaskStart任务中创建一个信号量InterruptSem(初值为1)。
3) 任务在TaskStart任务中挂起自己,操作系统实施调度,进入Task1运行;
4) 任务Task1睡眠100ticks;
5) 任务Task2开始执行, 任务Task2获得信号量InterruptSem;
6) 任务Task2睡眠500tick,任务Task3投入运行,打印输出语句后延时,任务Task1睡眠时
间到继续投入运行,它申请信号量InterruptSem失败被阻塞;
7) 任务Task3投入运行,循环地打印输出语句。期间时钟中断不断产生,在中断处理程序中
对任务Task2的睡眠时间进行计数;
8) Task2睡眠时间到后恢复运行,并释放信号量InterruptSem;
9) Task1获得信号量InterruptSem后抢占Task2运行;
10) Task1使用完信号量InterruptSem后释放该信号量;
11) 系统从步骤4重复执行,一直运行下去……
程序代码如下:
void Task1 (void *pdata)
{
INT8U err;
pdata=pdata;
52
for (;;)
{
OSTimeDly(100);
printk("\nTask1is try to get semaphore.\n\n"); /*task1 delay 100 clock ticks */
OSSemPend(InterruptSem, 0, &err); /* Acquire semaphore to get into the room */
printk("Task1 has Succeed to obtain semaphore.\n");
printk("Task1 is delayed.\n\n");
OSTimeDly(200);
printk("\nThe delay of Task1 finished .\n");
printk("Task1 release semaphore.\n");
OSSemPost(InterruptSem); /* Release semaphore */
OSTimeDly(200);
}
}
void Task2 (void *pdata)
{ INT8U err;
pdata=pdata;
for (;;)
{
printk( "\nTask2 is try to get semaphore.\n");
OSSemPend(InterruptSem, 0, &err); /* Acquire semaphore to get into the room */
printk( "Task2 has Succeed to obtain semaphore.\n");
printk("Task2 is delayed.\n\n");
OSTimeDly(500); /*task2 delay 500 clock ticks */
printk("\nThe delay of Task2 finished .\n");
printk("Task2 release semaphore.\n");
OSSemPost(InterruptSem); /* Release semaphore */
OSTimeDly(200);
}
}
void Task3 (void *pdata)
{
pdata=pdata;
for (;;)
{
printk("Task3 has got the CPU:|||||||||||||||||||||||||||||||||||||\n");
OSTimeDly(100);
}
}
53
2.2
uC_OS-II/OS_CFG.h:
#define OS_MAX_EVENTS 10 /*最多可以有10个事件*/ #define OS_MAX_FLAGS 5 /*最多可以有5个事件标志*/ #define OS_MAX_MEM_PART 10 /*最多可以划分5个内存块*/ #define OS_MAX_QS 2 /*最多可以使用2个队列*/ #define OS_MAX_TASKS 9 /*最多可以创建9个任务*/ #define OS_LOWEST_PRIO 24 /*任务优先级不可以大于24*/ #define OS_TASK_IDLE_STK_SIZE 1024 /*空闲任务堆栈大小*/ #define OS_TASK_STAT_EN 1 /*是否允许使用统计任务*/ #define OS_TASK_STAT_STK_SIZE 1024 /*统计任务堆栈大小*/
#define OS_FLAG_EN 0 /*是否允许使用事件标志功能*/
#define OS_MBOX_EN 1 /*是否允许使用邮箱功能*/ #define OS_MBOX_ACCEPT_EN 1 /*是否允许使用 OSMboxAccept() */ #define OS_MBOX_DEL_EN 1 /*是否允许使用 OSMboxDel()*/ #define OS_MBOX_POST_EN 1 /*是否允许使用OSMboxPost()*/ #define OS_MBOX_POST_OPT_EN 1 /*是否允许使用OSMboxPostOpt() */ #define OS_MBOX_QUERY_EN 1 /*是否允许使用OSMboxQuery()*/
#define OS_MEM_EN 1 /*是否允许使用内存管理的功能*/ #define OS_MEM_QUERY_EN 1 /*是否允许使用OSMemQuery()*/
#define OS_MUTEX_EN 1 /*是否允许使用互斥信号量的功能*/ #define OS_MUTEX_ACCEPT_EN 1 /*是否允许使用OSMutexAccept()*/ #define OS_MUTEX_DEL_EN 1 /*是否允许使用OSMutexDel()*/ #define OS_MUTEX_QUERY_EN 1 /*是否允许使用OSMutexQuery()*/
#define OS_Q_EN 1 /*是否允许使用队列功能*/ #define OS_Q_ACCEPT_EN 1 /*是否允许使用OSQAccept()*/ #define OS_Q_DEL_EN 1 /*是否允许使用OSQDel()*/ #define OS_Q_FLUSH_EN 1 /*是否允许使用 OSQFlush()*/ #define OS_Q_POST_EN 1 /*是否允许使用 OSQPost()*/
54
#define OS_Q_POST_FRONT_EN 1 /*是否允许使用OSQPostFront()*/ #define OS_Q_POST_OPT_EN 1 /*是否允许使用OSQPostOpt()*/ #define OS_Q_QUERY_EN 1 /*是否允许使用OSQQuery()*/
#define OS_SEM_EN 1 /*是否允许使用信号量功能*/ #define OS_SEM_ACCEPT_EN 1 /*是否允许使用OSSemAccept()*/ #define OS_SEM_DEL_EN 1 /*是否允许使用 OSSemDel() */ #define OS_SEM_QUERY_EN 1 /*是否允许使用 OSSemQuery()*/
#define OS_TASK_CHANGE_PRIO_EN 1 /*是否允许使用 OSTaskChangePrio()*/ #define OS_TASK_CREATE_EN 1 /*是否允许使用OSTaskCreate()*/ #define OS_TASK_CREATE_EXT_EN 1 /*是否允许使用OSTaskCreateExt()*/ #define OS_TASK_DEL_EN 1 /*是否允许使用OSTaskDel()*/ #define OS_TASK_SUSPEND_EN 1 /*是否允许使用OSTaskSuspend() and OSTaskResume()*/
#define OS_TASK_QUERY_EN 1 /*是否允许使用OSTaskQuery()*/
#define OS_TIME_DLY_HMSM_EN 0 /*是否允许使用OSTimeDlyHMSM()*/ #define OS_TIME_DLY_RESUME_EN 1 /*是否允许使用OSTimeDlyResume()*/ #define OS_TIME_GET_SET_EN 1 /*是否允许使用OSTimeGet() 和 OSTimeSet()*/ #define OS_SCHED_LOCK_EN 1 /*是否允许使用OSSchedLock()和OSSchedUnlock()*/ #define OS_TICKS_PER_SEC 200 /*设置每秒之内的时钟节拍数目*/
55
3
56
4 µC/OS-II
OSSemCreate()
OSSemPend()
OSSemPost()
OSTimeDly()
函数的具体介绍请参考实验“优先级继承”的相关内容。
57
7
1
掌握嵌入式实时操作系统µC/OS-II中消息队列机制的基本原理和使用方法。 2
2.1
在本实验中,设计了6个普通应用任务:TA0(优先级为1)、TA1(优先级为2)、TA2(优先级为3)、TA3(优先级为4)、TA4(优先级为5)、TA5(优先级为6),以及一个控制任务TaskCon(优先级为7)。
µC/OS-II
具体的设计思路为:
, :创建一个等待属性为FIFO的消息队列1;创建一个等待属性为LIFO的
消息队列2。
, FIFO:由任务TA0、TA1、TA2等待队列1中的消息。
TA0、TA1、TA2使用相同的任务代码(Taskq1函数)。
, LIFO:由任务TA3、TA4、TA5等待队列2中的消息。
TA3、TA4、TA5使用相同的任务代码(Taskq2函数)。
, :TaskCon任务向队列2中连续发送6条消息,
然后查询消息数;清空该队列后再查询。
, :在任务TA3、TA4、TA5等待队列2中的消息的过程中,让
TaskCon删除队列2;当队列2被删除后,检查任务TA3、TA4、TA5调用接收消息的函数
是否返回错误码。
2.2
在main()函数中通过q1 = OSQCreate(&Msg1[0],6);q2 = OSQCreate(&Msg2[0],6); 创建两个消息队列。
在TaskStart任务中创建并启动所有的应用任务。
static void TaskStartCreateTasks (void)
{
INT8U i;
58
for (i = 0; i =0){
printk("\n-------------Add message to queue2-------------\n");
}
for( j = 0 ; j < 6 ; j++ )
{
err = OSQPost(q2,(void*)t[j]); /* post message to q2 FIFO */
switch(err){
case OS_NO_ERR:{
printk("the queue2 %d add %s\n",j,t[j]);
OSTimeDlyHMSM(0, 0, 0, 150);
break;
}
case OS_Q_FULL:{
printk("the queue2 is full, don't add. \n");
OSTimeDlyHMSM(0, 0, 0, 150);
break;
}
default :break;
}
}
if(del>=0){
if(note==1)
{
OSQFlush(q2);
printk("\n--------------clear up the queue2--------------\n"); /* clear up the queue 2. */
note=0;
}
else
note=1;
62
}
err=OSQQuery(q2,data); /* get the information about q2 */
if(err==OS_NO_ERR){
printk("\n------------the queue2'information------------\n");
printk(" NextMsg:%s, NumMsg:%d, QSize:%d.\n",(char )data->OSMsg, data->OSNMsgs,
data->OSQSize);
printk("----------------------------------------------\n");
} /* print the information about q2 */
OSTimeDlyHMSM(0, 0, 0, 500); /* Wait 500 minisecond */
printk("\n------------------------------------\n",);
if(del==0)
{
q=OSQDel(q2,OS_DEL_ALWAYS,&err); /* delete the q2 */
if(q==(OS_EVENT *)0)
{
printk(" already successful delete queue2 \n");
}
}
else
{
del--;
printk( " not successful delete queue2 \n");
}
printk("------------------------------------\n");
}
}
2.3
uC_OS-II/OS_CFG.h
#define OS_MAX_EVENTS 10 /*最多可以有10个事件*/ #define OS_MAX_FLAGS 5 /*最多可以有5个事件标志*/ #define OS_MAX_MEM_PART 5 /*最多可以划分5个内存块*/ #define OS_MAX_QS 2 /*最多可以使用2个队列*/ #define OS_MAX_TASKS 10 /*最多可以创建10个任务*/
63
#define OS_LOWEST_PRIO 14 /*任务优先级不可以大于14*/ #define OS_TASK_IDLE_STK_SIZE 1024 /*空闲任务堆栈大小*/ #define OS_TASK_STAT_EN 1 /*是否允许使用统计任务*/ #define OS_TASK_STAT_STK_SIZE 1024 /*统计任务堆栈大小*/
#define OS_MBOX_EN 0 /*是否允许使用邮箱功能*/
#define OS_MEM_EN 0 /*是否允许使用内存管理的功能*/
#define OS_MUTEX_EN 0 /*是否允许使用互斥信号量的功能*/
#define OS_Q_EN 1 /*是否允许使用队列功能*/ #define OS_Q_ACCEPT_EN 1 /*是否允许使用OSQAccept()*/ #define OS_Q_DEL_EN 1 /*是否允许使用OSQDel()*/ #define OS_Q_FLUSH_EN 1 /*是否允许使用 OSQFlush()*/ #define OS_Q_POST_EN 1 /*是否允许使用 OSQPost()*/ #define OS_Q_POST_FRONT_EN 1 /*是否允许使用OSQPostFront()*/ #define OS_Q_POST_OPT_EN 1 /*是否允许使用OSQPostOpt()*/ #define OS_Q_QUERY_EN 1 /*是否允许使用OSQQuery()*/
#define OS_SEM_EN 0 /*是否允许使用信号量功能*/
#define OS_TASK_CHANGE_PRIO_EN 0 /*是否允许使用 OSTaskChangePrio()*/
#define OS_TIME_DLY_HMSM_EN 1 /*是否允许使用OSTimeDlyHMSM()*/ #define OS_TIME_DLY_RESUME_EN 1 /*是否允许使用OSTimeDlyResume()*/ #define OS_TIME_GET_SET_EN 1 /*是否允许使用OSTimeGet() 和 OSTimeSet()*/ #define OS_TICKS_PER_SEC 200 /*设置每秒之内的时钟节拍数目*/ 3
(1)首先,任务TaskCon将消息放入消息队列中:
64
(2)任务TaskCon清空消息队列2,之后查询消息队列2的内容:
(3)TA0—TA2按照LIFO顺序获取消息:
65
(4)任务TaskCon再次将消息放入队列中,TA0—TA2按照LIFO顺序获取消息,TA3—TA5按照
FIFO顺序获取消息。
66
(5)任务TaskCon将消息队列2删除以后,TA3—TA5就不能获取消息了。
67
4 µC/OS-II
4.1 OSQCreate
该函数用于建立一个消息队列。任务或中断可以通过消息队列向一个或多个任务发送消息。消
息的含义是和具体的应用密切相关的。
:OS_EVENT *OSQCreate( void **start, INT8U size);
start 是消息内存区的首地址,消息内存区是一个指针数组。
Size 是消息内存区的大小。
OSQCreate()函数返回一个指向消息队列控制块的指针。如果没有空闲的控制块,OSQCreate()函数返回空指针。
4.2 OSQPend
该函数用于任务等待消息。消息通过中断或任务发送给需要的任务。消息是一个指针变量,在
不同的应用中消息的具体含义不同。如果调用OSQPend()函数时队列中已经存在消息,那么该消
息被返回给OSQPend()函数的调用者,该消息同时从队列中清除。如果调用OSQPend()函数时队列中没有消息,OSQPend()函数挂起调用任务直到得到消息或超出定义的超时时间。如果同时
有多个任务等待同一个消息,μC/OS-?默认最高优先级的任务取得消息。一个由OSTaskSuspend()函数挂起的任务也可以接受消息,但这个任务将一直保持挂起状态直到通过调用OSTaskResume()函数恢复任务的运行。
:Void *OSQPend( OS_EVENT *pevent, INT16U timeout, INT8U *err);
:
pevent 是指向消息队列的指针,该指针的值在建立该队列时可以得到。(参考OSMboxCreate()函数)。
Timeout 允许一个任务以指定数目的时钟节拍等待消息。超时后如果还没有得到消息则恢复
成就绪状态。如果该值设置成零则表示任务将持续地等待消息,最大的等待时间为65535个时钟节拍。这个时间长度并不是非常严格的,可能存在一个时钟节拍的误差。
Err 是指向包含错误码的变量的指针。OSQPend()函数返回的错误码可能为下述几种:
, OS_NO_ERR :消息被正确地接受。
, OS_TIMEOUT :消息没有在指定的时钟周期数内接收到消息。
68
, OS_ERR_PEND_ISR :从中断调用该函数。虽然规定了不允许从中断中调用该函数,但
μC/OS-?仍然包含了检测这种情况的功能。
, OS_ERR_EVENT_TYPE :pevent 不是指向消息队列的指针。
OSQPend()函数返回取得的消息并将*err置为OS_NO_ERR。如果没有在指定数目的时钟节拍内接受到消息,OSQPend()函数返回空指针并将*err设置为OS_TIMEOUT。 4.3 OSQPostFront()
该函数用于向消息队列发送消息。OSQPostFront()函数和OSQPost()函数非常相似,不同之处在于OSQPostFront()函数将发送的消息插到消息队列的最前端。也就是说,OSQPostFront()函数使得消息队列按照后入先出(LIFO)的方式工作,而不是先入先出(FIFO)。消息是一个指针长度的变量,在不同的应用中消息的含义也可能不同。如果队列中已经存满消息,则此调用将返回
错误码。OSQPost()函数也是如此。在调用此函数时如果有任何任务在等待队列中的消息,则最
高优先级的任务将得到这个消息。如果等待消息的任务优先级比发送消息的任务优先级高,那么高
优先级的任务在得到消息后将立即抢占当前任务执行,也就是说,将发生一次任务切换。
:INT8U OSQPostFront(OS_EVENT *pevent, void *msg);
pevent 是指向即将接收消息的消息队列的指针。该指针的值在建立队列时可以得到。(参考
OSQCreate()函数)。
Msg 是即将发送的消息的指针。不允许传递一个空指针。
OSQPost()函数的返回值为下述之一:
, OS_NO_ERR :消息成功地放到消息队列中。
, OS_MBOX_FULL :消息队列已满。
, OS_ERR_EVENT_TYPE :pevent 不是指向消息队列的指针。 4.4 OSQPost()
该函数用于向消息队列发送消息。消息是一个指针长度的变量,在不同的应用中消息的含义也
可能不同。如果队列中已经存满消息,则此调用返回错误码。如果有任何任务在等待队列中的消息,
则最高优先级的任务将得到这个消息。如果等待消息的任务优先级比发送消息的任务优先级高,那
69
么高优先级的任务将在得到消息后立即抢占当前任务执行,也就是说,将发生一次任务切换。消息
是以先入先出(FIFO)方式进入队列的,即先进入队列的消息先被传递给任务。
:INT8U OSQPost(OS_EVENT *pevent, void *msg);
pevent 是指向即将接受消息的消息队列的指针。该指针的值在建立队列时可以得到。(参考
OSQCreate()函数)。
Msg 是即将发送给队列的消息。不允许传递一个空指针。
OSQPost()函数的返回值为下述之一:
, OS_NO_ERR :消息成功地放到消息队列中。
, OS_MBOX_FULL :消息队列已满。
, OS_ERR_EVENT_TYPE :pevent 不是指向消息队列的指针。 4.5 OSQFlush ()
该函数用于清空消息队列。
:INT8U *OSQFlush(OS_EVENT *pevent);
pevent 是指向消息队列的指针。该指针的值在建立队列时可以得到。(参考OSQCreate()函数)。
OSQFlush()函数的返回值为下述之一:
, OS_NO_ERR :消息队列被成功清空
, OS_ERR_EVENT_TYPE :试图清除不是消息队列的对象
4.6 OSQQuery()
该函数用来取得消息队列的信息。用户程序必须建立一个OS_Q_DATA的数据结构,该结构用来保存从消息队列的控制块得到的数据。通过调用该函数可以知道是否有任务在等待消息、有多少
个任务在等待消息、队列中有多少消息以及消息队列可以容纳的消息数。OSQQuery()函数还可以得到即将被传递给任务的消息。
:INT8U OSQQuery(OS_EVENT *pevent, OS_Q_DATA *pdata);
70
pevent 是指向消息队列的指针。该指针的值在建立消息队列时可以得到。(参考OSQCreate()函数)。
Pdata 是指向OS_Q_DATA数据结构的指针,该数据结构包含下述成员:
Void *OSMsg; /* 下一个可用的消息*/
INT16U OSNMsgs; /* 队列中的消息数目*/
INT16U OSQSize; /* 消息队列的大小 */
INT8U OSEventTbl[OS_EVENT_TBL_SIZE]; /* 消息队列的等待队列*/
INT8U OSEventGrp;
OSQQuery()函数的返回值为下述之一:
, OS_NO_ERR :调用成功
, OS_ERR_EVENT_TYPE :pevent 不是指向消息队列的指针。 4.7 OSQDel()
该函数用于删除指定的消息队列。
4.8 OSTimeDlyHMSM()
该函数用于将一个任务延时若干时间。延时的单位是小时、分、秒、毫秒。调用OSTimeDlyHMSM()后,如果延时时间不为0,系统将立即进行任务调度。
: void OSTimeDlyHMSM( INT8U hoursINT8U minutesINT8U secondsINT8U
milli);
hours为延时小时数,范围从0-255。
minutes为延时分钟数,范围从0-59。
seconds为延时秒数,范围从0-59
milli为延时毫秒数,范围从0-999。
需要说明的是,操作系统在处理延时操作时都是以时钟节拍为单位的,实际的延时时间是时钟
节拍的整数倍。如果系统时钟节拍的间隔是10ms,而设定延时为5ms的话,则不会产生延时操作;而如果设定延时为15ms,则实际的延时是两个时钟节拍,也就是20ms。
OSTimeDlyHMSM()的返回值为下述之一:
, OS_NO_ERR:函数调用成功。
, OS_TIME_INVALID_MINUTES:参数错误,分钟数大于59。
71
, OS_TIME_INVALID_SECONDS:参数错误,秒数大于59。
, OS_TIME_INVALID_MILLI:参数错误,毫秒数大于999。
, OS_TIME_ZERO_DLY:四个参数全为0。
72