ARM32开发--FreeRTOS-事件组

系列文章目录

知不足而奋进 望远山而前行


目录

系列文章目录

文章目录

前言

目标

内容

概念

事件标志位

开发流程

功能介绍

创建事件组

触发事件

等待事件触发

同步

清理事件

案例

总结


前言

在嵌入式系统开发中,任务之间的同步和通信是至关重要的。FreeRTOS作为一款开源的实时操作系统,提供了多种机制来实现任务间的有效协调。其中,事件组(Event Group)机制是一种强大的工具,允许任务等待和检测多个事件的状态,并在事件发生时进行及时的通知。通过使用事件组,开发人员可以实现复杂的任务调度和协同工作,提高系统的效率和可靠性。

本文将深入探讨FreeRTOS中事件组的基本概念、功能特性以及具体的使用方法。我们将详细介绍如何创建和管理事件组,以及如何利用事件组进行任务间的同步和通信。通过实际案例和代码示例,读者将能够全面理解如何在实际项目中应用事件组,从而更好地优化和管理嵌入式系统中的任务流程。


目标

  1. 理解什么是事件组
  2. 理解事件组标志位
  3. 掌握事件组开发流程

内容

概念

在FreeRTOS中,事件组(Event Group)是一种用于任务间同步和通信的机制。事件组允许任务等待和检测多个事件的状态,并在事件发生时进行通知。

事件组由一组标志位(或事件位)组成,每个标志位代表一个特定的事件。任务可以等待某些标志位被置位或清除,也可以设置或清除标志位。

以下是事件组的一些关键概念:

  1. 事件组句柄(Event Group Handle):

事件组句柄是用于标识和操作事件组的变量。它可以在创建事件组时由FreeRTOS分配,也可以通过函数返回。

  1. 标志位(Event Bit):

标志位是事件组中的单个位,它表示一个特定的事件。每个标志位可以被置位或清除,以表示事件发生或未发生。

标志位通常用二进制位来表示,如第0位、第1位等。可以使用位操作函数进行置位和清除操作。

  1. 等待事件(Waiting Events):

任务可以通过等待事件组中的一个或多个标志位来暂停执行,直到这些标志位满足特定的条件。

等待事件可以通过函数如xEventGroupWaitBits()、xEventGroupSync()等实现。

  1. 通知事件(Signaling Events):

任务可以通过设置或清除事件组中的标志位来通知其他任务事件的发生。

通知事件可以通过函数如xEventGroupSetBits()、xEventGroupClearBits()等实现。

通过使用事件组,任务可以进行有效的同步和通信,实现复杂的任务调度和协调。任务可以等待多个事件同时发生,也可以通过设置或清除标志位来触发其他任务的执行。

请注意,事件组是FreeRTOS中的一个特性,具体的使用方法和函数可能因不同的FreeRTOS版本而略有差异。建议参考相关的FreeRTOS文档和参考资料以获取更详细和准确的信息。

事件标志位

  1. 事件标志为一个32位的数字。也就是采用uint32_t来记录事件状态。
  2. 32位的状态分为高8位和低24位。
  3. 高8位位系统级事件和状态,由操作系统自行管理,无需开发人员关系。
  4. 低24位表示24种事件,每1个bit位表示一种事件,由开发人员控制这些事件位。
  5. 低24位中,每一位的取值是0或者1,0表示当前位对应的事件没有触发,1表示当前位的事件触发了。

开发流程

  1. 创建事件组
  2. 开启一个任务,用来等待事件触发
  3. 开启一个任务,用来改变事件触发

事件组标志位像一个订阅中心一样,一方可以订阅事件的触发,一方可以改变事件的状态。

功能介绍

功能

描述

xEventGroupCreate

创建事件组

xEventGroupSetBits

将事件状态改为触发

xEventGroupWaitBits

等待事件触发

创建事件组
EventGroupHandle_t xEventGroupCreate();

返回值为事件组的句柄。

触发事件

