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);// 创建任务1xTaskCreate(Task1, "Task1", 1000, NULL, 1, &Task1Handle);// 创建任务2xTaskCreate(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_VALUExTaskNotify(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.mzph.cn/web/21571.shtml

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

相关文章

This may be due to a blocked port, missing dependencies

安装XAMPPXAMPP之后启动mysql出现如下问题&#xff0c;只需双击XAMPP安装目录下的setup_xampp&#xff0c;等待运行完毕。 重启&#xff0c;双击xampp-control. 重新进入xampp控制界面&#xff0c;点击start。

Python私教张大鹏万字长文讲解Tailwindcss Flex 和 Grid 布局相关的样式,附完整源码和效果截图

flex-basics 样式类 Utilities for controlling the initial size of flex items. 用于控制伸缩项的初始大小的实用程序。 基础样式 ClassPropertiesbasis-0flex-basis: 0px;basis-1flex-basis: 0.25rem; /* 4px */basis-2flex-basis: 0.5rem; /* 8px */basis-3flex-basis:…

JDBC 学习笔记(一)基础篇 - JDBC 搭建的六大步骤

JDK 版本使用&#xff1a;JDK 21 框架思想&#xff1a;实体类及ORM思想 反射技术&#xff1a;BaseDAO 封装的过程 解决现有问题的角度&#xff0c;主要是 JDBC的基础应用 一、、JDBC 可以解决的问题 1.1 数据存储的问题 解决数据长期的存储问题&#xff1a; 数据通过 I/O 流…

城市之旅:使用 LLM 和 Elasticsearch 简化地理空间搜索(一)

作者&#xff1a;来自 Elastic Philipp Kahr, Valentin Crettaz 这篇博文的本地部署实践 Jupyter notebook 请详细阅读文章 “城市之旅&#xff1a;使用 LLM 和 Elasticsearch 简化地理空间搜索&#xff08;二&#xff09;”。 探索如何从自然语言提问创建地理空间搜索。在下…

最新鸿蒙南北开发学习路线+学习资料分享

前言 5月29日&#xff0c;“千帆竞发启航 共筑鸿蒙生态”鸿蒙原生应用合作仪式在北京成功举办&#xff0c;近40个应用现场官宣启动鸿蒙原生应用开发。此次官宣启动开发的鸿蒙原生应用不仅包括教育、母婴、出行、医疗健康等多领域的知名应用&#xff0c;还有十多家企业内部办公应…

OverlayFS在嵌入式系统中的应用

文章目录 抛出问题基本概念使用场景OverlayFS的详细介绍框架目录合并修改文件删除文件添加文件小结 OverlayFS在嵌入式系统中的应用内核配置OverlayFS简单应用OverlayFS应用新思路 总结 环境介绍 硬件&#xff1a;T113平台 软件&#xff1a;Tina5.0 SDK&#xff08;使用的build…

【第3章】SpringBoot实战篇之登录接口(含JWT和拦截器)

文章目录 前言一、JWT1. 什么是JWT2. 使用场景3. 结构3.1 Header3.2 Payload3.3 Signature 4. 使用 二、案例1.引入库2.JwtUtils3. UserController14. ArticleController 三、拦截器1. 定义拦截器2. 注册拦截器 四、测试1. 登录2. 无token3. 有token4. 全局配置 总结 前言 前面…

485通讯网关

在工业自动化与智能化的浪潮中&#xff0c;数据的传输与交互显得尤为重要。作为这一领域的核心设备&#xff0c;485通讯网关凭借其卓越的性能和广泛的应用场景&#xff0c;成为了连接不同设备、不同协议之间数据转换和传输的桥梁。在众多485通讯网关中&#xff0c;HiWoo Box以其…

postman教程-10-使用cookie

领取资料&#xff0c;咨询答疑&#xff0c;请➕wei: June__Go 上一小节我们学习了Postman Authorization授权的几种方法&#xff0c;本小节我们讲解一下Postman 使用cookie的方法。 Postman 的 cookie 管理器使您能够查看和编辑与不同域关联的 cookie。您可以为域手动创建 c…

