16.FreeRTOS直接任务通知 Notification

FreeRTOS 直接任务通知 Notification

介绍


在嵌入式系统开发中,任务间的通信和同步是非常重要的一部分。而FreeRTOS就提供了多种机制来实现这些,比如队列、信号量和事件组。不过,使用这些机制都需要创建一个通信对象,不能直接把事件和数据发送给接收任务或中断服务例程(ISR),而是必须通过队列、事件组或信号量等通信对象来传递。同样地,任务和ISR也不能直接从发送事件或数据的任务或ISR那里接收事件和数据,而要从通信对象中接收。

为了解决这个问题,FreeRTOS引入了一种新的机制:直接任务通知(Task Notifications)。使用任务通知,任务之间可以直接交互,并且可以与ISR同步,而无需单独的通信对象。借助任务通知,任务或ISR可以直接向接收任务发送事件,简单便捷。

直接任务通知的原理


FreeRTOS的直接任务通知。其实,这东西就是个特殊的二进制信号量。当一个任务想给另一个任务发个通知时,就像传纸条一样,可以顺便带上一个32位的数值。收到通知的任务就能看到这个数值,明白要干啥了。要是通知已经发出去了,等待的任务就会立马被叫醒;不然的话,任务就得一直等着,就看它会是等到通知还是等到超时了。

咱们来打个比方。假设你和朋友在玩游戏,有时候得传一个特别的信号给他,告诉他下一步该咋办。这个信号就像一张小纸条,你可以写上一些指示然后递给朋友。他一收到纸条,就知道咱们要干嘛。在FreeRTOS里,直接任务通知就像是这张小纸条,而且还能带点额外信息,比如一个数字,指示接收任务该咋办。发送任务发通知,接收任务等通知。一旦通知来了,接收任务就能知道该干啥了。

🚨要注意一点哦!如果一个任务正在等待通知,一旦通知被发出来,这任务就会立马醒来。这是因为FreeRTOS的调度器会在通知发出时看看有没有任务在等着接收这个通知。要是有等着的,它就会立刻叫醒任务,让任务看看通知的数值,继续工作。

如果任务在通知发出后才开始等待它,那这个任务就会立刻收到通知,不需要陷入等待状态。原因是FreeRTOS的任务通知机制会记住已发送但尚未被接收的通知。

使用任务通知

要开启任务通知功能,首先要在FreeRTOSConfig.h里把configUSE_TASK_NOTIFICATIONS设成1如下图👇。设成1以后,每个任务都有一个“通知状态”,可以是等待(Pending)或者“不在等待(Not-Pending),还有一个“通知值”,就是一个32位无符号整数。任务收到通知的时候,通知状态会变成“Pending”。任务读取通知值的时候,通知状态会变成“Not-Pending”。任务可以在阻塞(Blocked)状态下等待通知状态变成“Pending”。

在这里插入图片描述

直接任务通知的用法

FreeRTOS 提供了一组 API 来实现直接任务通知的功能,主要包括 xTaskNotifyGive()ulTaskNotifyTake()xTaskNotifyWait() 等函数。这些函数允许任务发送和接收直接任务通知,并且可以带有一个 32 位的通知值。

直接任务通知的示例

示例1

在这个例子中干了两个活:Task1 和 Task2。Task1每秒给Task2发个通知,Task2等着接收通知。一旦Task2收到通知,就会打印个消息说收到了。这样,Task1 和 Task2 就通过直接任务通知搞定了沟通和同步的事儿。

#include <Arduino.h>
#include <FreeRTOS.h>
#include <task.h>

// 定义任务句柄
TaskHandle_t Task1Handle, Task2Handle;

// 任务1函数
void Task1(void *pvParameters) {
  while (1) {
    // 发送任务通知
    xTaskNotifyGive(Task2Handle);
    vTaskDelay(pdMS_TO_TICKS(1000)); // 每秒发送一次通知
  }
}

// 任务2函数
void Task2(void *pvParameters) {
  while (1) {
    // 等待任务通知
    ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
    
    // 收到通知后的操作
    Serial.println("Task2 received notification");
  }
}

void setup() {
  // 初始化串口
  Serial.begin(115200);

  // 创建任务1
  xTaskCreate(Task1, "Task1", 1000, NULL, 1, &Task1Handle);

  // 创建任务2
  xTaskCreate(Task2, "Task2", 1000, NULL, 1, &Task2Handle);
}

