十七、FreeRTOS之FreeRTOS事件标志组

本节需要掌握以下内容:

1,事件标志组简介(了解)

2,事件标志组相关API函数介绍(熟悉)

3,事件标志组实验(掌握)

4,课堂总结(掌握)

一、时间标志组简介(了解)

时间标志位:用一个位,来表示事件是否发生,通常我们会定义一个标志位uint8_t flag = 0,bit0 = 1,表示按键按下了,bit0表示事件未发生。

事件标志组是一组事件标志位的集合,(一个位是一个事件标志位,把么8个位就组成了一个事件标志组,)那么可以简单的理解事件标志组,就是一个整数。

事件标志组的特点:

  • 它的每一位表示一个事件(高8位不算)
  • 每一位事件的含义。由用户自己决定,如:bit0表示按键是否按下,bit1表示是否接受到消息.......这些位的值为1:表示事件发生了;值为0:表示事件未发生
  • 任意任务或者中断都可以读写这些位
  • 可以等待某一位成立,或者等待多位同时成立

1.1 事件标志组简介

一个事件组就包含了一个EventBits_t数据类型的变量,变量类型EventBits_t的定义如下所示:

 EventBits_t实际上是一个16位或32位的无符号的数据类型

虽然使用了32位无符号的数据类型变量来存储事件标志,但其中的高8位用作存储事件标志组的控制信息,低24位用作存储事件标志,所以说一个事件组最多可以存储24个事件标志!

1.2  事件标志组与队列、信号量的区别?

功能

唤醒对象

事件清除

队列、信号量

事件发生时,只会唤醒一个任务

是消耗型的资源,队列的数据被读走就

没了;信号量被获取后就减少了

事件标志组

事件发生时,会唤醒所有符合条件的任务,可以理解为“广播”的作用

被唤醒的任务有两个选择,可以让事件

保留不动,也可以清除事件

二、事件标志组相关API函数介绍(熟悉)

函数

描述

xEventGroupCreate()

使用动态方式创建事件标志组

xEventGroupCreateStatic()

使用静态方式创建事件标志组

xEventGroupClearBits()

清零事件标志位

xEventGroupClearBitsFromISR()

在中断中清零事件标志位

xEventGroupSetBits()

设置事件标志位

xEventGroupSetBitsFromISR()

在中断中设置事件标志位

xEventGroupWaitBits()

等待事件标志位

xEventGroupSync()

设置事件标志位,并等待事件标志位

 此处只列举了常用的一部分,更多事件标志组相关的API函数介绍请查阅FreeRTOS开发指南》-- 第十六章“FreeRTOS事件标志组”

2.1 动态方式创建事件标志组API函数

EventGroupHandle_t    xEventGroupCreate ( void ) ;

返回值

描述

NULL

事件标志组创建失败

其他值

事件标志组创建成功,返回其句柄

2.2 清除事件标志位API函数

EventBits_t  xEventGroupClearBits( EventGroupHandle_t   xEventGroup,
        const
EventBits_t   uxBitsToClear )

形参

描述

xEventGroup

待操作的事件标志组句柄

uxBitsToSet

待清零的事件标志位

返回值

描述

整数

清零事件标志位之前事件组中事件标志位的值

 2.3 设置事件标志位API函数

EventBits_t   xEventGroupSetBitsEventGroupHandle_t   xEventGroup,
    const
EventBits_t   uxBitsToSet    )

形参

描述

xEventGroup

待操作的事件标志组句柄

uxBitsToSet

待设置的事件标志位

返回值

描述

整数

函数返回时,事件组中的事件标志位值

2.4 等待事件标志位API函数

EventBits_t   xEventGroupWaitBits(    EventGroupHandle_t   xEventGroup,

                                                                const EventBits_t   uxBitsToWaitFor,

                                                                const BaseType_t   xClearOnExit,

                                                                const BaseType_t   xWaitForAllBits,

                                                                TickType_t   xTicksToWait         )

形参

描述

xEvenrGroup

等待的事件标志组句柄

uxBitsToWaitFor

等待的事件标志位,可以用逻辑或等待多个事件标志位

xClearOnExit

成功等待到事件标志位后,清除事件组中对应的事件标志位,

pdTRUE  :清除uxBitsToWaitFor指定位;

pdFALSE:不清除

xWaitForAllBits

等待 uxBitsToWaitFor 中的所有事件标志位(逻辑与)

pdTRUE:等待的位,全部为1

pdFALSE:等待的位,某个为1

xTicksToWait

等待的阻塞时间

拿一个8位的变量来举例,假设设置bit0和bit1都成立,这时候第二个参数就可以或起来,写成0x02|0x01,再多几个也可以这样或起来。

返回值

描述

等待的事件标志位值

等待事件标志位成功,返回等待到的事件标志位

其他值

等待事件标志位失败,返回事件组中的事件标志位

 特点:可以等待某一位、也可以等待多位,等到期望的事件后,还可以清除某些位

2.5 同步函数

EventBits_t    xEventGroupSync(   EventGroupHandle_t   xEventGroup,
                                                       const EventBits_t
  uxBitsToSet,
                                                       const
EventBits_t   uxBitsToWaitFor,
                                                       
TickType_t   xTicksToWait        )

形参

描述

xEventGroup

等待事件标志所在事件组

uxBitsToSet

达到同步点后,要设置的事件标志

uxBitsToWaitFor

等待的事件标志