软件测试、测试模型、测试用例

软件开发的五个模型 瀑布模型&#xff08;Waterfall Model&#xff09; 瀑布模型是所有其他模型的基础框架&#xff0c;瀑布模型的每个阶段都只执行一次&#xff0c;因此是线性顺序进行的开发模式优点&#xff1a;强调开发的阶段性&#xff1b; 强调早期计划及需求调查&#…

【Python实战】使用postman测试flask api接口

cookie_demo.py # -*- coding: utf-8 -*- """ Time : 2024/5/28 17:14 Author : 娜年花开 File : cookie_demo.py Desc : 需求&#xff1a;用户需要先登陆&#xff0c;登陆之后&#xff0c;通过Cookie来判断是不是能够访问登录后的接口userinfo &quo…

TMS FNC WX Pack TMS软件分发的一组应用程序

TMS FNC WX Pack TMS软件分发的一组应用程序 TMS FNC WX Pack是由TMS软件分发的一组应用程序。这些活动是100%的跨平台和跨Frimorc&#xff0c;并在不同的应用程序中得到支持&#xff0c;如Web应用程序、Windows、Linux等。阿拉伯语视觉组件库。安装这些计算机的过程非常简单高…

第四讲 单片机STC89C52+RA8889代码移植范例(包含API接口)

本次介绍单片机STC89C52RA8889代码移植范例&#xff0c;该范例已将RA8889的API移植好了&#xff0c;下方提供下载地址。 硬件平台&#xff1a;89C52RA8889 采用SPI通信方式 (已测试通过&#xff09; 上一讲已经阐述RA8889移植到51单片机的基本方法&#xff0c;本讲增加了API…

【第一节】数据结构和算法绪论

目录 一、数据结构的起源与发展 二、什么是数据结构 三、数据的逻辑结构和存储结构 四、数据类型和数据结构 五、算法 六、算法与数据结构的关系 七、算法时间复杂度和空间复杂度 一、数据结构的起源与发展 数据结构的起源可以追溯至1968年。当时&#xff0c;美国的唐欧…

Spring Security 注册过滤器注意事项

前两天和小伙伴聊了 Spring SecurityJWT 实现无状态登录&#xff0c;然后有小伙伴反馈了一个问题&#xff0c;感觉这是一个我们平时写代码容易忽略的问题&#xff0c;写一篇文章和小伙伴们聊一聊。 一 问题复原 先来说问题吧&#xff0c;在 Spring SecurityJWT 登录中&#x…

C++入门5——C/C++动态内存管理(new与delete)

目录 1. 一图搞懂C/C的内存分布 2. 存在动态内存分配的原因 3. C语言中的动态内存管理方式 4. C内存管理方式 4.1 new/delete操作内置类型 4.2 new/delete操作自定义类型 1. 一图搞懂C/C的内存分布 说明&#xff1a; 1. 栈区&#xff08;stack&#xff09;&#xff1a;在…

【C语言】位段(结构体实现位段)

目录 一、位段的定义 二、位段的声明 三、位段的内存分配 四、位段在内存中的存储方式 五、位段的优点 六、位段的跨平台问题 七、位段的应用 八、位段使用的注意事项 一、位段的定义 信息的存取一般以字节为单位。实际上&#xff0c;有时存储一个信息不必用一个或多个字…

匠心独运,B 端系统 UI 演绎华章之美

匠心独运&#xff0c;B 端系统 UI 演绎华章之美

上位机图像处理和嵌入式模块部署(f103 mcu获取唯一id)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 对于stm32f103系列mcu来说&#xff0c;一般每一颗原厂的mcu&#xff0c;都会对应一个唯一的id。那这个id可以用来做什么用呢&#xff1f;个人认为&…

PX4 ROS2 真机

如果仿真跑通了。 真机遇到问题&#xff0c;可参考此文章。 ubuntu22 px4 1.14.3 ros2 humble 硬件接线。 先找两个usb - ttl串口&#xff0c;分别接到两台主机上&#xff0c;保证串口通信正常。 图中是个六合一的。浪费一天时间&#xff0c;发现是串口设置错误&#xff…