13.FreeRTOS使用事件标记组

FreeRTOS 事件标记组

什么是事件标记组?

事件标记组是一个24(在 FreeRTOS 中,默认情况下,事件标记组的位数是 24 位)位的变量,每一位(bit)可以独立地被设置或清除。任务可以等待一个或多个事件标记被设置,并且可以选择等待所有指定的事件标记都被设置或任意一个被设置。当某个事件发生时,任务可以设置对应的事件标记,通知等待这些标记的任务。

创建事件标记组

首先,在 Arduino 代码中,你需要创建一个事件标记组。在 setup() 函数中调用 xEventGroupCreate 来创建一个事件标记组:

#include <Arduino.h>
#include <FreeRTOS.h>
#include <event_groups.h>EventGroupHandle_t xEventGroup;void setup() {Serial.begin(115200);xEventGroup = xEventGroupCreate();if (xEventGroup == NULL) {// 事件标记组创建失败,可能是因为内存不足while (1);}
}

设置和清除事件标记

然后,你可以在任务中设置和清除事件标记。例如,你可以使用 xEventGroupSetBits 来设置事件标记,使用 xEventGroupClearBits 来清除事件标记:

#define EVENT_BIT_0 (1 << 0)
#define EVENT_BIT_1 (1 << 1)void task1(void *pvParameters) {for (;;) {// 模拟某些工作vTaskDelay(pdMS_TO_TICKS(500));// 设置事件标记xEventGroupSetBits(xEventGroup, EVENT_BIT_0);}
}void task2(void *pvParameters) {for (;;) {// 清除事件标记xEventGroupClearBits(xEventGroup, EVENT_BIT_0);// 模拟某些工作vTaskDelay(pdMS_TO_TICKS(1000));}
}

等待事件标记

最后,在另一个任务中,你可以等待事件标记的设置。使用 xEventGroupWaitBits 函数来等待事件标记:

void task3(void *pvParameters) {EventBits_t uxBits;const TickType_t xTicksToWait = pdMS_TO_TICKS(1000);for (;;) {uxBits = xEventGroupWaitBits(xEventGroup,EVENT_BIT_0,pdTRUE,   // 等待后清除事件标记pdFALSE,  // 等待任意一个事件标记被设置xTicksToWait);if ((uxBits & EVENT_BIT_0) != 0) {// 事件标记被设置,执行相关操作}}
}

将任务添加到调度器中

最后,将创建的任务添加到 FreeRTOS 的任务调度器中:

void setup() {// 创建事件标记组xEventGroup = xEventGroupCreate();if (xEventGroup == NULL) {// 事件标记组创建失败,可能是因为内存不足while (1);}// 创建任务xTaskCreate(task1, "Task 1", 10000, NULL, 1, NULL);xTaskCreate(task2, "Task 2", 10000, NULL, 1, NULL);xTaskCreate(task3, "Task 3", 10000, NULL, 1, NULL);// 启动任务调度器vTaskStartScheduler();
}

完整示例

在这个示例中,我们将创建两个任务:一个任务会定期地设置事件标记,另一个任务会等待事件标记的设置,并在事件标记被设置时输出消息到串口。

#include <Arduino.h>
#include <FreeRTOS.h>
#include <event_groups.h>// 定义事件标记位
#define EVENT_BIT_0 (1 << 0)// 声明事件标记组句柄
EventGroupHandle_t xEventGroup;// Task1: 定期设置事件标记
void task1(void *pvParameters) {for (;;) {// 模拟某些工作delay(1000);// 设置事件标记xEventGroupSetBits(xEventGroup, EVENT_BIT_0);}
}// Task2: 等待事件标记的设置并输出消息
void task2(void *pvParameters) {EventBits_t uxBits;const TickType_t xTicksToWait = pdMS_TO_TICKS(1000);for (;;) {// 等待事件标记uxBits = xEventGroupWaitBits(xEventGroup,EVENT_BIT_0,pdTRUE,   // 等待后清除事件标记pdFALSE,  // 等待任意一个事件标记被设置xTicksToWait);if ((uxBits & EVENT_BIT_0) != 0) {// 事件标记被设置,输出消息到串口Serial.println("Event bit 0 is set!");}}
}void setup() {Serial.begin(115200);// 创建事件标记组xEventGroup = xEventGroupCreate();if (xEventGroup == NULL) {// 事件标记组创建失败,可能是因为内存不足while (1);}// 创建任务xTaskCreate(task1, "Task 1", 10000, NULL, 1, NULL);xTaskCreate(task2, "Task 2", 10000, NULL, 1, NULL);// 启动任务调度器vTaskStartScheduler();
}void loop() {// loop 函数为空,不需要额外的代码
}

在这个示例中,Task1 每隔 1 秒就会设置事件标记,而 Task2 每隔 1 秒就会检查事件标记是否被设置,如果事件标记被设置,它就会输出一条消息到串口。这样,我们就实现了两个任务之间的简单同步通信。

API汇总

当使用 FreeRTOS 中的事件标记组(Event Groups)时,有几个关键的 API 函数需要理解。

1. xEventGroupCreate

EventGroupHandle_t xEventGroupCreate(void)
  • 功能:创建一个事件标记组。
  • 参数:无。
  • 返回值:如果创建成功,返回一个事件标记组的句柄;如果创建失败,返回 NULL。
  • 说明:该函数用于在内存中动态分配一个事件标记组,并返回该事件标记组的句柄,以供其他函数使用。如果内存不足或其他原因导致创建失败,将返回 NULL。

2. xEventGroupWaitBits

EventBits_t xEventGroupWaitBits(EventGroupHandle_t xEventGroup, EventBits_t uxBitsToWaitFor, BaseType_t xClearOnExit, BaseType_t xWaitForAllBits, TickType_t xTicksToWait)
  • 功能:等待事件标记组中的特定事件标记被设置。
  • 参数
    • xEventGroup:要等待的事件标记组的句柄。
    • uxBitsToWaitFor:一个位掩码,指定要等待的事件标记的组合。
    • xClearOnExit:如果为 pdTRUE,则在函数返回时自动清除已经设置的事件标记;如果为 pdFALSE,则不清除。
    • xWaitForAllBits:如果为 pdTRUE,则只有当所有指定的事件标记都被设置时,函数才会返回;如果为 pdFALSE,则只要任何一个指定的事件标记被设置,函数就会返回。
    • xTicksToWait:等待的最长时间(以 FreeRTOS 的 Tick 单位表示)。
  • 返回值:如果等待时间超时,则返回0;否则返回一个位掩码,表示已经设置的事件标记。
  • 说明:该函数用于在任务中等待指定的事件标记被设置。可以选择是等待所有指定的事件标记都被设置,还是只等待任意一个事件标记被设置。还可以选择在等待结束时自动清除已经设置的事件标记。

3. xEventGroupSetBits

BaseType_t xEventGroupSetBits(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet)
  • 功能:设置事件标记组中的指定事件标记。
  • 参数
    • xEventGroup:要设置事件标记的事件标记组的句柄。
    • uxBitsToSet:一个位掩码,指定要设置的事件标记。
  • 返回值:如果设置成功,则返回 pdPASS;否则返回 errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY。
  • 说明:该函数用于设置事件标记组中的指定事件标记,使其被置位。多个事件标记可以通过位掩码的方式同时设置。

4. xEventGroupClearBits

BaseType_t xEventGroupClearBits(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear)
  • 功能:清除事件标记组中的指定事件标记。
  • 参数
    • xEventGroup:要清除事件标记的事件标记组的句柄。
    • uxBitsToClear:一个位掩码,指定要清除的事件标记。
  • 返回值:如果清除成功,则返回 pdPASS;否则返回 errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY。
  • 说明:该函数用于清除事件标记组中的指定事件标记,使其被清零。多个事件标记可以通过位掩码的方式同时清除。

xEventGroupSync() 是 FreeRTOS 中的一个高级事件标记组 API 函数,它允许多个任务在特定的事件发生时同时被唤醒,以便它们可以同时执行相关操作。

5. xEventGroupSync

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

参数:

  • xEventGroup:要操作的事件标记组的句柄。
  • uxBitsToSet:要设置的事件标记的位掩码。
  • uxBitsToWaitFor:要等待的事件标记的位掩码。
  • xTicksToWait:等待的最长时间(以 FreeRTOS 的 Tick 单位表示)。

返回值:

函数将等待 uxBitsToWaitFor 中的所有位都被设置,并在等待结束后将 uxBitsToSet 中的位设置为 1。如果在超时之前所有 uxBitsToWaitFor 的位都被设置,则返回事件标记组的当前状态;否则,在超时时返回 0。

功能:
xEventGroupSync函数在FreeRTOS中用于同步事件标记组。这个函数的工作方式是:首先设置指定的位,然后等待其他的位被设置。

当你调用xEventGroupSync函数时,它会首先设置uxBitsToSet指定的位,然后等待uxBitsToWaitFor指定的所有位都被设置。如果在xTicksToWait指定的时钟节拍数内,所有的位都被设置,那么函数就会返回。否则,它会继续等待。

因此,对于xEventGroupSync函数来说,是先设置位,然后等待位。

注意使用 xEventGroupSync() 时要小心,确保正确设置和等待事件标记,以避免死锁或其他同步问题。

结论

在 ESP32 上使用 FreeRTOS 的事件标记组可以实现多任务之间的同步和通信。然而,尽管事件标记组在某些情况下可能非常有用,但在事件标记组的操作下(如设置、清除、等待位等)可能会比其他同步机制(如互斥锁或信号量)更复杂。如果你的应用程序不需要事件标记组提供的灵活性,那么使用更简单的同步机制可能会更好。

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

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

相关文章

锁是实现原子性的一种方案,但是原子性的实现不一定需要通过锁机制保证

前言&#xff1a;在实际开发过程中&#xff0c;我们可能会通过事务来保证原子性&#xff0c;但是很多人存在误解&#xff0c;他们会以为Transactional 注解原子性就是代表java中的CAS或者锁那种也能保证并发情况下的原子性。其实不是这样的&#xff0c;MySQL的原子性是通过redo…

GraphQL(2):使用express和GraphQL编写helloworld

1 安装express、graphql以及express-graphql 在项目的目录下运行一下命令。 npm init -y npm install express graphql express-graphql -S 2 新建helloworld.js 代码如下&#xff1a; const express require(express); const {buildSchema} require(graphql); const grap…

vue3与ts的组合式API

vue3与ts的组合式API props 1.基本props <script setup lang"ts"> const props defineProps<{foo: stringbar?: number }>() </script>2.抽离props <script setup lang"ts"> interface Props {foo: stringbar?: number }co…

leetcode146.LRU缓存,从算法题引入,全面学习LRU和链表哈希表知识

leetcode146. LRU 缓存 题目链接 请你设计并实现一个满足 LRU (最近最少使用) 缓存约束的数据结构。 实现 LRUCache 类&#xff1a; LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存 int get(int key) 如果关键字 key 存在于缓存中&#xff0c;则返回关…

【QT】父子按钮同时响应点击事件

QPushButton如何响应点击事件 QPushButton::event(QEvent *e) 。可以看到在QPushButton中的event函数中并没有鼠标点击相关的操作&#xff0c;那么我们去QAbstractButton::event中寻找 damn it!。依然没有那我们去QWidget::event中寻找 damn it! 只有mousePressEvent mouseR…

leetcode165.比较版本号,简单模拟

leetcode165.比较版本号 给你两个 版本号字符串 version1 和 version2 &#xff0c;请你比较它们。版本号由被点 ‘.’ 分开的修订号组成。修订号的值 是它 转换为整数 并忽略前导零。 比较版本号时&#xff0c;请按 从左到右的顺序 依次比较它们的修订号。如果其中一个版本字…

主流摄像机:海康、大华、宇视、华为等RTSP格式

主流摄像机&#xff1a;海康、大华、宇视、华为等RTSP格式 解决方案速览海康摄像机大华摄像机宇视摄像机华为摄像机 解决方案速览 品牌rtsp格式rtsp举例海康rtsp://[username]:[password][ip]:[port]/[codec]/[channel]/[subtype]/av_streamrtsp://admin:admin123192.168.1.10…

libcef.dll丢失的解决方法-多种libcef.dll亲测有效解决方法分享

libcef.dll是Chromium Embedded Framework (CEF)的核心动态链接库&#xff0c;它为开发者提供了一个将Chromium浏览器嵌入到本地桌面应用程序中的解决方案。这个库使得开发者能够利用Chromium的强大功能&#xff0c;如HTML5、CSS3、JavaScript等&#xff0c;来创建跨平台的应用…

罕见!史诗级“大堵船”

新加坡港口的停泊延误时间已延长至7天&#xff0c;积压的集装箱数量达到惊人的450000标准箱&#xff0c;远超新冠疫情暴发时期的数轮高点。业内认为&#xff0c;近期东南亚恶劣的天气情况加剧了该区域港口拥堵。 5月31日&#xff0c;上海航运交易所&#xff08;下称“航交所”…

重生奇迹MU召唤师如何学习狂暴术?

一、了解狂暴术的基本信息 狂暴术是一种非常强大的技能&#xff0c;可以让召唤师的攻击力和防御力大幅度提高&#xff0c;但同时也会增加自身的伤害。在使用狂暴术之前&#xff0c;召唤师需要仔细考虑自己的状态和对手的情况。 二、学习狂暴术的方法 1.通过任务学习 在游戏…

Docker安装与使用 --学习笔记

一、概述 Docker是什么? Docker是一种工具&#xff0c;类似于一个虚拟箱子&#xff0c;可以把软件和它运行所需要的环境打包放进这个箱子里。这样&#xff0c;无论这个箱子放到哪里&#xff0c;软件都能像在原来的地方一样运行&#xff0c;不会因为换了地方就出问题。 假设…

uniapp使用数据持久化存储

什么是持久化存储 持久化存储是指将数据存储在非易失性介质中&#xff0c;以保证数据在系统重启或断电后仍能保持不变。这种存储方式确保数据持久存储并且可靠地被读取和访问&#xff0c; 简答来说&#xff1a;就是防止丢失&#xff0c;长期存储 为什么要用持久化存储 Pini…

leetcode5 最长回文子串

给你一个字符串 s&#xff0c;找到 s 中最长的 回文 子串。 示例 1&#xff1a; 输入&#xff1a;s "babad" 输出&#xff1a;"bab" 解释&#xff1a;"aba" 同样是符合题意的答案。示例 2&#xff1a; 输入&#xff1a;s "cbbd" 输…

【Java】一文看懂Thread 线程池的 7 种创建方式、任务队列及自定义线程池(代码示例)

本文摘要&#xff1a;【Java】Thread 线程池的 7 种创建方式及自定义线程池&#xff08;代码示例版&#xff09; &#x1f60e; 作者介绍&#xff1a;我是程序员洲洲&#xff0c;一个热爱写作的非著名程序员。CSDN全栈优质领域创作者、华为云博客社区云享专家、阿里云博客社区专…

编写一款2D CAD/CAM软件(十九)点选图形

点选图元原理 设定鼠标敏感范围,比如选中鼠标点击位置5个像素内距离最近的图元;当鼠标点击时,求解点击位置在几何坐标系下坐标点与附近几何图元的距离;如果到图元距离小于设定的鼠标敏感范围,则视为图形可选中;进一步,如果多个图元满足被选中的条件,则只选中距离最近的…

彩灯控制器设计 74ls160+ne555实现

一、选题背景 数字电子技术在我们生活中的应用非常之广泛,不论是在各个方面都会涉及到它,小到家用电器的自动控制,大到神舟九号和天空一号航天器的设计,都无可避免的要运用它。并且鉴于以理论推动实践及理论实践相结合为指导思想,特此用我们所学的理论知识来实践这次课程设…

低空经济国外经验及发展重点

国外先进经验 1.精准分类管理 美国将空域划分五大类&#xff0c;主要包括A类&#xff08;高空管制空域&#xff09;、B类&#xff08;繁忙终端管制空域&#xff09;、C类&#xff08;一般终端管制空域&#xff09;、D类&#xff08;机场管制空域&#xff09;和E类&#xff08…

UVa12273/LA4958 Palindromic DNA

UVa12273/LA4958 Palindromic DNA 题目链接题意分析AC 代码 题目链接 本题是2010年icpc欧洲区域赛西南欧赛区的的E题 题意 DNA由四种核苷碱基A、G、T、C组成&#xff0c;它们形成环状排序。当今能对DNA进行修改&#xff08;但不能同时对相邻位置进行修改&#xff09;&#xff…

【云原生】Docker Compose 使用详解

目录 一、前言 二、Docker Compose 介绍 2.1 Docker Compose概述 2.2 Docker Compose特点 2.3 Docker Compose使用场景 三、Docker Compose 搭建 3.1 安装docker环境 3.2 Docker Compose安装方式一 3.2.1 下载最新版/如果不是最新可替换最新版本 3.2.2 设置权限 3.2.…

Q-Learning 简介:初学者教程(1)

一、说明 强化学习强调无模型学习算法&#xff0c;因此出现Q-Learning&#xff0c;Q-Learning算法酷似“有限状态自动机”模型&#xff0c;只是增加了奖励机制和Agent机制&#xff0c;而Agent与粒子群算法、蒙特卡洛算法是有关的。本文介绍这个算法框架。 &#xff0c; 二、QL框…