void loop() {
  // 什么也不做
}

示例2

同样有 任务1和任务2。任务1通过调用xTaskNotifyWait()等待通知。任务2通过调用xTaskNotify()向任务1发送通知。当任务1收到通知时,它会打印接收到的通知值。

#define NOTIFICATION_VALUE  ( 1UL << 0UL )  // 定义通知值

TaskHandle_t xTaskToNotify = NULL;  // 定义一个任务句柄,用于存储将要被通知的任务的句柄

// 任务1
void vTask1(void *pvParameters)
{
    // 定义一个变量,用于存储接收到的通知值
    uint32_t ulNotificationValue;

    // 等待通知
    // 如果在等待期间收到了通知,那么这个函数会返回pdPASS,并且ulNotificationValue会被设置为接收到的通知值
    BaseType_t xResult = xTaskNotifyWait(0, NOTIFICATION_VALUE, &ulNotificationValue, portMAX_DELAY);

    // 检查是否收到了通知
    if(xResult == pdPASS)
    {
        // 通知已接收,打印接收到的通知值
        printf("Received notification: %lu\n", ulNotificationValue);
    }
}

// 任务2
void vTask2(void *pvParameters)
{
    // 向任务1发送通知
    // 这个函数会将任务1的通知值设置为NOTIFICATION_VALUE
    xTaskNotify(xTaskToNotify, NOTIFICATION_VALUE, eSetBits);
}

int main(void)
{
    // 创建任务
    // 注意我们将任务1的句柄存储在了xTaskToNotify中,这样任务2就可以通过这个句柄向任务1发送通知
    xTaskCreate(vTask1, "Task 1", 1000, NULL, 1, &xTaskToNotify);
    xTaskCreate(vTask2, "Task 2", 1000, NULL, 1, NULL);

    // 启动调度器
    vTaskStartScheduler();

    return 0;
}

API

当然,以下是FreeRTOS中一些主要的直接任务通知API函数的详细信息:

1. xTaskNotify()

函数原型

BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction );

功能:向一个任务发送通知。

参数

  • xTaskToNotify:要通知的任务的句柄。
  • ulValue:通知值。
  • eAction:eAction是一个枚举类型,用于指定如何更新任务通知值。它有以下几个可能的值:
    • eNoAction:不改变通知值。这个动作可以用于仅发送通知,而不改变通知值。
    • eSetBits:将通知值中的一个或多个位设置为1 (相当于与对方的Notification value 或运算)。这个动作可以用于发送一个或多个事件标志。
    • eIncrement:将通知值加一。这个动作可以用于实现计数信号量。
    • eSetValueWithOverwrite:用新的值覆盖通知值,即使任务已经有通知挂起。
    • eSetValueWithoutOverwrite:只有在任务没有通知挂起时,才用新的值覆盖通知值。(即 只有当任务当前没有待处理的通知时,新的通知值才会被设置。)

返回值:如果通知成功发送,那么这个函数返回pdPASS。如果任务已经在等待接收通知,那么这个函数返回pdTRUE。

2. xTaskNotifyWait()

函数原型

BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait );

功能:让一个任务等待通知。

参数

  • ulBitsToClearOnEntry:在等待通知时要清除的位。
  • ulBitsToClearOnExit:在函数返回时要清除的通知值的位。
  • pulNotificationValue:指向变量的指针,这个变量用于存储接收到的通知值 (是在清除通知值对应位前的值)
  • xTicksToWait:等待通知的最大时间。

返回值:如果任务收到通知,那么这个函数返回pdPASS。否则,这个函数返回pdFALSE。

3. xTaskNotifyGive()

函数原型

void xTaskNotifyGive( TaskHandle_t xTaskToNotify );

功能:向一个任务发送通知,并将通知值加一。

参数

  • xTaskToNotify:要通知的任务的句柄。

返回值:这个函数没有返回值。

4. ulTaskNotifyTake()

函数原型

uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait );

功能:接收通知,并将通知值清零。

参数

  • xClearCountOnExit:一个布尔值,指定是否应该在通知值为零时阻塞任务。
  • xTicksToWait:等待通知的最大时间。

返回值:这个函数返回接收到的通知值。

总结

