FreeRTOS:事件标志组与任务通知

 目录

一、事件标志组(Event Groups)

1、事件标志组的特点

2、事件标志组与队列、信号量的区别

3、关键API函数

4、示例代码

5、优缺点

6、总结

二、任务通知(Task Notifications)

1、任务通知的特点

2、关键API函数

3、使用场景

模拟二值信号量

模拟计数型信号量

模拟消息邮箱

4、优缺点

5、小结

三、总结


在FreeRTOS中,事件标志组(Event Groups)和任务通知(Task Notifications)是用于任务间同步和通信的重要机制。它们可以有效地帮助多个任务进行事件响应和通知,从而实现不同任务之间的协作

一、事件标志组(Event Groups)

事件标志组是一个非常强大的同步工具,它允许任务使用标志位的组合来表示多个事件的状态。每个任务可以检查一个或多个事件标志位,从而决定是否继续执行。事件标志组是一种位掩码机制,任务可以使用位操作来设置、清除或检查这些标志。

事件标志组是一种用于任务间同步的机制。它是由多个事件标志组成的一个集合,可以通过设置、清除或等待特定事件标志位来控制任务的执行流。每个事件标志组的每一位标志可以表示一个具体的事件状态,用户可以通过位操作来管理这些事件。

简单来说,事件标志组就像一个整数(无符号的 16 位或 32 位整数),每一位用来表示一个事件的状态。例如,某个任务可能会根据某些事件的发生情况来执行,而这些事件的状态通过事件标志组的各个位进行管理。

1、事件标志组的特点

  1. 每个位表示一个事件:每一位的状态(0 或 1)表示一个事件是否发生。比如,bit0 可能表示按键是否按下,bit1 可能表示是否收到了数据包,等等。

  2. 事件标志的存储:事件标志组内部使用 16 位或 32 位无符号整数来存储事件标志。在 STM32 中,通常是 32 位无符号整数。事件标志的高 8 位用于控制事件标志组的管理信息,低 24 位用于存储具体的事件标志。因此,一个事件标志组最多可以存储 24 个事件标志。

  3. 支持任务和中断操作:事件标志组不仅可以在任务中使用,还支持中断处理程序(ISR)操作。

  4. 等待某个事件或多个事件:任务可以选择等待单个事件的发生,或者等待多个事件的同时发生。并且,任务在等待某个事件的过程中,可以选择是否在事件被清除后继续等待。

  5. 事件标志的操作:可以设置、清除或等待事件标志,这些操作可以是独立的,也可以是组合的。

  6. 事件的“广播”作用:与信号量或队列不同,事件标志组可以在事件发生时唤醒多个任务,满足多个任务的条件。

2、事件标志组与队列、信号量的区别

队列和信号量:通常情况下,事件发生时只会唤醒一个任务。队列的数据被读取后就消失,信号量在被获取后会减少。

事件标志组:事件发生时,会唤醒所有符合条件的任务,相当于具有“广播”功能。被唤醒的任务有两个选择:要么继续等待事件,要么清除事件标志,避免任务再次被唤醒。

3、关键API函数

创建一个事件标志组:xEventGroupCreate()

设置事件标志组中的某些位:

EventBits_t xEventGroupSetBits(
    EventGroupHandle_t xEventGroup,          // 事件标志组句柄
    const EventBits_t uxBitsToSet            // 需要设置的事件标志位
);

该函数用于设置指定的事件标志位。如果事件发生,指定的标志位将被设置为 1,通知等待该事件的任务。

清除事件标志组中的某些位:xEventGroupClearBits()

等待某些事件标志位:

EventBits_t xEventGroupWaitBits(
    EventGroupHandle_t xEventGroup,          // 事件标志组句柄
    const EventBits_t uxBitsToWaitFor,       // 需要等待的事件标志
    const BaseType_t xClearOnExit,           // 退出时是否清除标志
    const BaseType_t xWaitForAllBits,        // 是否等待所有标志位成立
    TickType_t xTicksToWait                 // 等待超时时间
);
该函数用于等待指定的事件标志位。如果 xWaitForAllBitspdTRUE,则任务会等待所有指定的标志位,否则只等待其中任何一个标志位。如果 xClearOnExitpdTRUE,则在事件满足条件后清除标志位。

 同步两个或更多的任务的事件标志:

EventBits_t xEventGroupSync(
    EventGroupHandle_t xEventGroup,          // 事件标志组句柄
    const EventBits_t uxBitsToSet,           // 需要设置的标志位
    const EventBits_t uxBitsToWaitFor,       // 需要等待的标志位
    TickType_t xTicksToWait                 // 等待超时时间
);
该函数用于实现同步操作,它将同时设置指定的事件标志,并等待另一个任务设置指定的标志位。

使用场景

事件驱动的任务调度:任务根据事件标志位的状态来执行。

任务同步:多个任务需要在某些条件下同时执行。

4、示例代码

#include "FreeRTOS.h"
#include "task.h"
#include "event_groups.h"

// 事件标志组句柄
EventGroupHandle_t xEventGroup;

// 定义标志位
#define BIT_0    ( 1 << 0 )
#define BIT_1    ( 1 << 1 )

// 任务1
void Task1(void *pvParameters) {
    while (1) {
        // 设置 BIT_0 标志位
        xEventGroupSetBits(xEventGroup, BIT_0);
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

// 任务2
void Task2(void *pvParameters) {
    while (1) {
        // 等待 BIT_0 被设置
        EventBits_t uxBits = xEventGroupWaitBits(xEventGroup, BIT_0, pdTRUE, pdFALSE, portMAX_DELAY);
        if (uxBits & BIT_0) {
            // 响应事件
            printf("Task2 received BIT_0 event\n");
        }
    }
}

int main(void) {
    // 创建事件标志组
    xEventGroup = xEventGroupCreate();
    
    // 创建任务
    xTaskCreate(Task1, "Task1", 128, NULL, 2, NULL);
    xTaskCreate(Task2, "Task2", 128, NULL, 1, NULL);

    // 启动调度器
    vTaskStartScheduler();
    for (;;);
}
解释

xEventGroupSetBits(xEventGroup, BIT_0):任务1通过设置事件标志组中的BIT_0来通知任务2。

xEventGroupWaitBits(xEventGroup, BIT_0, pdTRUE, pdFALSE, portMAX_DELAY):任务2等待BIT_0标志位被设置,一旦设置,它会执行响应操作。

5、优缺点

优点:

事件标志组允许一个或多个任务等待不同的事件,并且可以组合多个标志位,支持灵活的同步机制。可减少不必要的任务切换,提高系统效率。

缺点

可能会引入较大的内存开销,尤其是当事件标志组的位数较多时。

6、总结

事件标志组是一个强大的同步工具,适合多个任务需要根据不同事件状态来执行的场景。它提供了位操作、事件等待、事件清除等功能,能够灵活地管理任务间的同步。相比队列和信号量,事件标志组具有“广播”能力,能够同时唤醒多个任务,因此适合需要多个任务响应的场景。使用事件标志组时,开发者可以选择任务在事件发生后是否清除事件标志,确保任务的灵活性。总之,事件标志组是FreeRTOS中非常重要的同步工具,它为任务间通信提供了一种高效且灵活的方式。

二、任务通知(Task Notifications)

任务通知是另一种高效的任务间通信机制,它允许一个任务向另一个任务发送“通知”。与事件标志组不同,任务通知是基于一个简单的计数器或标志位的机制,它能够非常快速地通知任务发生了某个事件。在FreeRTOS中,任务通知是任务间通信的一种轻量级方式,可以用于同步和传递简单的状态信息。任务通知的实现通过任务控制块(TCB)中的 ulNotifiedValueucNotifyState 成员来管理通知的值和状态。

1、任务通知的特点

  1. 不覆盖接收任务的通知值:可以选择更新通知值的部分位,而不是完全覆盖。

  2. 覆盖接收任务的通知值:可以选择完全覆盖接收任务的通知值。

  3. 更新通知值的某些位:类似于事件标志组,可以只更新通知值中的某些特定位。

  4. 增加接收任务的通知值:模拟计数信号量的行为,允许通知值递增。

  5. 类似队列、事件标志组和信号量:任务通知可以模拟二值信号量、计数型信号量、消息邮箱、事件标志组等多种功能。

2、关键API函数

xTaskNotifyGive():发送通知给任务。

xTaskNotifyWait():等待通知。

xTaskNotify():通知一个任务,并可以附加一个值。

xTaskNotifyAndQuery():向任务发送通知,并带上通知值,同时查询任务的当前通知值。

ulTaskNotifyTake():接收任务的通知值,适用于信号量的模拟。接收到通知后,通知值会被清零。

3、使用场景

轻量级任务间通信:任务通知通常用于需要简单同步或触发任务执行的场景。

不需要复杂状态控制的任务间同步:如果你只需要通知另一个任务某个事件发生,任务通知提供了一个非常快速和高效的机制。

模拟二值信号量

二值信号量通常用于同步任务,确保一个任务在执行时,另一个任务处于等待状态。在FreeRTOS中,任务通知可以用来模拟二值信号量。实现过程如下:

任务1:调用 xTaskNotifyGive() 向任务2发送通知,模拟释放信号量。

任务2:调用 ulTaskNotifyTake() 来等待信号量的获取,若信号量可用,则继续执行。

void Task1(void *pvParameters) {
    while (1) {
        // 模拟释放二值信号量
        xTaskNotifyGive(xTask2Handle);
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

void Task2(void *pvParameters) {
    while (1) {
        // 模拟获取二值信号量
        ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
        // 执行任务2
    }
}

模拟计数型信号量

计数型信号量允许多个任务共享资源。任务通知可以通过增加通知值来模拟计数信号量的行为。例如:

任务1:通过 xTaskNotifyGive() 向任务2发送通知,模拟计数信号量的增加。

任务2:通过 ulTaskNotifyTake() 等函数获取信号量。

void Task1(void *pvParameters) {
    while (1) {
        // 模拟计数型信号量的增加
        xTaskNotifyGive(xTask2Handle);
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

void Task2(void *pvParameters) {
    while (1) {
        // 获取计数信号量
        ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
        // 执行任务2
    }
}

模拟消息邮箱

任务通知也可以用来模拟消息邮箱。通过向任务发送带有数据的通知值,任务可以接收数据并进行处理。例如:

任务1:发送带有数据的通知(例如通过 xTaskNotify())。

任务2:接收通知并处理数据。

void Task1(void *pvParameters) {
    while (1) {
        uint32_t message = 42; // 模拟消息
        xTaskNotify(xTask2Handle, message, eSetValueWithOverwrite);
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

void Task2(void *pvParameters) {
    while (1) {
        uint32_t receivedMessage;
        xTaskNotifyWait(0, 0, &receivedMessage, portMAX_DELAY);
        // 处理接收到的消息
    }
}

4、优缺点

优点:

比较轻量级,开销小,适用于频繁的任务通知。不需要像事件标志组那样维护多个标志位,易于理解和实现。

缺点

只能用来通知任务,适用场景相对简单,无法像事件标志组那样处理复杂的同步需求。

无法向ISR发送通知:任务通知不能直接从中断服务程序(ISR)中发送。

无法广播给多个任务:任务通知只能通知一个任务,不能像事件标志组那样同时通知多个任务。

无法缓存多个数据:任务通知只保存一个值,无法像队列一样缓存多个数据。

发送受阻不支持阻塞:任务通知的发送不会被阻塞,发送方不能像信号量一样等待资源。

5、小结

任务通知是FreeRTOS中一种非常高效的任务间通信机制。它的优势在于:

低开销:任务通知操作非常高效,内存占用小。

灵活性:可以模拟二值信号量、计数型信号量、消息邮箱和事件标志组等功能。

然而,它也有一些局限性:

无法广播给多个任务:任务通知只能通知一个任务。

无法缓存多个数据:每个任务通知只能携带一个值,不像队列可以缓存多个数据。

综上所述,任务通知是一个非常适合在高效同步和传递简单状态信息的场景中使用的工具,特别是在资源有限的嵌入式系统中。

三、总结

事件标志组

用于多个任务间的事件同步,可以同时检查多个标志位。

适合需要更复杂事件组合和同步的场景。

支持位操作和多标志组合,灵活性较强。

任务通知

用于任务间的轻量级通知,适用于简单的同步或触发任务。

速度快,资源占用小,适合高频率的通知场景。

不适合复杂的状态同步和多事件组合。

两者的选择应该根据实际的应用需求来决定。如果是较为复杂的同步需求,事件标志组更为合适;如果仅需要简单的任务通知,则任务通知更为高效。

  

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2.不同语音ai任务dataset类写法

主流语音任务 语音数据读取基本原则 直接保存语音会将该对象保存在内存中&#xff08;Dataset类调用__getitem__方法&#xff09; 所以一般保存这些数据的存储路径文档&#xff08;表单&#xff09;而不是数据的直接copy&#xff08;不然占用内存太大了&#xff09; 通常用nump…

K8S + Jenkins 做CICD

前言 这里会做整体CICD的思路和流程的介绍&#xff0c;会给出核心的Jenkins pipeline脚本&#xff0c;最后会演示一下 实验/实操 结果 由于整体内容较多&#xff0c;所以不打算在这里做每一步的详细演示 - 本文仅作自己的实操记录和日后回顾用 要看保姆式教学的可以划走了&…

力扣 LeetCode 701. 二叉搜索树中的插入操作(Day10:二叉树)

解题思路&#xff1a; 全部插入到叶子节点即可 class Solution {public TreeNode insertIntoBST(TreeNode root, int val) {if (root null) {TreeNode node new TreeNode(val);return node;}if (root.val < val) {root.right insertIntoBST(root.right, val);}if (root…

2024年11月22日Github流行趋势

项目名称&#xff1a;twenty 项目维护者&#xff1a;charlesBochet, lucasbordeau, Weiko, FelixMalfait, bosiraphael 项目介绍&#xff1a;正在构建一个由社区驱动的现代Salesforce替代方案。 项目star数&#xff1a;22,938 项目fork数&#xff1a;2,413 项目名称&#xff1…

Qt之QMainWidget相关

QMainWindow 继承于QWidget的子类 自带一个菜单栏,一个工具栏,可以设置状态栏与铆钉部件 菜单栏:QMenuBar 注意:一个窗口最多一个菜单栏 API: 创建 QMenuBar(parent) 获取QMainWindow自带的菜单栏 QMenuBar* menuBar() 添加菜单:QMenu addMenu(QMenu *menu); 菜单添加活动:QAct…

【深度学习之一】2024最新pytorch+cuda+cudnn下载安装搭建开发环境

兵马未动&#xff0c;粮草先行。作为深度学习的初学者&#xff0c;快速搭建一个属于自己的开发环境就是头等大事&#xff0c;可以让我们节省许多的时间。这一期我们主要讲一讲2024年最新pytorchcudacudnn下载安装搭建开发环境&#xff0c;以及安装过程中可能遇到的一些问题以及…

SQL 复杂查询

目录 复杂查询 一、目的和要求 二、实验内容 &#xff08;1&#xff09;查询出所有水果产品的类别及详情。 查询出编号为“00000001”的消费者用户的姓名及其所下订单。&#xff08;分别采用子查询和连接方式实现&#xff09; 查询出每个订单的消费者姓名及联系方式。 在…

如何在 UniApp 中实现 iOS 版本更新检测

随着移动应用的不断发展&#xff0c;保持应用程序的更新是必不可少的&#xff0c;这样用户才能获得更好的体验。本文将帮助你在 UniApp 中实现 iOS 版的版本更新检测和提示&#xff0c;适合刚入行的小白。我们将分步骤进行说明&#xff0c;每一步所需的代码及其解释都会一一列出…

ssm面向品牌会员的在线商城小程序

摘要 随着Internet的发展&#xff0c;人们的日常生活已经离不开网络。未来人们的生活与工作将变得越来越数字化&#xff0c;网络化和电子化。它将是直接管理面向品牌会员的在线商城小程序的最新形式。本小程序是以面向品牌会员的在线商城管理为目标&#xff0c;使用 java技术制…

《OpenCV 图像缩放、翻转与变换全攻略:从基础操作到高级应用实战》

简介&#xff1a;本文详细阐述了 OpenCV 在图像操作中的关键技术&#xff0c;包括缩放&#xff08;确定尺寸缩放与按比例缩放&#xff09;、翻转&#xff08;沿不同轴的翻转方式&#xff09;以及变换&#xff08;平移、旋转、三点确定变换和四点确定变换即透视变换&#xff09;…

sql注入报错分享(mssql+mysql)

mysql mysql的报错内容比较多 网上也有比较多的 这里重复的就不多介绍了。一笔带过 溢出类 bigint 当超过mysql的整形的时候&#xff0c;就会导致溢出&#xff0c;mysql可能会将错误信息带出。这里user()是字母默认为0 取反以后1可能就会导致异常。 报错特征 BIGINT UNSIG…

FastAPI重载不生效?解决PyCharm中Uvicorn无法重载/重载缓慢的终极方法!

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 重载缓慢 📒📝 问题概述🚨 相关原因📝 解决方案一📝 解决方案二📝 解决方案三📝 解决方案四⚓️ 相关链接 ⚓️📖 介绍 📖 在使用FastAPI开发时,reload=True 本应让你在修改代码后自动重启服务,提升开发效率…

AI智能稿件排版系统订单管理系统

在现代制造业和服务行业中&#xff0c;高效的生产流程和精确的订单管理是企业保持竞争优势的核心要素。AI智能稿件排版系统和订单管理系统作为一体化解决方案&#xff0c;以其强大的自动化能力和智能化技术&#xff0c;帮助企业实现排版效率提升、数据格式兼容性增强和生产流程…

jetson orin系列开发版安装cuda的gpu版本的opencv

opencv安装包下载地址&#xff1a; https://github.com/opencv/opencv/扩展库下载地址&#xff1a; https://github.com/opencv/opencv_contrib1. 删除jetpack包中的opencv版本 原先的opencv库安装在目录/usr/lib/aarch64-linux-gnu/下&#xff08;一般其他的第三方库也都安…

24小时自动监控,自动录制直播蓝光视频!支持抖音等热门直播软件

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 工具特点📒📝 使用🎈 获取方式 🎈⚓️ 相关链接 ⚓️📖 介绍 📖 对于许多直播爱好者和内容创作者而言,错过心爱的直播或难以搜集视频素材始终是一个难题。今天,给大家分享的这款工具可以轻松解决这个问题,它拥有…

dockerfile构建Nginx镜像练习二(5-2)

环境准备&#xff1a; (1)保证拥有centos基础镜像 docker images | grep centos (2)服务器保证可以连接外网 1.创建工作目录 mkdir nginx cd nginx 2.在工作目录中创建并编写Dockerfile文件 vim dockerfile #定义基础镜像 FROM centos:7#维护者信息(可缺省) MAINTAINER d…

Etcd 框架

基本了解 客户端、长连接与租约的关系 客户端对象 etcd的客户端对象是用户与etcd服务进行交互的主要接口&#xff0c;主要功能就是存储、通知和事务等功能访问 键值存储&#xff1a;客户端通过put 和 get操作存储数据&#xff1b;数据存储在etcd的层级化键值数据库中监听器&a…

滑动窗口篇——如行云流水般的高效解法与智能之道(1)

前言&#xff1a; 上篇我们介绍了双指针算法&#xff0c;并结合具体题目进行了详细的运用讲解。本篇我们将会了解滑动窗口。滑动窗口是一种常用的算法技巧&#xff0c;主要用于处理子数组、子串等具有“窗口”特性的题目。柳暗花明&#xff0c;乃巧解复杂问题的高效之道。 一. …

数据结构-树状数组专题(2)

一、前言 接上回树状数组专题&#xff08;1&#xff09;&#xff0c;这次主要介绍差分跟树状数组联动实现区间更新 二、我的模板 重新放了一遍&#xff0c;还是提一嘴&#xff0c;注意下标从0开始&#xff0c;区间左闭右开 template <typename T> struct Fenwick {in…

QA|使用 MapleSim 模拟卷料生产 (Converting)和卷对卷系统 (R2R)

使用 MapleSim 模拟卷料生产 (Converting)和卷对卷系统 (R2R) 纸张、薄膜、塑料、金属箔、新能源电池和卷料生产设备 (converting equipment) 的制造商正在转向建模和仿真&#xff0c;以提升卷料处理的设备性能和产品质量。MapleSim 卷料处理库提供了专业的建模元件以及功能&a…