将事件状态改为触发

EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToSet )

参数说明:

  1. EventGroupHandle_t xEventGroup:事件组的句柄。
  2. const EventBits_t uxBitsToSet:事件标志位。

返回值:

当前触发的事件有哪些。

等待事件触发
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToWaitFor,const BaseType_t xClearOnExit,const BaseType_t xWaitForAllBits,TickType_t xTicksToWait )

参数说明:

  1. EventGroupHandle_t xEventGroup:事件组的句柄。
  2. const EventBits_t uxBitsToWaitFor:等待事件组的哪个标志位。可以是多个标志位。例如:
    1. 一个标志位(索引为1):0x02
    2. 两个标志位(索引为1和3):0x0A(0x08 + 0x02)
  1. const BaseType_t xClearOnExit:等待事件触发后,是否清除这个事件,如果清除,其他的订阅者将不会收到,不清除,就会收到。
    1. pdTRUE表示清除
    2. pdFALSE表示不清除。
  1. const BaseType_t xWaitForAllBits:指定是否等待所有的标志位都被设置。
    1. pdTRUE 表示等待所有标志位都被设置。(都为1)
    2. pdFALSE 表示只要有任何一个标志位被设置就可以继续执行任务。(任意一个为1)
  1. TickType_t xTicksToWait:等待标志位被设置的超时时间,以 FreeRTOS 的 Tick 单位表示。
    1. 可以使用 pdMS_TO_TICKS 宏将毫秒转换为 Tick 值。
    2. 如果设置为 portMAX_DELAY,则表示无限等待,直到标志位被设置。

返回值表示已设置的标志位。

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

参数说明:

  1. EventGroupHandle_t xEventGroup:事件组句柄
  2. const EventBits_t uxBitsToSet:要设置的标志位
  3. const EventBits_t uxBitsToWaitFor:要等待的事件标志位
  4. TickType_t xTicksToWait:等待的超时时间

清理事件

案例

开启三个任务,等待事件发生。通过按键触发事件发生。观察效果。