FreeRTOS 直接任务通知提供了一种高效的任务间通信机制,可以实现任务间的同步和协作,适用于多种实时嵌入式系统中。通过简单的 API 调用,任务可以发送和接收直接任务通知,从而实现灵活的任务管理和事件触发。

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

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

相关文章

【Unity Shader入门精要 第10章】高级纹理(一)

1. 立方体纹理原理 立方体纹理由6张图片组成&#xff0c;每张图片分别对应立方体的一个面。这6张图片代表沿世界空间下的轴线&#xff08;上下左右前后&#xff09;观察所得的图像 立方体的应用主要分为两类&#xff1a; 单纯利用6张图片的展示功能&#xff0c;为我们提供一…

怎么下载 jar 包

一、在Maven仓库里面下载 Maven仓库 网址&#xff1a;https://mvnrepository.com/ 二、搜索需要的 jar 包&#xff08;以 druid 为例&#xff09; 三、找到 druid jar包&#xff0c;点进去 四、找到自己需要的版本&#xff0c;点进去 五、 点 jar 下载

数字化前沿:Web3如何引领未来技术演进

在当今数字化时代&#xff0c;随着技术的不断发展和创新&#xff0c;Web3作为一种新兴的互联网范式&#xff0c;正逐渐成为数字化前沿的代表。Web3以其去中心化、加密安全的特性&#xff0c;正在引领着未来技术的演进&#xff0c;为全球范围内的科技创新带来了新的可能性和机遇…

第二讲笔记:隐私计算助力数据要素流通

1、数据要素流转与数据 2、数据外循环中的信任 焦虑 信任焦虑背后的代表性案例 内鬼门 &#xff1a; 2023 年 &#xff0c; 美国科技公司 Ubiquiti在2021年1月曝出数据泄露事 件&#xff0c; “攻击者”在随后的“谈判”中试 图向该企业勒索近200万美元&#xff08;50比特 币&…

.Net Core Console 项目如何使用 HttpClient 与 Web 服务通信

前言 HttpClient 类是在 .NET Framework 4.5 和 .NET Core 中引入的新的 HTTP 客户端类&#xff0c;是 .NET 用于发送和接收 HTTP 请求的类&#xff0c;相比之前的 WebRequest 和 HttpWebRequest&#xff0c; 它提供了现代的、易用的 API&#xff0c;并且具有更好的性能和扩展…

【Spring Cloud】微服务链路跟踪Sleuth

目录 为什么要使用微服务链路跟踪微服务的现状多服务协同工作复杂的调用链条容易出错 微服务链路跟踪需要实现的需求实现监控决策避免技术债务快速定位故障 微服务链路跟踪的技术要求低消耗应用透明延展性可控采样率可视化 Spring Cloud Sleuth简介Spring Cloud Sleuth的4个特点…

‘yarn’不是内部或外部命令,也不是可运行的程序或批处理文件。

目录 问题点 解决方式 # 安装 # 版本 # 本地发生变化&#xff08;了解&#xff09; # 安装项目依赖 新问题 解决方式 问题点 在vscode中&#xff0c;点击dev运行&#xff0c;项目报错【Q1】 * 正在执行任务: yarn run dev yarn : 无法将“yarn”项识别为 cmdlet、函数…

代码随想录算法训练营第26天(py)| 回溯 | 39. 组合总和、40.组合总和II、131.分割回文串

39. 组合总和 力扣链接 给定一个无重复元素的数组 candidates 和一个目标数 target &#xff0c;找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的数字可以无限制重复被选取。 说明&#xff1a; 所有数字&#xff08;包括 target&#xff09;都是正整数…

利用MaxKB+Ollama:搭建智能问答系统_Ubuntu部署maxkb

Docker方式&#xff0c;不建议使用 即使maxKB和ollama在同一目录下&#xff0c;API域名也显示无效。 Ollama下载网址&#xff1a;Download Ollama on Linux Linux下载&#xff1a;curl -fsSL https://ollama.com/install.sh | sh The Ollama API is now available at 127.0.…

PE文件结构详解之头信息解析

PE文件结构详解 一、前言1.概述2.PE文件结构3.所用工具 二、DOS头&#xff08;DOS Header&#xff09;解析1.作用2.图例3.参数详解4.总结 三、DOS Stub1.作用2.图例 四、NT头&#xff08;NT Header&#xff09;解析1.作用2.PE标识图例3.文件头&#xff08;COFF头&#xff09;图…

