当前位置: 首页 > ai >正文

FreeRTOS——事件标志组

一、简介

1)介绍

事件标志位:使用单个二进制位(0 或 1),来表示某个‌特定事件是否发生。

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

        事件标志组的特点:

  • 它的每一个位表示一个事件(高8位不算)
  • 每一位事件的含义,由用户自己决定,如:bit0表示按键是否按下,bit1表示是否接受到消息
    • 这些位的值为1:表示事件发生了;值为0:表示事件未发生
  • 任意任务或中断都可以读写这些位
  • 可以等待某一位成立,或者等待多位同时成立
2)事件标志组类型
事件标志组是一个变量 ,这个变量有很多位,也就是事件标志位的集合。
一个事件组就包含了一个 EventBits_t 数据类型的变量,变量类型 EventBits_t 的定义如下所示:
typedef TickType_t               EventBits_t;#if ( configUSE_16_BIT_TICKS == 1 )typedef uint16_t     TickType_t;#define portMAX_DELAY              ( TickType_t ) 0xffff
#elsetypedef uint32_t     TickType_t;#define portMAX_DELAY              ( TickType_t ) 0xffffffffUL

可以看出 EventBits_t 本质上是 TickType_t,而 TickType_t 数据类型又是由 configUSE_16_BIT_TICKS 这个宏决定的,如果该宏置 1,则为  uint16_t 类型,否则为 uint32_t 类型。(configUSE_16_BIT_TICKS 默认为 0)  

3)事件标志组结构说明

以无符号整形(uint32_t)为例,该类型有32位,但是并不是32位都用作于标志位,只有低24位用做存储事件标志位,高8位用于存储事件标志组的控制信息,所以说一个事件组最多可以存储 24 个事件标志!

        示意图如下:

4)事件标志组与队列、信号量的对比

功能唤醒对象时间清楚
队列、信号量

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

是消耗型的资源,队列的数据被读走就没了;信号量被获取后就减少了

事件标志组

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

被唤醒的任务有两个选择,可以让事件保留不动,也可以清除事件

二、API函数

函数描述

xEventGroupCreate()

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

xEventGroupCreateStatic()

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

xEventGroupClearBits()

清零事件标志位

xEventGroupClearBitsFromISR()

在中断中清零事件标志位

xEventGroupSetBits()

设置事件标志位

xEventGroupSetBitsFromISR()

在中断中设置事件标志位

xEventGroupWaitBits()

等待事件标志位

xEventGroupSync()

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

1. 动态创建事件标志组函数

/* 动态创建事件标志组函数原型 */
EventGroupHandle_t xEventGroupCreate( void )

该函数没有入口参数,使用该函数需要将宏 configSUPPORT_DYNAMIC_ALLOCATION 置 1。

返回值描述
NULL创建失败
其他值事件标志组创建成功,返回其句柄

2. 清除事件标志位函数

/* 函数原型 */
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToClear )

        参数说明:

  • xEventGroup:待操作的事件标志组句柄
  • uxBitsToClear :待清除的事件标志位
返回值描述
整数清除事件标志位前,事件标志位中的值

3. 设置事件标志位函数

/* 函数原型 */
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToSet )

        参数说明:

  • xEventGroup:待操作的事件标志组句柄
  • uxBitsToSet :待设置的事件标志位(置 1)
返回值描述
整数事件组中的事件标志位值

4. 等待事件标志位函数

/* 函数原型 */
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToWaitFor,const BaseType_t xClearOnExit,const BaseType_t xWaitForAllBits,TickType_t xTicksToWait )

 用于等待某些事件发生后,再继续执行。例如:按下按键0(将bit0 置 1),再发送消息(获取到了 bit0 置 1)。

        参数说明:

  • xEventGroup:等待的事件标志组句柄
  • uxBitsToWaitFor:等待的事件标志位,可以用逻辑或(&)等待多个事件
  • xClearOnExit:成功等待到事件标志位后,是否将对应的事件标志位清零
    • pdTRUE  :清除uxBitsToWaitFor指定位

    • pdFALSE:不清除

  • xWaitForAllBits:等待 uxBitsToWaitFor 中的某个时间,或者全部事件同时满足

    • pdTRUE:等待的位,全部置 1

    • pdFALSE:等待的位,一个置 1

  • xTicksToWait :等待的阻塞时间