#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"
#include "FreeRTOS.h"
#include "task.h"#include "event_groups.h"
#include "Usart0.h"#define	EVENT_BIT(N)		(1 << N)
#define EVENT_BIT_0			EVENT_BIT(0)
#define EVENT_BIT_1			EVENT_BIT(1)
#define EVENT_BIT_2			EVENT_BIT(2)
#define EVENT_BIT_3			EVENT_BIT(3)
#define EVENT_BIT_4			EVENT_BIT(4)
#define EVENT_BIT_5			EVENT_BIT(5)
#define EVENT_BIT_6			EVENT_BIT(6)
#define EVENT_BIT_7			EVENT_BIT(7)
#define EVENT_BIT_8			EVENT_BIT(8)
#define EVENT_BIT_9			EVENT_BIT(9)
#define EVENT_BIT_10		EVENT_BIT(10)
#define EVENT_BIT_11		EVENT_BIT(11)
#define EVENT_BIT_12		EVENT_BIT(12)
#define EVENT_BIT_13		EVENT_BIT(13)
#define EVENT_BIT_14		EVENT_BIT(14)
#define EVENT_BIT_15		EVENT_BIT(15)
#define EVENT_BIT_16		EVENT_BIT(16)
#define EVENT_BIT_17		EVENT_BIT(17)
#define EVENT_BIT_18		EVENT_BIT(18)
#define EVENT_BIT_19		EVENT_BIT(19)
#define EVENT_BIT_20		EVENT_BIT(20)
#define EVENT_BIT_21		EVENT_BIT(21)
#define EVENT_BIT_22		EVENT_BIT(22)
#define EVENT_BIT_23		EVENT_BIT(23)TaskHandle_t            task_handler;
TaskHandle_t            task_key_handler;
TaskHandle_t            task1_handler;
TaskHandle_t            task2_handler;
TaskHandle_t            task3_handler;
EventGroupHandle_t			event_group;void task1(void *pvParameters) {EventBits_t bits;while(1) {bits = xEventGroupWaitBits(event_group, EVENT_BIT_0, pdTRUE, pdFALSE, portMAX_DELAY);printf("task1: %d\r\n", bits);vTaskDelay(1000);}vTaskDelete(NULL);
}void task2(void *pvParameters) {EventBits_t bits;while(1) {bits = xEventGroupWaitBits(event_group, EVENT_BIT_0, pdTRUE, pdTRUE, portMAX_DELAY);printf("task2: %d\r\n", bits);vTaskDelay(2000);}vTaskDelete(NULL);
}void task3(void *pvParameters) {EventBits_t bits = 0;while(1) {bits = xEventGroupWaitBits(event_group, EVENT_BIT_0, pdTRUE, pdTRUE, portMAX_DELAY);printf("task3: %d\r\n", bits);vTaskDelay(3000);}vTaskDelete(NULL);
}void task_key(void *pvParameters) {FlagStatus pre_state = RESET;while(1) {FlagStatus state = gpio_input_bit_get(GPIOA, GPIO_PIN_0);if(SET == state && pre_state == RESET) {// 当前高电平, 上一次为低电平,按下pre_state = state;printf("set bit \r\n");xEventGroupSetBits(event_group, EVENT_BIT_0);} else if(RESET == state && pre_state == SET) {// 当前高电平, 上一次为低电平,抬起pre_state = state;}vTaskDelay(20);}
}void start_task(void *pvParameters) {GPIO_config();Usart0_init();event_group = xEventGroupCreate();if(event_group != NULL) {printf("group success\r\n");}taskENTER_CRITICAL();xTaskCreate(task_key, "task_key", 64, NULL, 0, &task_key_handler);xTaskCreate(task1, "task1", 64, NULL, 4, &task1_handler);xTaskCreate(task2, "task2", 64, NULL, 3, &task2_handler);xTaskCreate(task3, "task3", 64, NULL, 2, &task3_handler);vTaskDelete(task_handler);taskEXIT_CRITICAL();
}void Usart0_recv(uint8_t *data, uint32_t len)
{// printf("recv: %s\n", data);xEventGroupSetBitsFromISR(event_group, EVENT_BIT_0, NULL);}static void GPIO_config() {// 时钟初始化rcu_periph_clock_enable(RCU_GPIOA);// 配置GPIO模式gpio_mode_set(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_PULLDOWN, GPIO_PIN_0);
}int main(void)
{nvic_priority_group_set(NVIC_PRIGROUP_PRE4_SUB0);xTaskCreate(start_task, "start_task", 128, NULL, 0, &task_handler);vTaskStartScheduler();while(1) {}
}

总结

事件组作为FreeRTOS中的重要特性,为嵌入式系统开发带来了灵活而强大的任务协调机制。通过本文的学习,我们深入了解了事件组的核心概念,包括事件组句柄、标志位的设置和等待、以及任务间的同步与通信方式。我们学习了如何创建事件组、如何设置和等待特定的事件标志位,以及如何通过事件组实现任务的有效协作。

在实际应用中,事件组可以帮助开发人员实现高效的任务调度和资源管理,提升系统的可靠性和响应速度。通过合理利用事件组的功能,开发人员能够更好地优化系统性能,适应不同的应用场景需求,从而实现更为复杂和可靠的嵌入式软件设计。

通过持续学习和实践,我们可以进一步探索和应用事件组的高级特性,为嵌入式系统开发注入更多创新和效率。希望本文能为读者提供实用且深入的指导,帮助他们在实际项目中充分发挥事件组的优势,构建出更加稳健和高效的嵌入式应用程序。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/29262.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

智慧矿山项目建设整体解决方案(938页 )

智慧矿山&#xff0c;究竟是什么&#xff1f; 在深入探讨之前&#xff0c;让我们先来提出一个深刻的问题&#xff1a;我们能否借助科技的力量&#xff0c;让矿山作业不仅安全、高效&#xff0c;还能做到环保可持续&#xff1f;答案是肯定的。智慧矿山&#xff0c;正是这一理念…

支撑每秒 600 万订单无压力,SpringBoot + Disruptor 太猛了!

一、背景 工作中遇到项目使用Disruptor做消息队列,对你没看错,不是Kafka,也不是rabbitmq;Disruptor有个最大的优点就是快,还有一点它是开源的哦,下面做个简单的记录. 二、Disruptor介绍 Disruptor 是英国外汇交易公司LMAX开发的一个高性能队列&#xff0c;研发的初衷是解决内存…

【docker入门】

在软件开发过程中&#xff0c;环境配置是一个至关重要的步骤&#xff0c;它不仅影响开发效率&#xff0c;也直接关联到软件的最终质量。正确的环境配置可以极大地减少开发中的潜在问题&#xff0c;提升软件发布的流畅度和稳定性。以下是几个关键方面&#xff0c;以及如何优化环…

【机器学习】第6章 支持向量机(SVM)

一、概念 1.支持向量机&#xff08;support vector machine&#xff0c;SVM&#xff09;&#xff1a; &#xff08;1&#xff09;基于统计学理论的监督学习方法&#xff0c;但不属于生成式模型&#xff0c;而是判别式模型。 &#xff08;2&#xff09;支持向量机在各个领域内的…

如何在不丢失数据的情况下解锁安卓手机密码

手机是我们生活中必不可少的工具&#xff0c;可以帮助我们与朋友和家人保持联系&#xff0c;了解最新消息&#xff0c;甚至经营我们的业务。然而&#xff0c;当我们在 Android 手机或 iPhone 上设置密码时&#xff0c;我们经常会忘记密码&#xff0c;或者根本没有设置密码。当这…

IntelliJ IDEA 使用 Maven 时不加载本地私服的最新版本快照(snapshot)JAR 包

IntelliJ IDEA 使用 Maven 时不加载本地私服的最新版本快照&#xff08;snapshot&#xff09;JAR 包 目录 IntelliJ IDEA 使用 Maven 时不加载本地私服的最新版本快照&#xff08;snapshot&#xff09;JAR 包1. 检查 settings.xml2. IDEA Maven 配置3. 强制更新 Snapshot4. 使用…

学习笔记——路由网络基础——路由度量值

3、路由度量值 (1)基本概念 路由度量值表示到达这条路由所指目的地址的代价。度量值数值越小越优先&#xff0c;度量值最小路由将会被添加到路由表中。度量值很多时候被称为开销(Cost)。 路由度量(路由开销 cost)对于同一个路由协议&#xff0c;当到达某目标网段有多条路由供…

SQL Server入门-安装和测试(2008R2版)

环境&#xff1a;win10&#xff0c;SQL Server 2008 R2 因为工作需要用到SQL Server&#xff08;而且要用2008R2版&#xff09;&#xff0c;完全不熟&#xff0c;所以来学习学习。 SQL Server是微软开发的关系型数据库&#xff0c;支持SQL。同时还有微软还开发了自己的T-SQL&am…

小鹏汽车2025冲刺类L4智驾,挑战与机遇并存

随着科技的飞速发展&#xff0c;智能驾驶已成为汽车行业的前沿领域。近日&#xff0c;小鹏汽车在AI DAY上宣布国内首个量产上车的端到端大模型&#xff0c;这一创新举措无疑为智能驾驶的发展注入了新的活力。然而&#xff0c;在迈向2025年实现类L4级智能驾驶的道路上&#xff0…

大前端 业务架构 插件库 设计模式 属性 线程

大前端 业务架构 插件库 适配模式之(多态)协议1对多 抽象工厂模式 观察者模式 外观模式 装饰模式之参考catagory 策略模式 属性

服务器新硬盘分区、格式化和挂载

文章目录 参考文献查看了一下起点现状分区(base) ~ sudo parted /dev/sdcmklabel gpt&#xff08;设置分区类型&#xff09;增加分区 格式化需要先退出quit&#xff08;可以&#xff09;(base) / sudo mkfs.xfs /dev/sdc/sdc1&#xff08;失败&#xff09;sudo mkfs.xfs /dev/s…

通过nginx转发后应用偶发502bad gateway

序言 学习了一些东西&#xff0c;如何才是真正自己能用的呢&#xff1f;好像就是看自己的潜意识的反应&#xff0c;例如解决了一个问题&#xff0c;那么下次再碰到类似的问题&#xff0c;能直接下意识的去找到对应的信息&#xff0c;从而解决&#xff0c;而不是和第一次碰到一样…

CRC循环冗余校验

CRC循环冗余校验 循环冗余校验码是一种用在数字网络和存储设备上的差错校验码&#xff0c;可以校验原始数据的偶然差 错。 CRC 计算单元使用固定多项式计算 32 位 CRC 校验码。 1. 硬件CRC 在单片机中&#xff0c;芯片具有专用的CRC计算单元&#xff0c;它是按照32位数据长…

LeetCode 48.旋转图像

1.做题要求: 2.从此题我们可以看出规律为第几行要变为倒数第几列&#xff0c;所以我们最好先把二维数组存入一维数组中&#xff0c;然后先从最后一列遍历&#xff0c;把一维数组里的元素&#xff0c;依次等于遍历的元素即可: void rotate(int** matrix, int matrixSize, int*…

Scala函数

文章目录 一、第1关&#xff1a;方法S 三角形 ​实验代码&#xff1a; 二、第2关&#xff1a;Scala函数以及函数调用实验代码&#xff1a; 一、第1关&#xff1a;方法 任务描述 本关任务&#xff1a;根据三角形的三边长 a、b、c&#xff0c;返回三角形的面积。 任意三角形面积…

外网怎么访问内网?

当我们需要在外网环境下访问内网资源时&#xff0c;常常会面临一些困扰。通过使用一些相关的技术与工具&#xff0c;我们可以轻松地实现这一目标。本文将介绍如何通过【天联】组网产品&#xff0c;解决外网访问内网的问题。 【天联】组网是一款由北京金万维科技有限公司自主研…

JAVAFX打包部署真正能用的办法(jdk21,javafx23)IntelliJ IDEA

我之前创建了javafx项目&#xff0c;想打包试试。一试&#xff0c;全是坑&#xff0c;所以记录下来&#xff0c;为有缘人节约时间。直接构建工件是错误的&#xff0c;别尝试了&#xff0c;找不在JDK的。我也花了一天多的时间尝试了网上各种大神的办法&#xff0c;就没找到一个是…

stm32学习-软件I2C读取MPU6050

接线 SDAPB11SCLPB10 I2C 对操作端口的库函数进行封装 void MyI2C_W_SCL(uint8_t BitValue)//写 {GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)BitValue);Delay_us(10); }void MyI2C_W_SDA(uint8_t BitValue)//写 {GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)BitValu…

Redis 7.x 系列【4】命令手册

有道无术&#xff0c;术尚可求&#xff0c;有术无道&#xff0c;止于术。 本系列Redis 版本 7.2.5 源码地址&#xff1a;https://gitee.com/pearl-organization/study-redis-demo 文章目录 1. 说明2. 命令手册2.1 Generic2.2 数据类型2.2.1 String2.2.2 Hash2.2.3 List2.2.4 S…

如何在纯内网环境下,将EasyCVR视频汇聚网关通过4G与第三方公网云平台级联?

EasyCVR视频汇聚网关是TSINGSEE青犀软硬一体的一款产品&#xff0c;可提供多协议的接入、音视频采集、处理&#xff0c;能实现海量前端设备的轻量化接入/转码/分发、视频直播、云端录像、云存储、检索回看、智能告警、平台级联等&#xff0c;兼容多种操作系统&#xff0c;轻松扩…