FreeRTOS 事件标志组

1. 事件标志组简介

跟裸机上的事件标志位非常非常类似。

事件标志位:用一个位,来表示事件是否发生。

事件标志组是一组事件标志位的集合, 可以简单的理解事件标志组,就是一个整数。

事件标志组的特点:

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

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

typedef TickType_t EventBits_t;
#if ( configUSE_16_BIT_TICKS == 1 )
	typedef   uint16_t   TickType_t;
#else
	typedef   uint32_t   TickType_t;
#endif
#define  configUSE_16_BIT_TICKS    0 

EventBits_t 实际上是一个 16 位或 32 位无符号的数据类型。(取决于 configUSE_16_BIT_TICKS 宏)

在我们的 STM32 中,我们这里定义 configUSE_16_BIT_TICKS 是 0,也就是说 EventBits_t 这一个数据类型是无符号 32 位的。虽然使用了 32 位无符号的数据类型变量来存储事件标志, 但其中的高 8 位用作存储事件标志组的控制信息,低 24 位用作存储事件标志 ,所以说一个事件组最多可以存储 24 个事件标志

在这里插入图片描述
事件标志组与队列、信号量的区别?

功能唤醒对象事件清除
队列、信号量事件发生时,只会唤醒一个任务是消耗型的资源,队列的数据被读走就没了;信号量被获取后就减少了
事件标志组事件发生时,会唤醒所有符合条件的任务,可以理解为“广播”的作用被唤醒的任务有两个选择,可以让事件保留不动,也可以清除事件

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   xEventGroupSetBits(  	EventGroupHandle_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等待的阻塞时间
返回值描述
等待的事件标志位值等待事件标志位成功,返回等待到的事件标志位
其他值等待事件标志位失败,返回事件组中的事件标志位

特点:

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

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. 事件标志组实验

实验目的:学习 FreeRTOS 的事件标志组API函数的使用。
实验设计:将设计三个任务:start_task、task1、task2

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

3.1 创建事件标志组

#include "event_groups.h"

/******************************************************************************************************/
EventGroupHandle_t  eventgroup_handle;
#define EVENTBIT_0  (1 << 0)
#define EVENTBIT_1  (1 << 1)
/**
 * @brief       FreeRTOS例程入口函数
 * @param       无
 * @retval      无
 */

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();                /* 退出临界区 */
}

3.2 任务函数实现

/* 任务一,释放二值信号量 */
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 之后,它就不会清除的,所以它一直会保持 1,所以等待事件标志位函数这里就会一直成立,那一直成立,肯定就一直打印,所以打印的一个结果就是 0x03。

4. 总结

在这里插入图片描述

  • 18
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值