ucos-ii学习笔记——信号量集(事件标志组)的原理及使用
Created on: 2012-10-8
Author: zhang bin
学习笔记
for ucos-ii PC
redesigned by zhang bin
2012-10-8
versions:V-0.1
All Rights Reserved
/*设计一个有三个任务的应用程序,这三个任务分别叫做Mytask Youtask
Hertask。
要求用一个信号量集来控制Mytask的运行,即任务Youtask发送一个信号,任务
Hertask
发送一个信号,当这两个任务都发了信号以后,Mytask才能运行。
*/
#include "INCLUDES.h"
#define TASK_STK_SIZE
512
/* 任务堆栈长度*/
OS_STK
区 */
OS_STK
OS_STK
OS_STK
StartTaskStk[TASK_STK_SIZE];
//起始任务 /*定义任务堆栈
MyTaskStk[TASK_STK_SIZE];
YouTaskStk[TASK_STK_SIZE];
HerTaskStk[TASK_STK_SIZE];
char *s1= "Mytask is running";
char *s2= "Youtask is running";
char *s3= "Hertask is running";
INT8U err;
INT8U y=0;
//返回的错误信息
//字符显示位置
OS_FLAG_GRP
OS_FLAG_GRP类型的指针 用标志组描述信号量集
//事件控制块用来描述信号量,消息邮箱,消息队列
*Sem_F;
// 定 义 一 个 信 号 量 集 指 针 , 是 标 志 组 类 型 ,
void StartTask(void *data);
void MyTask(void *data);
/* 声明起始任务 */
/* 声明任务
*/
void YouTask(void *data);
void HerTask(void *data);
/* 声明任务
/* 声明任务
*/
*/
/*
*********************************************************************
************************************
*
*********************************************************************
************************************
*/
MAIN主函数
void main (void)
{
OSInit();
uC/OS-II
*/
PC_DOSSaveReturn();
DOS环境
*/
PC_VectSet(uCOS, OSCtxSw);
uC/OS-II的中断 */
/* 初始化
/* 保存
/* 安装
Sem_F=OSFlagCreate(0,&err);
// 创 建 信 号 量 集 函 数 的 原 型 为 :
OS_FLAG_GRP *OSFlagCreate(OS_FLAGS flags,INT8U *err)
//其中参数OS_FLAGS flags是信号的初始值,在这里指定为0,即信号初始
值为0.参数*err是错误信息,前面已经定义了
//返回的错误信息,所以此处为&err
//INT8U err;
//返回值为OS_FLAG_GRP型的指针,即为创建的信号量集的标志组的指针,
//前面已经定义了OS_FLAG_GRP *Sem_F;
//定义一个信号量集指针
OSTaskCreate(StartTask, (void *)0, &StartTaskStk[TASK_STK_SIZE - 1], 0); //
创建起始任务
OSStart();
/* 启动多任务管理 */
}
/*
*********************************************************************
************************************
*
*********************************************************************
************************************
*/
void StartTask(void *pdata)
{
STARTUP TASK
#if OS_CRITICAL_METHOD == 3
进出临界段(开关中断)使用的第三种方法*/
OS_CPU_SR cpu_sr;
#endif
key;
INT16S
pdata = pdata;
OS_ENTER_CRITICAL();
PC_VectSet(0x08, OSTickISR);
/* Prevent compiler warning
/*用于退出的建*/
*/
//进入临界段
中断向量 */
钟频率 */
PC_SetTickRate(OS_TICKS_PER_SEC);
OS_EXIT_CRITICAL();
//退出临界段
/* Allocate storage for CPU status register
/* 安装时钟
/* 设置时
OSStatInit();
/* 初始化统计任务 */
OSTaskCreate(MyTask, (void *)0, &MyTaskStk[TASK_STK_SIZE - 1], 3); //在
起始任务中创建三个任务
OSTaskCreate(YouTask, (void *)0, &YouTaskStk[TASK_STK_SIZE - 1], 4);
OSTaskCreate(HerTask, (void *)0, &HerTaskStk[TASK_STK_SIZE - 1], 5);
for (;;) {
//如果恩下ESC键,则退出UC/OS-II
if (PC_GetKey(&key) == TRUE) {
has been pressed
*/
if (key == 0x1B) {
the ESCAPE key
*/
PC_DOSReturn();
*/
}
}
OSTimeDlyHMSM(0, 0, 3, 0);
DOS
*/
}
}
/* See if key
/* Yes, see if it's
/* Return to
/* Wait 3s
/*--------------------MyTask任务-------------------------*/
void MyTask(void *pdata)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
/* Allocate storage for CPU status register */
#endif
pdata=pdata;
for( ; ; )
{
OSFlagPend(
Sem_F,
(OS_FLAGS)3,
//请求信号量集
//请求信号量集指针
数据3强制转化为OS_FLAGS类型的数据,
//过滤器 请求第0和第1位信号 0011 这里是把
//因为过滤器和信号量集中的信号都是OS_FLAGS类型的数据
//OS_FLAG_WAIT_SET_ALL+OS_FLAG_CONSUME,
//信号全是
1表示信号有效 参数OS_FLAG_CONSUME表示当
//任务等待的事件发生后,清除相应的事件标志位
OS_FLAG_WAIT_SET_ALL,
//信号全是1表示信号有效 没有加
参数OS_FLAG_CONSUME,所以不会清除标志位
//等待时限,0表示无限等待
//错误信息
0,
&err
);
//任务MyTask在这里请求信号量集,如果请求到了信号量集,就继续
运行,下面就显示信息,如果请求不到信号量集
//MyTask就挂起,处于等待状态,只到请求到了信号量集才继续往下
运行
PC_DispStr(10,++y,s1,DISP_BGND_BLACK+DISP_FGND_WHITE);
//
显示信息
OSTimeDlyHMSM(0,0,2,0);
//等待2s
}
}
/*-------------------------------Youtask-------------------------------------*/
void YouTask(void *pdata)
{
#if OS_CRITICAL_METHOD == 3
Allocate storage for CPU status register */
OS_CPU_SR cpu_sr;
#endif
pdata=pdata;
for( ; ; )
{
/*
//
PC_DispStr(10,++y,s2,DISP_BGND_BLACK+DISP_FGND_WHITE);
显示信息
OSTimeDlyHMSM(0,0,8,0);
//等待8s
OSFlagPost(
Sem_F,
(OS_FLAGS)2,
//向信号量集发信号
//发送信号量集的指针
样把2强制转化为OS_FLAGS型的数据,
//因为信号为OS_FLAGS型的
//选择要发送的信号 给第1位发信号 0010 同
//信号有效的选项 信号置1 OS_FLAG_SET为
OS_FLAG_SET,
置1 OS_FLAG_CLR为置0
//错误信息
&err
);
OSTimeDlyHMSM(0,0,2,0);
//等待2s
}
}
/*-------------------------------Hertask-------------------------------------*/
void HerTask(void *pdata)
{
#if OS_CRITICAL_METHOD == 3
Allocate storage for CPU status register */
OS_CPU_SR cpu_sr;
/*
//
}
//因为任务MyTask请求信号量集的时候请求的是第一位和第零位,所以下面两个
任务分别发送第一位和第零位信号
//有一个问题:任务请求信号量集,得到信号后,信号量集中的对应的信号会被
清除么??从本例的运行现象来看,好像
//是没有清除,因为当第一次YouTask和HerTask运行后,间隔了8s任务MyTask才
运行,因为YouTask和HerTask都等待了8s
//才向信号量集发送信号。这个显现是正常的。但是以后MyTask每间隔2s就运行
一次,没有间隔8s,等待信号量集。
//查到了:OSFlagPend()函数允许指定在任务等待的事件发生后,重新置起或是
清除相应的事件标志位。这是通过在调用
PC_DispStr(10,++y,s3,DISP_BGND_BLACK+DISP_FGND_WHITE);
// 给 第 0 位 发 信 号 0001 , 把 1 强 制 转 化 为
#endif
pdata=pdata;
for( ; ; )
{
显示信息
OSTimeDlyHMSM(0,0,8,0);
OSFlagPost(
Sem_F,
(OS_FLAGS)1,
//向信号量集发信号
//等待8s
OS_FLAGS型的
OS_FLAG_SET,
&err
);
//信号置1
OSTimeDlyHMSM(0,0,1,0);
//等待1s
}
//OSFlagPend() 函 数 时 将 一 个 常 量 OS_FLAG_CONSUME 和 参 数 wait_type 相
“加”(或者相“或”)来实现的。
//例如希望等待事件标志组的BIT0位置位,而此时事件标志组的BIT0位已经置位
了,那么如果在调用OSFlagPend()时,把参数
//wait_type加上OS_FLAG_CONSUME,就能清除这个事件标志位。如下所示:(详
细说明,参见P210)
/*
OSFlagPend(OSFlagMyGrp,
(OS_FLAGS)0x01,
FLAG_WAIT_SET_ANY+OS_FLAG_CONSUME,
0,
&err);
*/
/* 我 把 MyTask 的 OSFlagPend() 的 wait_type 参 数 改 成
OS_FLAG_WAIT_SET_ALL+OS_FLAG_CONSUME,通过运行验证上面的说法
是
正确的。运行现象为任务MyTask会处于等待状态,知道YouTask和HerTask都发
送了消息,每次运行大概都等待8s左右
说明 MyTask 通过 OSFlagPend()函数获得信号后,相应的标志位确实是被清除了,
这就是参数 OS_FLAG_CONSUME 的作用。*/