返回值描述
等待到的事件标志位

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

其他值

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

 5. 通过事件标志位进行同步函数

/* 函数原型 */
EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToSet,const EventBits_t uxBitsToWaitFor,TickType_t xTicksToWait )

用于任务同步,例如:

        task1:做饭

        task2:做菜

在 task1 做好饭之后需要等待 task2 也做好菜,然后一起吃饭。

        参数说明:

  • xEventGroup:等待事件标志所在的事件标志组句柄
  • uxBitsToSet:达到同步点后,要设置的事件标志位
  • uxBitsToWaitFor:等待的事件标志位
  • xTicksToWait :等待的阻塞时间
返回值描述
等待到的事件标志位

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

其他值

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

三、代码示例

实验描述:task1通过按键0和按键1分别设置事件标志组的bit0位和bit1位,task2 去等待bit0位和bit1位,两个事件同时发生时task2继续执行,并打印标志位的值,task3和task2一样的作用,用于判断是否为广播式通知

main.c 文件

#include "malloc.h"
#include "freertos_demo.h"
#include "sys.h"
#include "usart.h"
#include "delay.h"
#include "usmart.h"
#include "led.h"
#include "lcd.h"
#include "key.h"int main(void)
{HAL_Init();                         /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */delay_init(72);                     /* 延时初始化 */usart_init(115200);                 /* 串口初始化为115200 */led_init();                         /* 初始化LED */lcd_init();                         /* 初始化LCD */key_init();                         /* 初始化按键 */my_mem_init(SRAMIN);                /* 初始化内部SRAM内存池 */freertos_demo();                    /* 创建起始任务 */
}

 freertos_demo.c 文件,主要功能实现

#include "freertos_demo.h"
#include "usart.h"
#include "led.h"
#include "lcd.h"
#include "key.h"
/*FreeRTOS******************************************************************************/
#include "FreeRTOS.h"
#include "task.h"
#include "event_groups.h"
#include "queue.h"
/***************************************************************************************//* START_TASK 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define TASK_STACK_SIZE 256
#define TASK_PRIORITY   1
TaskHandle_t start_task_handle;
void start_task(void *pvParameters);/* TASK1 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define TASK1_STACK_SIZE 256
#define TASK1_PRIORITY   2
TaskHandle_t task1_handle;
void task1(void *pvParameters);/* TASK2 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define TASK2_STACK_SIZE 256
#define TASK2_PRIORITY   3
TaskHandle_t task2_handle;
void task2(void *pvParameters);/* TASK3 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define TASK3_STACK_SIZE 256
#define TASK3_PRIORITY   4
TaskHandle_t task3_handle;
void task3(void *pvParameters);/***************************************************************************************/
#define EVENTBIT0       1 << 0                /* bit0位置1 */
#define EVENTBIT1       1 << 1                /* bit1位置1 */
EventGroupHandle_t event_bit;                 /* 事件标志组句柄 */void freertos_demo(void)
{/* 创建起始任务 */xTaskCreate((TaskFunction_t         )start_task,            /*函数指针,函数入口*/(char *                )"start_task",           /*任务名字*/(configSTACK_DEPTH_TYPE)TASK_STACK_SIZE,        /*任务堆栈的大小*/(void *                )NULL,                   /*任务参数*/(UBaseType_t           )TASK_PRIORITY,          /*任务优先级*/(TaskHandle_t *        )&start_task_handle      /*任务句柄*/);vTaskStartScheduler();
}/* 起始任务:创建其他任务和事件标志组 */
void start_task(void *pvParameters)
{taskENTER_CRITICAL();											/* 进入临界区 */event_bit = xEventGroupCreate();                                /* 创建事件标志组 */if(event_bit == NULL) printf("事件标志组创建失败\r\n");else printf("事件标志组创建成功\r\n");/* 创建任务1 */xTaskCreate((TaskFunction_t         )task1,(char *                )"task1",(configSTACK_DEPTH_TYPE)TASK1_STACK_SIZE,(void *                )NULL,(UBaseType_t           )TASK1_PRIORITY,(TaskHandle_t *        )&task1_handle);/* 创建任务2 */xTaskCreate((TaskFunction_t         )task2,(char *                )"task2",(configSTACK_DEPTH_TYPE)TASK2_STACK_SIZE,(void *                )NULL,(UBaseType_t           )TASK2_PRIORITY,(TaskHandle_t *        )&task2_handle);/* 创建任务3 */xTaskCreate((TaskFunction_t         )task3,(char *                )"task3",(configSTACK_DEPTH_TYPE)TASK3_STACK_SIZE,(void *                )NULL,(UBaseType_t           )TASK3_PRIORITY,(TaskHandle_t *        )&task3_handle);taskEXIT_CRITICAL();											/* 退出临界区 */vTaskDelete(NULL);												/* 删除当前任务 */
}/* 任务1:通过按键去设置相对于的事件标志位 */
void task1(void *pvParameters)
{uint8_t key = 0;while(1){key = key_scan(0);if(key == KEY0_PRES){xEventGroupSetBits( event_bit,EVENTBIT0);            /* 设置bit0位置1 */}else if(key == KEY1_PRES){xEventGroupSetBits( event_bit,EVENTBIT1);            /* 设置bit1位置1 */}vTaskDelay(10);}
}EventBits_t print_bit = 0;
void task2(void *pvParameters)
{while(1){print_bit = xEventGroupWaitBits(event_bit,              /* 等待的事件标志组 */EVENTBIT0 | EVENTBIT1,  /* 等待事件标志组的bit0和bit1位 */     pdTRUE,                 /* 成功等待后清理标志位 */pdFALSE,                /* 等待所有的标志位 */portMAX_DELAY);         /* 死等 */printf("task2: %#x\r\n",print_bit);}
}void task3(void *pvParameters)
{while(1){print_bit = xEventGroupWaitBits(event_bit,              /* 等待的事件标志组 */EVENTBIT0 | EVENTBIT1,  /* 等待事件标志组的bit0和bit1位 */     pdTRUE,                 /* 成功等待后清理标志位 */pdFALSE,                /* 等待所有的标志位 */portMAX_DELAY);         /* 死等 */printf("task3: %#x\r\n",print_bit);}
}

