打印
[应用相关]

ucos-ii信号量集(事件标志组)的原理及使用

[复制链接]
3550|28
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
在实际应用中,任务常常需要与多个事件同步,即要根据多个信号量组合作用的结果来决定任务的运行方式。UCOSII为了实现多个信号量组合的功能定义了一种特殊的数据结构——信号量集。


沙发
wangjiahao88|  楼主 | 2018-3-7 09:28 | 只看该作者
#include "INCLUDES.h"

#define  TASK_STK_SIZE        512                    

OS_STK        StartTaskStk[TASK_STK_SIZE];  //起始任务  
OS_STK        MyTaskStk[TASK_STK_SIZE];
OS_STK        YouTaskStk[TASK_STK_SIZE];
OS_STK        HerTaskStk[TASK_STK_SIZE];

使用特权

评论回复
板凳
wangjiahao88|  楼主 | 2018-3-7 09:31 | 只看该作者
char *s1= "Mytask is running";
char *s2= "Youtask is running";
char *s3= "Hertask is running";

INT8U  err;  //返回的错误信息
INT8U  y=0;   //字符显示位置

使用特权

评论回复
地板
wangjiahao88|  楼主 | 2018-3-7 09:31 | 只看该作者
OS_FLAG_GRP  *Sem_F;    //定义一个信号量集指针,是标志组类型,OS_FLAG_GRP类型的指针  用标志组描述信号量集
//事件控制块用来描述信号量,消息邮箱,消息队列

void  StartTask(void *data);               
void  MyTask(void *data);                  
void  YouTask(void *data);                  
void  HerTask(void *data);         

使用特权

评论回复
5
wangjiahao88|  楼主 | 2018-3-7 09:34 | 只看该作者
void  main (void)
{
    OSInit();                                             
    PC_DOSSaveReturn();                                    
    PC_VectSet(uCOS, OSCtxSw);                             
   
    Sem_F=OSFlagCreate(0,&err);    //创建信号量集 函数的原型为:OS_FLAG_GRP *OSFlagCreate(OS_FLAGS flags,INT8U *err)
    //其中参数OS_FLAGS flags是信号的初始值,在这里指定为0,即信号初始值为0.参数*err是错误信息,前面已经定义了
    //INT8U  err;  //返回的错误信息,所以此处为&err
    //返回值为OS_FLAG_GRP型的指针,即为创建的信号量集的标志组的指针,
    //前面已经定义了OS_FLAG_GRP  *Sem_F;    //定义一个信号量集指针
   
    OSTaskCreate(StartTask, (void *)0, &StartTaskStk[TASK_STK_SIZE - 1], 0); //创建起始任务
   
    OSStart();      
}

使用特权

评论回复
6
wangjiahao88|  楼主 | 2018-3-7 09:35 | 只看该作者
void  StartTask(void *pdata)
{
#if OS_CRITICAL_METHOD == 3     
    OS_CPU_SR  cpu_sr;
#endif
    INT16S        key;            
    pdata = pdata;        
    OS_ENTER_CRITICAL();  //进入临界段
    PC_VectSet(0x08, OSTickISR);                           
    PC_SetTickRate(OS_TICKS_PER_SEC);                     
    OS_EXIT_CRITICAL();   //退出临界段

    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) {                     
            if (key == 0x1B) {                             
                PC_DOSReturn();                           
            }
        }
        OSTimeDlyHMSM(0, 0, 3, 0);                        
    }
}

使用特权