TinyMCE 富文本编辑器:打造个性化编辑体验

本文由ScriptEcho平台提供技术支持 项目地址&#xff1a;传送门 TinyMCE 富文本编辑器&#xff1a;打造个性化编辑体验 应用场景介绍 TinyMCE 是一款功能强大的富文本编辑器&#xff0c;广泛应用于网站内容管理、博客创作、在线文档编辑等场景。它提供了一系列丰富的编辑功…

LightDB pro*c迁移指南(游标模块)

文章目录 一、不使用SQLDA描述符范围的游标操作1.1 oracle 案例1.1.1 使用游标获取数据1.1.2 对于fetch结果集怎么去利用 1.2 LightDB 案例1.2.1 使用游标获取数据1.2.2 对于fetch结果集怎么去利用 3 总结&#xff1a;不同项 二、使用SQLDA描述符范围的游标操作2.1 Oracle样例2…

基于java的CRM客户关系管理系统(五)

目录 第五章 系统的详细设计与实现 5.1 持久层设计 5.1.1 创建关系映射 5.1.2 与数据库的连接 5.1.3 Hibernate的ORM映射 5.1.4 Struts的配置文件 5.1.5 Spring 的配置文件 5.1.6 DAO层设计 5.2 逻辑业务层设计 5.2.1 业务逻辑类的实现 前面内容请移步 基于java的C…

Jmeter干货分享:当你的Log viewer不显示日志时,可能是引入的Jar包冲突导致

问题描述 近期使用Jmeter时发现了一个非常奇怪的问题&#xff0c;就是Jmeter是可以正常使用运行脚本&#xff0c;但是在Log viewer中确没有任何日志&#xff0c;如下图&#xff1a; 问题排查过程 真是百思不得其解啊&#xff0c;在网上各种获取资料&#xff0c;大多数都是说跟…

001----flask

flask---001 flask与django对比今日概要问答今日详细1.flask快速使用1.2 快速使用flask1.3 用户名密码登录 flask与django对比 django是个大而全的框架&#xff0c;flask是一个轻量级的框架。 django内部为我们提供了非常多的组件&#xff1a;orm/session/cookie/admin/from/mo…

【学习】企业如何选择一个合适的DCMM咨询机构

DCMM是我国首个数据管理领域正式发布的国家标准。旨在帮助企业利用先进的数据管理理念和方法&#xff0c;建立和评价自身数据管理能力&#xff0c;持续完善数据管理组织、程序和制度&#xff0c;充分发挥数据在促进企业向信息化、数字化、智能化发展方面的价值。该标准借鉴了国…

Python学习从0开始——Kaggle机器学习003总结

Python学习从0开始——Kaggle机器学习003总结 一、加载及浏览数据二、机器学习模型三、模型验证四、欠拟合和过拟合五、随机森林 一、加载及浏览数据 # 路径 melbourne_file_path ../input/melbourne-housing-snapshot/melb_data.csv # 读取 melbourne_data pd.read_csv(mel…

为什么大家都要考CDA数据分析师认证

为什么学习数据分析&#xff1f; 2024年&#xff0c;是一个被数据影响的时代。数据&#xff0c;如同无形的燃料&#xff0c;驱动着现代社会的运转。从全球互联网的用户每天产生的2.5亿TB数据&#xff0c;到制造业的传感器、金融交易、医疗病历等领域的海量信息&#xff0c;数据…

排序算法——归并排序以及非递归实现

一、归并排序思想 归并排序&#xff08;MERGE-SORT&#xff09;是建立在归并操作上的一种有效的排序算法,该算法是采用分治法&#xff08;Divide andConquer&#xff09;的一个非常典型的应用。将已有序的子序列合并&#xff0c;得到完全有序的序列&#xff1b;即先使每个子序列…

使用Python绘制瀑布图

使用Python绘制瀑布图 瀑布图效果代码 瀑布图 瀑布图&#xff08;Waterfall Chart&#xff09;是一种数据可视化工具&#xff0c;用于展示累积数值的变化&#xff0c;尤其适合于展示随时间或过程中的增减变化。它通常用于财务分析&#xff0c;如展示收入、支出和净利润的变化过…