当前位置: 首页 > news >正文

【STM32 FreeRTOS】任务通知

任务通知简介

任务通知:用来通知任务的,任务控制块中的结构体成员变量ulNotifiedValue(32位)就是这个通知值。

	#if( configUSE_TASK_NOTIFICATIONS == 1 )volatile uint32_t ulNotifiedValue;volatile uint8_t ucNotifyState;#endif

任务控制块TCB里有两个成员变量,一个uint32_t的表示通知值,一个uint8_t的用来表示通知状态。

  • 使用队列、信号量、事件标志组时都需要另外创建一个结构体,通过中间的结构体进行间接通信。
  • 使用任务通知时,任务结构体TCB中就包含了内部对象,可以直接接收别人发过来的通知。

任务通知值的更新方式:

  • 不覆盖接收任务的通知值
  • 覆盖接收任务的通知值
  • 更新接收任务通知值的一个或多个bit
  • 增加接收任务的通知值

只要合理,灵活的利用任务通知的特点,可以在一些场合中替代队列、信号量和事件标志组。

任务通知的优势:

  • 效率更高:使用任务通知向任务发送事件或数据比使用队列、事件标志组或信号量快得多。
  • 使用内存更小:使用任务通知时无需额外创建结构体

任务通知的劣势:

  • 无法发送数据给ISR:ISR没有任务结构体,所以无法给ISR发送数据。但是ISR可以使用任务通知发数据给任务。
  • 无法广播给多个任务:任务通知只能是被指定的一个任务接收并处理。
  • 无法缓存多个数据:任务结构体中只有一个任务通知值,只能保存一个数据。
  • 发送受阻不支持阻塞:发送发无法进入阻塞状态等待。

任务通知状态:

#define taskNOT_WAITING_NOTIFICATION	( ( uint8_t ) 0 )
#define taskWAITING_NOTIFICATION		( ( uint8_t ) 1 )
#define taskNOTIFICATION_RECEIVED		( ( uint8_t ) 2 )
  • 任务未等待通知,任务通知默认的初始化状态
  • 等待通知,接收方已经准备好了(调用了接收任务通知函数),等待发送方发给个通知
  • 等待接收,发送方已经发送出去(调用了发送任务通知函数),等待接收方接收

任务通知相关API函数介绍

发送通知

函数描述
xTaskNotify发送通知,带有通知值
xTaskNotifyAndQuery发送通知,带有通知值并且保留接收任务的原有通知值
xTaskNotifyGive发送通知,不带通知值
xTaskNotifyFromISR
xTaskNotifyAndQueryFromISR
vTaskNotifyGiveFromISR

接收通知

函数描述
ulTaskNotifyTake获取任务通知,可以设置在退出该函数的时候将任务通知值清零或者减一。
xTaskNotifyWait获取任务通知,可获取通知值和清除通知值的指定位
  • 当任务通知用作于信号量时,使用ulTaskNotifyTake函数获取信号量。
  • 当任务用作于事件标志组或队列时,使用xTaskNotifyWait函数来获取。

模拟二值信号量和计数信号量