评论回复
7
wangjiahao88|  楼主 | 2018-3-7 09:36 | 只看该作者
void MyTask(void *pdata)
{
#if OS_CRITICAL_METHOD == 3  
    OS_CPU_SR  cpu_sr;
#endif
pdata=pdata;
for( ; ; )
{
OSFlagPend(   //请求信号量集
Sem_F,   //请求信号量集指针
(OS_FLAGS)3,    //过滤器 请求第0和第1位信号 0011 这里是把数据3强制转化为OS_FLAGS类型的数据,
//因为过滤器和信号量集中的信号都是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
}
}

使用特权

评论回复
8
wangjiahao88|  楼主 | 2018-3-7 09:36 | 只看该作者
void YouTask(void *pdata)
{
#if OS_CRITICAL_METHOD == 3                                
    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,    //选择要发送的信号 给第1位发信号 0010  同样把2强制转化为OS_FLAGS型的数据,
//因为信号为OS_FLAGS型的
OS_FLAG_SET,   //信号有效的选项 信号置1  OS_FLAG_SET为置1  OS_FLAG_CLR为置0  
&err   //错误信息
);
OSTimeDlyHMSM(0,0,2,0);  //等待2s
}
}

使用特权

评论回复
9
wangjiahao88|  楼主 | 2018-3-7 09:39 | 只看该作者
void HerTask(void *pdata)
{
#if OS_CRITICAL_METHOD == 3                                
    OS_CPU_SR  cpu_sr;
#endif
pdata=pdata;
for( ; ; )
{
PC_DispStr(10,++y,s3,DISP_BGND_BLACK+DISP_FGND_WHITE);  //显示信息
OSTimeDlyHMSM(0,0,8,0);  //等待8s
OSFlagPost(   //向信号量集发信号
Sem_F,
(OS_FLAGS)1,    //给第0位发信号  0001,把1强制转化为OS_FLAGS型的
OS_FLAG_SET,   //信号置1
&err
);
OSTimeDlyHMSM(0,0,1,0);  //等待1s
}
}

使用特权

评论回复
10
wangjiahao88|  楼主 | 2018-3-7 09:39 | 只看该作者
//因为任务MyTask请求信号量集的时候请求的是第一位和第零位,所以下面两个任务分别发送第一位和第零位信号

//有一个问题:任务请求信号量集,得到信号后,信号量集中的对应的信号会被清除么??从本例的运行现象来看,好像
//是没有清除,因为当第一次YouTask和HerTask运行后,间隔了8s任务MyTask才运行,因为YouTask和HerTask都等待了8s
//才向信号量集发送信号。这个显现是正常的。但是以后MyTask每间隔2s就运行一次,没有间隔8s,等待信号量集。

//查到了:OSFlagPend()函数允许指定在任务等待的事件发生后,重新置起或是清除相应的事件标志位。这是通过在调用
//OSFlagPend()函数时将一个常量OS_FLAG_CONSUME和参数wait_type相“加”(或者相“或”)来实现的。
//例如希望等待事件标志组的BIT0位置位,而此时事件标志组的BIT0位已经置位了,那么如果在调用OSFlagPend()时,把参数
//wait_type加上OS_FLAG_CONSUME,就能清除这个事件标志位。如下所示:(详细说明,参见P210)

使用特权

评论回复
11
wangjiahao88|  楼主 | 2018-3-7 09:40 | 只看该作者
实验截图 如下:

111111.png (25.6 KB )

111111.png

使用特权

评论回复
12
wangjiahao88|  楼主 | 2018-3-7 09:57 | 只看该作者
第二个 例子应用如下:

#include "..\include\main.h"
#include "..\include\led.h"
#include "..\include\system_clock.h"
#include "..\include\usart6.h"
#include "..\include\key.h"

#include "includes.h"

#include "stm32f7xx_hal.h"

#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

//------------------------- Define ------------------------//
#define START_TASK_PRIO           10
#define AppTask1_TASK_PRIO        9
#define AppTask2_TASK_PRIO        8

#define START_STK_SIZE            128
#define AppTask1_STK_SIZE                128
#define AppTask2_STK_SIZE                128

//------------------------ Variable -----------------------//
OS_STK START_TASK_STK[START_STK_SIZE];
OS_STK AppTask1_TASK_STK[AppTask1_STK_SIZE];
OS_STK AppTask2_TASK_STK[AppTask2_STK_SIZE];

OS_FLAG_GRP *TaskFlag;//定义一个信号量集

使用特权