xTicksToWait

等待的阻塞时间

返回值

描述

等待的事件标志位值

等待事件标志位成功,返回等待到的事件标志位

其他值

等待事件标志位失败,返回事件组中的事件标志位

举个例子:

Task1:做饭        Task2:做菜 

Task1做好自己的事之后,需要等待菜也做好,大家在一起吃饭。

特点:同步!

三、事件标志组实验(掌握)

3.1、实验目的:

学习 FreeRTOS 的事件标志组相关API的使用。

3.2、实验设计:

将设计三个任务:start_task、task1、task2

三个任务的功能如下:

  • start_task:用来创建task1和task2任务,并创建事件标志组
  • task1:读取按键按下键值,根据不同的键值将事件标志组相应事件位置1,模拟事件发生
  • task2:同时等待事件标志组中的多个事件位,当这些事件位都置1的话就执行相应的处理

3.3 实验代码

demo.c

/******************************************************************************************************/
/*FreeRTOS配置*/

/* START_TASK 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define START_TASK_PRIO         1
#define START_TASK_STACK_SIZE   128
TaskHandle_t    start_task_handler;
void start_task( void * pvParameters );

/* TASK1 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define TASK1_PRIO         2
#define TASK1_STACK_SIZE   128
TaskHandle_t    task1_handler;
void task1( void * pvParameters );


/* TASK2 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define TASK2_PRIO         3
#define TASK2_STACK_SIZE   128
TaskHandle_t    task2_handler;
void task2( void * pvParameters );

/******************************************************************************************************/
EventGroupHandle_t  eventgroup_handle;
#define EVENTBIT_0  (1 << 0)   /* 0x01 */
#define EVENTBIT_1  (1 << 1)   /* 0x10 */
/**
 * @brief       FreeRTOS例程入口函数
 * @param       无
 * @retval      无
 */
void freertos_demo(void)
{    
    xTaskCreate((TaskFunction_t         )   start_task,
                (char *                 )   "start_task",
                (configSTACK_DEPTH_TYPE )   START_TASK_STACK_SIZE,
                (void *                 )   NULL,
                (UBaseType_t            )   START_TASK_PRIO,
                (TaskHandle_t *         )   &start_task_handler );
    vTaskStartScheduler();
}


void start_task( void * pvParameters )
{
    taskENTER_CRITICAL();               /* 进入临界区 */
    eventgroup_handle = xEventGroupCreate();
    if(eventgroup_handle != NULL)
    {
        printf("事件标志组创建成功!!\r\n");
    }
    
    xTaskCreate((TaskFunction_t         )   task1,
                (char *                 )   "task1",
                (configSTACK_DEPTH_TYPE )   TASK1_STACK_SIZE,
                (void *                 )   NULL,
                (UBaseType_t            )   TASK1_PRIO,
                (TaskHandle_t *         )   &task1_handler );
                
    xTaskCreate((TaskFunction_t         )   task2,
                (char *                 )   "task2",
                (configSTACK_DEPTH_TYPE )   TASK2_STACK_SIZE,
                (void *                 )   NULL,
                (UBaseType_t            )   TASK2_PRIO,
                (TaskHandle_t *         )   &task2_handler );
                             
    vTaskDelete(NULL);
    taskEXIT_CRITICAL();                /* 退出临界区 */
}

/* 任务一,事件标志组相应事件位置1 */
void task1( void * pvParameters )
{
    uint8_t key = 0;
    while(1) 
    {
        key = key_scan(0);
        if(key == KEY0_PRES)
        {
            xEventGroupSetBits( eventgroup_handle, EVENTBIT_0); /* 将事件标志组的bit0位置1 */
        }else if(key == KEY1_PRES)
        {
            xEventGroupSetBits( eventgroup_handle, EVENTBIT_1); /* 将事件标志组的bit1位置1 */
        }
        vTaskDelay(10);
    }
}

/* 任务二,等待事件标志组中的多个事件位 */
void task2( void * pvParameters )
{
    EventBits_t event_bit = 0;
    while(1)
    {
        event_bit = xEventGroupWaitBits( eventgroup_handle,         /* 事件标志组句柄 */
                                         EVENTBIT_0 | EVENTBIT_1,   /* 等待事件标志组的bit0和bit1位 */
                                         pdTRUE,                    /* 成功等待到事件标志位后,清除事件标志组中的bit0和bit1位 */
                                         pdTRUE,                    /* 等待事件标志组的bit0和bit1位都置1,就成立 */
                                         portMAX_DELAY );           /* 死等 */
        printf("等待到的事件标志位值为:%#x\r\n",event_bit);
    }
}

 把程序下进去之后,复位

首先打印的是:事件标志组创建成功!

为什么不打印等待事件的标志位值呢?因为此时BIT0 与 BIT1都不是1,Task2处于阻塞状态,

按下KEY0也不会打印,KEY0与KEY1都按了才会打印:等待事件的标志位值为0x03(0x01|0x02)

当事件等待函数xEventGroupWaitBits()执行完毕之后,BIT0 与 BIT1都会被清除,所以打印一次之后,下次进来之后,就又进入阻塞状态了

如果把第三个参数改为pdFALSE,那就是不清零,就一直打印一直打印。

如果把第四个参数改成pdFLASE,那么BIT0 与 BIT1只有有一个为1,就会打印对应的键值。

四、总结

  • 28
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

I am Supreme

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值