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

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);}
}

相关文章:

  • JS逆向【抖查查】逆向分析 | sign | secret签名验证
  • 华为OD机试真题——猴子吃桃/爱吃蟠桃的孙悟空(2025B卷:200分)Java/python/JavaScript/C++/C语言/GO六种最佳实现
  • 高精度装配人形机器人|产品参数详细介绍
  • Linux系统调用深度剖析
  • Transformer,多头注意力机制 隐式学习子空间划分
  • 10:图像传参+UI界面互传
  • Higress MCP Server 安全再升级:API 认证为 AI 连接保驾护航
  • 【混合动力能量管理新突破:负载识别优化策略深度解析与仿真实战】
  • Python 进阶学习
  • JVM 深度解析
  • HarmonyOS NEXT~HarmonyOS 语言仓颉:下一代分布式开发语言的技术解析与应用实践
  • python网络编程
  • 三色标记法 判断有向图是否有环
  • Leetcode 3562. Maximum Profit from Trading Stocks with Discounts
  • CAD精简多段线顶点、优化、删除多余、重复顶点——CAD c#二次开发
  • 厚铜PCB线路板厂会如何处理质量问题?
  • 滑动窗口算法实时计算QPS:Java实现与原理分析
  • MAR:无需量化的掩码自回归图像生成模型
  • RuoYi前后端分离框架集成UEditorPlus富文本编辑器
  • 嵌入式学习(基本操作)day1
  • 顺义做网站公司/最新热搜榜
  • 西安做商铺的网站/一个企业该如何进行网络营销
  • 网站的三级页面怎么做/seo视频教学网站
  • 网页设计html和css代码/成都网站快速优化排名
  • 0基础学网站建设/关键词排名技巧
  • 近的网站在线客服系统/seo优化网