void StartMyTask1(void *argument)
{printf("StartMyTask1\r\n");uint32_t notify_value = 0;for(;;){//这里实际是取通知值,只要通知值大于0的时候就不会阻塞,可以执行到下面//第一个参数设置为true,表示执行完该函数后,会将通知值设置为0,//这意味着如果再没有接收通知,那么会一直阻塞在这里。//函数返回值,表示通知值再设置为0之前的值(一般情况下为1)notify_value = ulTaskNotifyTake(pdTRUE,portMAX_DELAY);if(0 != notify_value)printf("task1 notify_value=%d\r\n",notify_value);vTaskDelay(pdMS_TO_TICKS(500));//500ms}
}void NotifyMyTask1FromISR()
{printf("NotifyMyTask1FromISR\r\n");BaseType_t xHigherPriorityTaskWoken = pdFALSE;//这里是在中断服务函数中调用的vTaskNotifyGiveFromISR(myTask1Handle,&xHigherPriorityTaskWoken);portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
NotifyMyTask1FromISR
task1 notify_value=1
NotifyMyTask1FromISR
task1 notify_value=1
NotifyMyTask1FromISR
task1 notify_value=1
NotifyMyTask1FromISR
task1 notify_value=1
NotifyMyTask1FromISR
NotifyMyTask1FromISR
task1 notify_value=2
NotifyMyTask1FromISR
NotifyMyTask1FromISR
task1 notify_value=2
NotifyMyTask1FromISR
task1 notify_value=1
NotifyMyTask1FromISR
NotifyMyTask1FromISR
NotifyMyTask1FromISR
task1 notify_value=3
NotifyMyTask1FromISR
NotifyMyTask1FromISR
NotifyMyTask1FromISR
task1 notify_value=3

可以看到,正常情况下,执行一次NotifyMyTask1FromISR就会执行一次ulTaskNotifyTake。但是如果NotifyMyTask1FromISR函数执行的频率很快,ulTaskNotifyTake函数执行不过来,所以通知值不是1(执行通知函数的时候实际上是将通知值加一),ulTaskNotifyTake函数执行一次后还是会阻塞,因为执行一次后将通知值设置为0了。如果将ulTaskNotifyTake函数的第一个参数设置为pdFALSE,表示执行完后将通知值减一,这样其实就是模拟计数信号量了。

void StartMyTask1(void *argument)
{printf("StartMyTask1\r\n");uint32_t notify_value = 0;for(;;){//这里实际是取通知值,只要通知值大于0的时候就不会阻塞,可以执行到下面//第一个参数设置为false,表示执行完该函数后,会将通知值减1,//函数返回值,表示通知值在减1之前的值notify_value = ulTaskNotifyTake(pdFALSE,portMAX_DELAY);if(0 != notify_value)printf("task1 notify_value=%d\r\n",notify_value);vTaskDelay(pdMS_TO_TICKS(500));//500ms}
}
NotifyMyTask1FromISR
task1 notify_value=1
NotifyMyTask1FromISR
task1 notify_value=1
NotifyMyTask1FromISR
task1 notify_value=1
NotifyMyTask1FromISR
task1 notify_value=1
NotifyMyTask1FromISR
NotifyMyTask1FromISR
NotifyMyTask1FromISR
task1 notify_value=3
task1 notify_value=2
task1 notify_value=1

模拟消息邮箱

void NotifyMyTask1FromISR(uint32_t notify_value)
{printf("NotifyMyTask1FromISR\r\n");BaseType_t xHigherPriorityTaskWoken = pdFALSE;//这里是在中断服务函数中调用的//将参数值当作通知值发送给任务xTaskNotifyFromISR(myTask1Handle,notify_value,eSetValueWithOverwrite,&xHigherPriorityTaskWoken);portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}void StartMyTask1(void *argument)
{printf("StartMyTask1\r\n");uint32_t notify_value = 0;for(;;){//第一个参数表示接收前不清零通知值的bit//第二个参数表示接收后清零通知值的所有bitxTaskNotifyWait(0x00,0xFFFFFFFF,&notify_value,portMAX_DELAY);printf("task1 notify_value=%d\r\n",notify_value);vTaskDelay(pdMS_TO_TICKS(500));//500ms}
}
NotifyMyTask1FromISR
task1 notify_value=1
NotifyMyTask1FromISR
task1 notify_value=2
NotifyMyTask1FromISR
task1 notify_value=3
NotifyMyTask1FromISR
task1 notify_value=4

可以将参数作为通知值传递给任务。

模拟时间标志组

void NotifyMyTask1FromISR(uint32_t notify_value)
{//notify_value表示第几位设置为1,其实可以一次设置多位,这里不演示//notify_value == 2,则表示第二位置1,那么通知值 = (1<<2)printf("NotifyMyTask1FromISR\r\n");BaseType_t xHigherPriorityTaskWoken = pdFALSE;//模拟事件标志组其实就是利用通知值的每一位作为事件的Flag,//发送和接收的时候,都只是修改和判断对应bitxTaskNotifyFromISR(myTask1Handle,1<<notify_value,eSetBits,&xHigherPriorityTaskWoken);portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}void StartMyTask1(void *argument)
{printf("StartMyTask1\r\n");uint32_t notify_value = 0;for(;;){//第一个参数表示接收前不清零通知值的bit//第二个参数表示接收后清零通知值的所有bitxTaskNotifyWait(0x00,0xFFFFFFFF,&notify_value,portMAX_DELAY);printf("task1 notify_value=%d\r\n",notify_value);if((notify_value & (1<<0)) != 0){printf("bit0 event... \r\n");}else if((notify_value & (1<<1)) != 0){printf("bit1 event... \r\n");}else if((notify_value & (1<<2)) != 0){printf("bit2 event... \r\n");}vTaskDelay(pdMS_TO_TICKS(500));//500ms}
}
NotifyMyTask1FromISR
task1 notify_value=4
bit2 event... 
NotifyMyTask1FromISR
task1 notify_value=2
bit1 event... 
NotifyMyTask1FromISR
task1 notify_value=1
bit0 event... 
NotifyMyTask1FromISR
task1 notify_value=4
bit2 event... 

其实,关于xTaskNotifyWait函数的第二个参数,准确来说不是执行完xTaskNotifyWait函数后清零比特位,而是在下次给通知值赋值的时候吧???

相关文章:

【STM32 FreeRTOS】任务通知

任务通知简介 任务通知&#xff1a;用来通知任务的&#xff0c;任务控制块中的结构体成员变量ulNotifiedValue&#xff08;32位&#xff09;就是这个通知值。 #if( configUSE_TASK_NOTIFICATIONS 1 )volatile uint32_t ulNotifiedValue;volatile uint8_t ucNotifyState;#endi…...

51单片机学习

定时器流水灯 #include <REGX52.H> #include "Timer0.h" #include "Key.h" #include <INTRINS.H> unsigned char KeyNum,LEDMode; void main() { P20xFE; Timer0Init(); while(1) { KeyNumKey(); if(KeyNum)…...

vue项目实现postcss-pxtoremvue大屏适配

1.安装依赖 npm install postcss-pxtorem autoprefixer postcss-loader --save-dev # 或者 yarn add postcss-pxtorem autoprefixer postcss-loader --dev2.配置 PostCSS 在项目根目录下创建一个 .postcssrc.js 文件&#xff0c;并添加以下配置&#xff1a; module.exports …...

如何打造爆款游戏?开发由你操刀,运维交由我托管,合作共赢创造更大成功

Linode提供的云计算服务都有哪里的哪些人在用&#xff0c;又都用来做什么&#xff1f;简而言之&#xff1a;世界各地&#xff01;各行各业&#xff01;&#xff01;丰富多彩&#xff01;&#xff01;&#xff01; 今天我们将关注云计算在游戏行业的应用。在这篇文章里&#xf…...

颈部按摩仪语音播报芯片方案,高品质语音IC,NV080D

想要利用碎片化的时间按摩肩颈&#xff0c;颈部按摩仪是很好的选择。然而&#xff0c;随着科技的不断进步&#xff0c;一些新的技术也开始被应用于颈部按摩仪中&#xff0c;以提升它们的功能和用户体验。 例如&#xff0c;NV080D语音播放芯片在颈部按摩仪上的应用&#xff0c;…...

Opencv模板匹配

使用OpenCV和C来识别彩色图片中的特定物体&#xff0c;如黑桃♠&#xff0c;通常涉及几个步骤&#xff1a;预处理图像、特征提取、对象检测等。下面是一个基本的示例代码&#xff0c;演示如何使用OpenCV的模板匹配方法来识别图片中的黑桃♠。 函数原型 void matchTemplate(Inp…...

JavaScript DOM事件监听器:深入解析与实践应用

引言 在JavaScript中&#xff0c;DOM&#xff08;文档对象模型&#xff09;事件监听器是与用户交互的核心机制之一。它们允许开发者响应用户的行为&#xff0c;如点击、滚动、输入等&#xff0c;从而创建动态和交互式的网页。本文将深入探讨DOM事件监听器的工作原理、类型以及…...

iOS的App启动详细过程(底层知识)

1.虚拟内存 & ASLR 在早期计算机中数据是直接通过物理地址访问的&#xff0c;这就造成了下面两个问题 1.内存不够用 2.数据安全问题 内存不够 ---> 虚拟内存 虚拟内存就是通过创建一张物理地址和虚拟地址的映射表来管理内存&#xff0c;提高了CPU利用率&#xff0c;…...

【轨物推荐】创新者的钥匙:如何破解创新的最大难题

原创 混沌学园 混沌学园 2021年12月27日 19:55 本文重点在于&#xff0c;将纷繁复杂现象中&#xff0c;针对创新的灵魂问题“不创新是等死&#xff0c;创新是找死”&#xff0c;给出本质上的解读、解析和解答。将创新在保守和发散的两难选择中&#xff0c;下探本质找到那个价值…...

SpringCloud的能源管理系统-能源管理平台源码

介绍 基于SpringCloud的能源管理系统-能源管理平台源码-能源在线监测平台-双碳平台源码-SpringCloud全家桶-能管管理系统源码 软件架构...

Mybatis获取主键自增的方法

原本的方法 使用原本的JDBC去获取主键自增的方法如下图所示&#xff1a; 在这段代码中&#xff0c;通过连接对象 conn 的 prepareStatement 方法创建了一个PreparedStatement对象&#xff0c;并将SQL语句和 RETURN_GENERATED_KEYS 常量作为参数传递给该方法。这意味着执行SQL…...

strip 、objdump、objcopy 差异与区别

strip 、objdump、objcopy 差异与区别 strip 命令用于从已编译的可执行文件或目标文件中移除调试信息和其他非必要数据。这可以减小文件的大小&#xff0c;并且有助于保护源代码不被轻易反编译。通常&#xff0c;在发布软件时会使用 strip 命令来减少二进制文件的体积 objdump…...

本地phpstudy部署算命系统,用户端是H5页面,支持微信支付宝支付,支持微信支付宝登录

算命系统本地部署教程 0. 技术架构1. 启动Apache、MySQL服务2. 创建前台和后台两个网站3. Navicat连接数据库4. 登录后台是长这个样子5. 登录前台登录样子6. 代码结构是 0. 技术架构 前端&#xff1a;HTMLCSSJquery 后端&#xff1a;PHP 数据库&#xff1a;MySQL 1. 启动Ap…...

APP上架苹果App Store被拒原因及解决方案

苹果官方商店的审核大致分为三部分&#xff1a;预审、机审和人工审核&#xff0c;审核流程包括&#xff1a;初步提交、审核队列、审核过程、结果通知等步骤。#iOS App Store审核是非常严格的&#xff0c;很多很多APP&#xff0c;并不是能够一次上架成功&#xff0c;大部分APP都…...

docker-compose的下载

方式一&#xff1a;使用二进制文件安装。 GitHub官方下载安装&#xff08;推荐&#xff0c;速度慢但不会出错&#xff09; 1.GitHub官方下载&#xff08;测试&#xff0c;已成功&#xff09; curl -SL https://github.com/docker/compose/releases/download/v2.29.1/docker-c…...

h3c虚拟园区网概述

虚拟园区网概述 H3C虚拟园区网的解决方案 企业园区网作为企业网络的核心部分&#xff0c;连接了企业总部的办公、生产、研发、财务等多种重要的机 构。在网络建设中占有重要的地位。园区网内部终端种类众多,接入用户数量庞大,对网络的性能、可 靠性、可管理性都有较高的要求…...

云原生和安装Ubuntu 22系统

一.云原生简介 2004年开始&#xff0c;Google已在内部大规模地使用容器技术。 2008年&#xff0c;Google将 Cgroups合并进入了Linux内核。2013年&#xff0c;Docker项目正式发布。2014年&#xff0c;Kubernetes项目正式发布。2015年&#xff0c;由Google、Redhat 以及微软等大…...

HTTP代理IP如何助力旅游大数据领域?怎么建立安全的代理隧道连接?

在旅游行业&#xff0c;数据的准确性和实时性至关重要。随着大数据分析的兴起&#xff0c;HTTP代理IP成为了这一领域中不可或缺的工具。本文将探讨HTTP代理IP如何帮助旅游大数据领域&#xff0c;并介绍如何建立安全的代理隧道连接。 1. HTTP代理IP在旅游大数据领域的应用 1.1…...

AIGC从入门到实战:基础理论【核心算法与模型】

历史导读&#xff1a; 三、AIGC从入门到实战:基础理论【模型微调】 二、AIGC从入门到实战:AIGC基础理论 一、AIGC从入门到实战&#xff1a;为什么要了解AIGC 核心算法与模型 在人工智能生成内容(AIGC)领域&#xff0c;技术的飞速进步催生了一系列高效且创新的生成模型&…...

极狐GitLab 17.2发布了哪些 JH-Only 的功能?

极狐GitLab 是 GitLab 在中国的发行版&#xff0c;专门面向中国程序员和企业提供企业级一体化 DevOps 平台&#xff0c;用来帮助用户实现需求管理、源代码托管、CI/CD、安全合规&#xff0c;而且所有的操作都是在一个平台上进行&#xff0c;省事省心省钱。可以一键安装极狐GitL…...

四旋翼变形控制:RL与MPC在混合动力学中的对比

1. 四旋翼变形控制的技术挑战与解决方案四旋翼变形控制&#xff08;Quadrotor Morpho-Transition&#xff09;是当前机器人领域最具挑战性的前沿技术之一。这项技术使机器人能够在空中完成形态变换&#xff0c;实现从飞行模式到地面模式的平滑切换。想象一下&#xff0c;一架四…...

AArch64内存管理:MAIR_EL3寄存器详解与应用

1. AArch64内存管理基础与MAIR_EL3寄存器定位 在Armv8-A/v9-A架构中&#xff0c;内存管理单元(MMU)通过多级页表实现虚拟地址到物理地址的转换。当处理器执行内存访问时&#xff0c;MMU会遍历页表条目(Translation Table Entry)&#xff0c;其中包含两个关键信息&#xff1a;目…...

对称与负电源测试:动态直流电子负载的设计、原理与应用

1. 项目概述&#xff1a;对称与负电源的静态与动态直流负载在电子实验室里&#xff0c;测试一个电源的性能&#xff0c;尤其是它的动态响应能力&#xff0c;是件既基础又关键的事。我们常说的“直流电子负载”就是这个领域的核心工具。我之前设计并分享过一个用于正电源测试的静…...

森优时铁锌维发根养黑用三个月真实效果实测:内服营养养黑的客观测评

"森优时铁锌维发根养黑用三个月真实效果实测显示&#xff0c;针对压力、熬夜引发的早白问题&#xff0c;通过内服补充毛囊所需营养的方式&#xff0c;多数使用者能感受到发根韧性提升、新生发色素沉淀改善&#xff0c;整体改善效果因人而异&#xff0c;合规的营养补充是目…...

三步实现跨架构程序兼容:Box64高效架构转换指南

三步实现跨架构程序兼容&#xff1a;Box64高效架构转换指南 【免费下载链接】box64 Box64 - Linux Userspace x86_64 Emulator with a twist, targeted at ARM64, RV64 and LoongArch Linux devices 项目地址: https://gitcode.com/gh_mirrors/bo/box64 你是否曾在ARM64…...

37家金融客户紧急启用的DeepSeek扫描辅助加固包(含未公开API调用密钥策略)

更多请点击&#xff1a; https://kaifayun.com 第一章&#xff1a;DeepSeek漏洞扫描辅助的背景与战略价值 近年来&#xff0c;大模型在安全领域的应用正从辅助问答向深度协同防御演进。DeepSeek系列模型凭借其开源、高推理精度及强代码理解能力&#xff0c;成为构建智能化漏洞…...

通过curl命令快速测试Taotoken大模型API的连通性与返回格式

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 通过curl命令快速测试Taotoken大模型API的连通性与返回格式 在集成大模型能力到应用时&#xff0c;开发者通常需要一种快速、轻量的…...

3分钟掌握JetBrains IDE试用期重置:终极完整指南

3分钟掌握JetBrains IDE试用期重置&#xff1a;终极完整指南 【免费下载链接】ide-eval-resetter 项目地址: https://gitcode.com/gh_mirrors/id/ide-eval-resetter JetBrains IDE试用期重置工具&#xff08;ide-eval-resetter&#xff09;是一个开源项目&#xff0c;专…...

AI算法工程师如何进行模型部署?这2个工具+3个技巧,快速上线

对于软件测试从业者来说&#xff0c;模型部署并不是一个陌生的概念——随着AI功能逐渐渗透到各类应用软件中&#xff0c;测试工程师不仅需要验证模型输出的准确性&#xff0c;更需要理解部署流程对模型稳定性、响应速度和结果一致性的影响。很多测试同学会有这样的困惑&#xf…...

实测对比,使用Taotoken聚合接口后Agent任务延迟与稳定性观感

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 实测记录&#xff1a;使用 Taotoken 聚合接口后 Agent 任务延迟与稳定性观感 效果展示类&#xff0c;记录将原有基于单一 API 的 A…...