评论回复
13
wangjiahao88|  楼主 | 2018-3-7 09:58 | 只看该作者
//------------------- Function Prototype ------------------//
void start_task(void *pdata);
void AppTask1_task(void *pdata);
void AppTask2_task(void *pdata);

//------------------------ Function -----------------------//
/*
* Name                : main
* Description         : ---
* Author              : liu.
*
* History
* --------------------
* Rev                 : 0.00
* Date                : 07/12/2017
*
* create.
* --------------------
*/
/*实验现象:
  打开串口工具putty.exe,按下按键ARM.KEY,终端显示信号量集的状态;松开按键,停止显示。
信号量的16位分别循环置1。
*/
int main(void)
{
    system_clock.initialize();                               //系统时钟初始化
    led.initialize();                                        //LED初始化
    usart6.initialize(115200);                               //串口初始化
    key.initialize();

    usart6.printf("\x0c");                                   //清屏
    usart6.printf("\033[1;32;40m");                          //设置字体终端为绿色
    usart6.printf("\r\n Hello, I am iCore4!\r\n\r\n");
    LED_RED_ON;

    OSInit();

    //UCOS初始化
    OSTaskCreate(start_task,                                 //创建开始任务
                 (void*)0,                                   //任务参数
                 (OS_STK*)&START_TASK_STK[START_STK_SIZE-1], //任务堆栈
                 START_TASK_PRIO);                           //任务优先级
    OSStart();                                               //开启UCOS
}

使用特权

评论回复
14
wangjiahao88|  楼主 | 2018-3-7 10:47 | 只看该作者
/*
* Name                : AppTask1_task
* Description         : ---
* Author              : liu.
*
* History
* --------------------
* Rev                 : 0.00
* Date                : 07/12/2017
*
* create.
* --------------------
*/
void AppTask1_task(void *pdata)
{
    u8 err;
    int i = 0;
    while(1) {
        if(ARM_KEY_STATE == KEY_DOWN)
                        {                  //按键按下
            i++;
            if(i < OS_FLAGS_NBITS) {
                OSFlagPost(TaskFlag,i,OS_FLAG_SET,&err);     //设置第0位的信号为1
            } else {
                i=0;
            }
        }
        OSTimeDlyHMSM(0,0,0,500);                        //延时500ms
    }
}

使用特权

评论回复
15
wangjiahao88|  楼主 | 2018-3-7 10:48 | 只看该作者
/*
* Name                : AppTask2_task
* Description         : ---
* Author              : liu.
*
* History
* --------------------
* Rev                 : 0.00
* Date                : 07/12/2017
*
* create.
* --------------------
*/
void AppTask2_task(void *pdata)
{
    u8 err;
    u16 flag;

    while(1) {
        flag = OSFlagQuery(TaskFlag,&err);                     //查询信号量集的状态
        if(flag != 0) {
            usart6.printf("The %d bit is set to high.\r\n",flag);
            OSFlagPost(TaskFlag,(OS_FLAGS)flag,OS_FLAG_CLR,&err);//信号置0
        }
        OSTimeDlyHMSM(0,0,0,500);                              //延时500ms
    }
}

使用特权

评论回复
16
mmuuss586| | 2018-3-7 12:21 | 只看该作者
不错,感谢分享;

使用特权

评论回复
17
wangjiahao88|  楼主 | 2018-3-7 14:16 | 只看该作者
一起学习吧!

使用特权

评论回复
18
aspoke| | 2018-3-7 22:11 | 只看该作者
是互斥变量?

使用特权

评论回复
19
232321122| | 2018-3-7 22:11 | 只看该作者
wangjiahao88 发表于 2018-3-7 09:31
char *s1= "Mytask is running";
char *s2= "Youtask is running";
char *s3= "Hertask is running";

使用特权

评论回复
20
ghuca| | 2018-3-7 22:11 | 只看该作者
wangjiahao88 发表于 2018-3-7 09:35
void  StartTask(void *pdata)
{
#if OS_CRITICAL_METHOD == 3     

这个任务的分配是什么原理?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

473

主题

7517

帖子

30

粉丝