http://www.xdnf.cn/news/9137.html

相关文章:

  • Java 权威方案:彻底修复 OPTIONS 方法安全漏洞(附企业级案例与测试指南)
  • 今日行情明日机会——20250526
  • 固态硬盘不识别或掉盘如何解决?——以Kingston FURY Renegade G5为例
  • Qwen-Agent的使用示例-天气查询(function calling)
  • 电子电路原理第十七章(线性运算放大器电路的应用)
  • 【登录优化】redis删除旧token
  • AI测试进入智能体时代:AutoGen 、 Coze、CrewAI 谁主沉浮?
  • C++ STL map multimap 查找操作详解
  • 2025-5-26Vue3快速上手
  • Nginx location匹配模式详解
  • 解锁 MCP 中的 JSON-RPC:跨平台通信的奥秘
  • nfs下载镜像报错File lookup fail,TTTTTTTTTTTTTTT,内核 6.11.0降到5.15.0
  • JAVA面试复习知识点
  • 【沉浸式解决问题】基于泛型递归,Java中实体类基类开启MybatisPlus的ActiveRecord模式
  • PID控制学习(位置式,增量式,算法优化,多环串级PID)
  • LitCTF 2025 Robbie Wanna Revenge
  • 并发的产生及对应的解决方案之实例举证
  • Java 中经常犯的错误
  • 2025年5月26日第一轮
  • 【springboot项目部署】打包部署
  • 矩阵链乘法问题
  • vae 视频截图 复习 gans和vae的原理区别
  • JVM垃圾回收器详细介绍
  • 注解的使用和自定义
  • Composer 常规操作说明与问题处理
  • 【部署】读取制度类txt文件导入dify的父子分段知识库
  • Kubernetes 1.33您需要了解的和升级新功能
  • 爬虫学习-Scrape Center spa6 超简单 JS 逆向
  • 二叉树遍历
  • 打破壁垒:国内软件业产品与技术割裂困局及工程师产品思维重塑