16.FreeRTOS直接任务通知 Notification

2024-06-03 22:20

本文主要是介绍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 调用,任务可以发送和接收直接任务通知,从而实现灵活的任务管理和事件触发。

这篇关于16.FreeRTOS直接任务通知 Notification的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1028273

相关文章

Spring定时任务只执行一次的原因分析与解决方案

《Spring定时任务只执行一次的原因分析与解决方案》在使用Spring的@Scheduled定时任务时,你是否遇到过任务只执行一次,后续不再触发的情况?这种情况可能由多种原因导致,如未启用调度、线程... 目录1. 问题背景2. Spring定时任务的基本用法3. 为什么定时任务只执行一次?3.1 未启用

如何使用Python实现一个简单的window任务管理器

《如何使用Python实现一个简单的window任务管理器》这篇文章主要为大家详细介绍了如何使用Python实现一个简单的window任务管理器,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起... 任务管理器效果图完整代码import tkinter as tkfrom tkinter i

Spring Boot 集成 Quartz 使用Cron 表达式实现定时任务

《SpringBoot集成Quartz使用Cron表达式实现定时任务》本文介绍了如何在SpringBoot项目中集成Quartz并使用Cron表达式进行任务调度,通过添加Quartz依赖、创... 目录前言1. 添加 Quartz 依赖2. 创建 Quartz 任务3. 配置 Quartz 任务调度4. 启

Java使用多线程处理未知任务数的方案介绍

《Java使用多线程处理未知任务数的方案介绍》这篇文章主要为大家详细介绍了Java如何使用多线程实现处理未知任务数,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 知道任务个数,你可以定义好线程数规则,生成线程数去跑代码说明:1.虚拟线程池:使用 Executors.newVir

Spring Boot中定时任务Cron表达式的终极指南最佳实践记录

《SpringBoot中定时任务Cron表达式的终极指南最佳实践记录》本文详细介绍了SpringBoot中定时任务的实现方法,特别是Cron表达式的使用技巧和高级用法,从基础语法到复杂场景,从快速启... 目录一、Cron表达式基础1.1 Cron表达式结构1.2 核心语法规则二、Spring Boot中定

Android 悬浮窗开发示例((动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

《Android悬浮窗开发示例((动态权限请求|前台服务和通知|悬浮窗创建)》本文介绍了Android悬浮窗的实现效果,包括动态权限请求、前台服务和通知的使用,悬浮窗权限需要动态申请并引导... 目录一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后

Spring Boot 整合 ShedLock 处理定时任务重复执行的问题小结

《SpringBoot整合ShedLock处理定时任务重复执行的问题小结》ShedLock是解决分布式系统中定时任务重复执行问题的Java库,通过在数据库中加锁,确保只有一个节点在指定时间执行... 目录前言什么是 ShedLock?ShedLock 的工作原理:定时任务重复执行China编程的问题使用 Shed

一文详解Java Condition的await和signal等待通知机制

《一文详解JavaCondition的await和signal等待通知机制》这篇文章主要为大家详细介绍了JavaCondition的await和signal等待通知机制的相关知识,文中的示例代码讲... 目录1. Condition的核心方法2. 使用场景与优势3. 使用流程与规范基本模板生产者-消费者示例

Python Invoke自动化任务库的使用

《PythonInvoke自动化任务库的使用》Invoke是一个强大的Python库,用于编写自动化脚本,本文就来介绍一下PythonInvoke自动化任务库的使用,具有一定的参考价值,感兴趣的可以... 目录什么是 Invoke?如何安装 Invoke?Invoke 基础1. 运行测试2. 构建文档3.

解决Cron定时任务中Pytest脚本无法发送邮件的问题

《解决Cron定时任务中Pytest脚本无法发送邮件的问题》文章探讨解决在Cron定时任务中运行Pytest脚本时邮件发送失败的问题,先优化环境变量,再检查Pytest邮件配置,接着配置文件确保SMT... 目录引言1. 环境变量优化:确保Cron任务可以正确执行解决方案:1.1. 创建一个脚本1.2. 修