FreeRTOS CMSIS系列(6):任务通知详解
目录一、什么是任务通知二、任务通知值的更新方式三、任务通知的优势和劣势3-1 任务通知的优势3-2 任务通知的劣势四、任务通知相关 API 函数4-1 发送通知4-2 等待通知五、测试程序一、什么是任务通知FreeRTOS 从版本 V8.2.0 开始提供任务通知这个功能每个任务都有一个 32 位的通知值。按照 FreeRTOS官方的说法使用消息通知比通过二进制信号量方式解除阻塞任务快 45% 并且更加省内存无需创建队列。在大多数情况下任务通知可以替代二值信号量、计数信号量、事件标志组可以替代长度为 1 的队列可以保存一个 32 位整数或指针值并且任务通知速度更快、使用的RAM更少二、任务通知值的更新方式FreeRTOS提供以下几种方式发送通知给任务 1.发送消息给任务如果有通知未读 不覆盖通知值2.发送消息给任务直接覆盖通知值3.发送消息给任务设置通知值的一个或者多个位4.发送消息给任务递增通知值通过对以上方式的合理使用可以在一定场合下替代原本的队列、信号量、事件标志组等三、任务通知的优势和劣势3-1 任务通知的优势1. 使用任务通知向任务发送事件或数据比使用队列、事件标志组或信号量快得多。2. 使用其他方法时都要先创建对应的结构体使用任务通知时无需额外创建结构体。3-2 任务通知的劣势1. 只有任务可以等待通知中断服务函数中不可以因为中断没有 TCB 。2. 通知只能一对一因为通知必须指定任务。3. 等待通知的任务可以被阻塞 但是发送消息的任务任何情况下都不会被阻塞等待。4. 任务通知是通过更新任务通知值来发送数据的任务结构体中只有一个任务通知值只能保持一个数据。四、任务通知相关API函数4-1发送通知/* * -------------函数---------------------------------------描述------------------- *| xTaskNotify() | 发送通知带有通知值 *|------------------------------|---------------------------------------------- *| xTaskNotifyAndQuery() | 发送通知带有通知值并且保留接收任务的原通知值 *|------------------------------|---------------------------------------------- *| xTaskNotifyGive() | 发送通知不带通知值 *|------------------------------|---------------------------------------------- *| xTaskNotifyFromISR() | 在中断中发送任务通知 *|------------------------------|---------------------------------------------- *| xTaskNotifyAndQueryFromISR() | 在中断中发送任务通知 *|------------------------------|---------------------------------------------- *| vTaskNotifyGiveFromISR() | 在中断中发送任务通知 *|------------------------------|---------------------------------------------- * * *//* * 参数 * xTaskToNotify需要接收通知的任务句柄 * ulValue用于更新接收任务通知值 具体如何更新由形参 eAction 决定 * eAction一个枚举代表如何使用任务通知的值 * * * -------------枚举值-------------------------------描述------------------------ * | eNoAction | 发送通知但不更新值参数ulValue未使用 * |------------------------------|---------------------------------------------- * | eSetBits | 被通知任务的通知值按位或ulValue。某些场景下可代替事件组效率更高 * |------------------------------|---------------------------------------------- * | eIncrement | 被通知任务的通知值增加1参数ulValue未使用相当于xTaskNotifyGive * |------------------------------|---------------------------------------------- * | eSetValueWithOverWrite | 被通知任务的通知值设置为 ulValue。某些场景下可代替xQueueOverwrite 效率更高 * |------------------------------|---------------------------------------------- * | eSetValueWithoutOverwrite | 如果被通知的任务当前没有通知则被通知的任务的通知值设为ulValue。如果被通知任务没有取走上一个通知又接收到了一个通知则这次通知值丢弃在这种情况下视为调用失败并返回 pdFALSE某些场景下可代替 xQueueSend 效率更高 * |------------------------------|---------------------------------------------- * * 返回值: * 如果被通知任务还没取走上一个通知又接收了一个通知则这次通知值未能更新并返回 pdFALSE 而其他情况均返回pdPASS。 * * * * BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify,uint32_t ulValue,eNotifyAction eAction ); * * *//* * 参数 * xTaskToNotify需要接收通知的任务句柄 * ulValue用于更新接收任务通知值 具体如何更新由形参 eAction 决定 * eAction一个枚举代表如何使用任务通知的值 * pulPreviousNotifyValue对象任务的上一个任务通知值如果为 NULL 则不需要回传 这个时候就等价于函数 xTaskNotify()。 * * 返回值 * 如果被通知任务还没取走上一个通知又接收了一个通知则这次通知值未能更新并返回 pdFALSE 而其他 * 情况均返回pdPASS。 * * * BaseType_t xTaskNotifyAndQuery( TaskHandle_t xTaskToNotify,uint32_t ulValue,eNotifyAction eAction,uint32_t *pulPreviousNotifyValue ); * * *//* * 参数 * xTaskToNotify接收通知的任务句柄 并让其自身的任务通知值加 1。 * 返回值 * 总是返回 pdPASS。 * * BaseType_t xTaskNotifyGive( TaskHandle_t xTaskToNotify ); * * */4-2等待通知等待通知API函数只能用在任务不可应用于中断中/* * -------------函数-------------------------------描述------------------------ * | ulTaskNotifyTake() | 获取任务通知可以设置在退出此函数的时候将任务通知值清零或者减一。当任务通知用作二值信号量或者计数信号量的时候使用此函数来获取信号量。 * |------------------------------|---------------------------------------------- * | xTaskNotifyWait() | 获取任务通知比 ulTaskNotifyTak()更为复杂可获取通知值和清除通知值的指定位 * |------------------------------|---------------------------------------------- * * *//* * 参数 * xClearCountOnExit指定在成功接收通知后将通知值清零或减 1pdTRUE把通知值清零二值信号量pdFALSE把通知值减一计数型信号量 * xTicksToWait阻塞等待任务通知值的最大时间 * * 返回值 * 0接收失败 * 非0接收成功返回任务通知的通知值 * * * uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit,TickType_t xTicksToWait ); * * * *//* * BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry,uint32_t ulBitsToClearOnExit,uint32_t *pulNotificationValue,TickType_t xTicksToWait ); * * * ulBitsToClearOnEntry函数执行前清零任务通知值那些位 。 * ulBitsToClearOnExit表示在函数退出前清零任务通知值那些位在清 0 前接收到的任务通知值会先被 * 保存到形参*pulNotificationValue 中。 * pulNotificationValue用于保存接收到的任务通知值。 如果 不需要使用则设置为 NULL 即可 。 * xTicksToWait等待消息通知的最大等待时间。 * * * */五、测试程序#include wu_task.h /* * FreeRTOS中任务共存在4种状态: 1Running 运行态 --------------------------当任务处于实际运行状态称之为运行态即CPU的使用权被这个任务占用同一时间仅一个任务处于运行态。 2Ready 就绪态 --------------------------处于就绪态的任务是指那些能够运行没有被阻塞和挂起但是当前没有运行的任务因为同优先级或更高优先级的任务正在运行。 3Blocked 阻塞态 --------------------------如果一个任务因延时或等待信号量、消息队列、事件标志组等而处于的状态被称之为阻塞态。 4Suspended 挂起态 --------------------------类似暂停通过调用函数 vTaskSuspend() 对指定任务进行挂起挂起后这个任务将不被执行只有调用函数 xTaskResume() 才可以将这个任务从挂起态恢复。 * * 常用的一些函数用法: * osThreadSuspend(WUTask02Handle);//挂起态 暂停任务 * osThreadResume(WUTask02Handle);//就绪态 恢复任务 * osThreadTerminate(defaultTaskHandle);//删除任务 终止一个线程的执行并将其从活动线程中移除 * * * */ extern osMessageQId WUQueue01Handle;//声明一个外部的信号量队列消息队列 extern osSemaphoreId WUBinarySem01Handle;//声明一个外部的二进制信号量句柄 extern osSemaphoreId WUCountingSem01Handle;//声明一个外部的计数信号量句柄 extern osMutexId WUMutex01Handle;//声明一个外部的互斥锁互斥量 EventGroupHandle_t eventgroup_handle;// 声明事件组句柄 //WUBinarySem01Handle xSemaphoreCreateBinary(); u8 wu_cs5; u8 d1,d2; uint16_t buf 100; // 声明一个事件位变量初始值为0 EventBits_t wu_bit 0; void WU_Task_1(viod) { BaseType_t status; if(click()1) { wu_cs;buf123; // status xQueueSend(WUQueue01Handle, buf, 0);//写入队列 // if (status pdTRUE) // d11; // else // d10; // if (xSemaphoreGive(WUBinarySem01Handle) pdTRUE) // d11; // else // d10; // if (xSemaphoreGive(WUCountingSem01Handle) pdTRUE) // d11; // else // d10; // xEventGroupSetBits(eventgroup_handle, 0x01);// KEY1 按下 xTaskNotifyGive(WUBinarySem01Handle);//任务通知模拟二值信号量发送成功 Seria1_Printf(TXD:任务通知模拟二值信号量发送成功); } // xSemaphoreTake(WUMutex01Handle, portMAX_DELAY); // Seria1_Printf(TaskH: ON! \r\n); // HAL_Delay(1000); // //osDelay(1000); // Seria1_Printf(TaskH: OK! \r\n); // xSemaphoreGive(WUMutex01Handle); // osDelay(1000); } void WU_Task_2(viod) { LED_GREEN_TogglePin; osDelay(1000); // Seria1_Printf(TaskM: CPU-STOP!!! \r\n); // osDelay(1000); // wu_bit xEventGroupWaitBits(eventgroup_handle, 0x01 | 0x02, pdTRUE, pdFALSE, portMAX_DELAY); // Seria1_Printf(wu_bit:%#x\r\n, wu_bit); } void WU_Task_3(viod) { BaseType_t status; uint32_t ydd 0; if(click_2()1) { wu_cs--; // status xQueueReceive(WUQueue01Handle, buf, 0);//读取队列 // if (status pdTRUE) // d21; // else // d20; // if(xSemaphoreTake(WUBinarySem01Handle, portMAX_DELAY ) pdTRUE) // d21; // else // d20; // if (xSemaphoreTake(WUCountingSem01Handle, 0 ) pdTRUE) // d21; // else // d20; // xEventGroupSetBits(eventgroup_handle, 0x02);// KEY2 按下 ydd ulTaskNotifyTake(pdTRUE, portMAX_DELAY); if(ydd ! 0) Seria1_Printf(RXD:任务通知模拟二值信号量接收成功\r\n); } // xSemaphoreTake(WUMutex01Handle, portMAX_DELAY); // Seria1_Printf(TaskL: ON! \r\n); // HAL_Delay(3000); // //osDelay(3000); // Seria1_Printf(TaskL: OK! \r\n); // xSemaphoreGive(WUMutex01Handle); // osDelay(1000); } void WU_Task_4(viod) { //Seria1_Printf(WU); //Wu_xsp_Proc(); //Wu_Mai_Proc(); Wu_Led_Proc(); Wu_Key_Proc(); WU_OLED_U8G2_ClearBuffer(); WU_OLED_U8G2_SetFont(u8g2_font_wqy13_t_gb2312a);//选择字库 // WU_OLED_U8G2_Printf(0,15,CHINA,温度:%d℃,16); // WU_OLED_U8G2_Printf(0,30,CHINA,湿度:%d,58); // // d1?WU_OLED_U8G2_Printf(0,45,CHINA,写入队列值:%d,buf):WU_OLED_U8G2_Printf(0,45,CHINA,写入队列失败); // d2?WU_OLED_U8G2_Printf(0,60,CHINA,读取队列值:%d,buf):WU_OLED_U8G2_Printf(0,60,CHINA,读取队列失败); WU_OLED_U8G2_SendBuffer(); } void StartTask02(void const * argument) { while(1) { WU_Task_2(); } }参考资料1. FreeRTOS官方文档https://www.freertos.org/2. STM32 HAL库开发手册本文为个人学习笔记整理仅供学习交流使用。

相关新闻

SVD揭秘推荐背后的兴趣密码

SVD揭秘推荐背后的兴趣密码

一、假设你刚刚刷了三条视频 你的行为是: FPS 枪法教学 → 看完,还点了赞 游戏装备评测 → 看完 蛋糕制作教程 → 很快划走现在系统要决定:下一条给你推荐什么?最直接的方法是:继续推荐游戏视频。 但系统怎么从海量观看…

2026/10/12 4:25:38 阅读更多 →
602 蓝牙耳机使用WSDF5361锂保芯片进入船运模式实现方法

602 蓝牙耳机使用WSDF5361锂保芯片进入船运模式实现方法

耳机经过锂电池保护,电池供电,发24个脉冲进船运模式后,可以用充电5V脉冲激活才能启动。所以电路是经过锂电池保护的。为什么写了25个脉冲还是没有进入船运模式?什么原因?GPIO测量,可以产生高电平3V, 低电平…

2026/10/12 4:25:38 阅读更多 →
Xilem 构建压力测试指南:用 `cargo rustc` 与 `compile_stress_test` 度量 Rust UI 框架的编译性能

Xilem 构建压力测试指南:用 `cargo rustc` 与 `compile_stress_test` 度量 Rust UI 框架的编译性能

前端桌面应用 【免费下载链接】xilem An experimental Rust native UI framework 项目地址: https://gitcode.com/gh_mirrors/xil/xilem 点击查看 免费下载 Xilem 是一个高度依赖 Rust 泛型与类型系统组合的实验性原生 UI 框架,其声明式 view 树在编译期…

2026/10/12 4:25:38 阅读更多 →

最新新闻

递归函数与软件测试实战:从组合优化到协议生成的工程实践

递归函数与软件测试实战:从组合优化到协议生成的工程实践

我有个挺扎心的项目经验:一个软件测试工程师,被塞了个需求,要写代码自动生成离婚协议里的房产分割条款,核心算法用的是递归函数。乍一听像段子,但真做起来,我发现这项目正好把“递归”和“软件测试”这两个…

2026/10/12 5:48:25 阅读更多 →
自动化测试维护陷阱:从选择器稳定性到AI生成代码的避坑指南

自动化测试维护陷阱:从选择器稳定性到AI生成代码的避坑指南

1. 维护陷阱的底层逻辑:自动化测试从资产到负债的转折点我见过太多自动化测试项目,头两个月跑得轰轰烈烈,到了第四个月就开始人人喊打。原因不是测试写得不认真,而是大家普遍低估了一件事:自动化测试的真正成本不在编写…

2026/10/12 5:48:25 阅读更多 →
Maven安装配置与Idea集成实战:从环境变量到依赖管理

Maven安装配置与Idea集成实战:从环境变量到依赖管理

写这篇文章的起因很简单:这些年我见过太多人在 Maven 配置上栽跟头,明明只是二三十分钟能搞定的事,硬是折腾一整天。环境变量写错、settings 没配、Idea 里指错了版本,每一步都有坑,而且报错信息对新手极不友好。所以我…

2026/10/12 5:48:25 阅读更多 →
Abaqus隧道开挖模拟实战:双洞、双盾构、小净距与连拱隧道建模要点

Abaqus隧道开挖模拟实战:双洞、双盾构、小净距与连拱隧道建模要点

一提到Abaqus隧道开挖模拟,很多刚接触的同行第一反应是:不就是把土体单元Remove掉、衬砌单元Add回来嘛?真到自己上手做双洞隧道、双盾构隧道、小净距隧道或者连拱隧道的时候,才会发现完全不是这么回事。双洞涉及先后洞顺序&#x…

2026/10/12 5:48:25 阅读更多 →
AI应用工程化补零件:数据管道、推理调度与上下文管理

AI应用工程化补零件:数据管道、推理调度与上下文管理

1. 这期周报里藏着的两条暗线每周翻热门项目榜,大部分人看的是"哪个 star 涨得快",但我更习惯先看这批项目在解决什么共性问题。10 月 7 日这一周的热门榜单里,有个现象挺有意思:四个项目都在做同一件事——给 AI 系统补…

2026/10/12 5:48:25 阅读更多 →
你的项目不是一次性的:vibe-vibe 迭代思维实战指南——从“做完“到“好用“

你的项目不是一次性的:vibe-vibe 迭代思维实战指南——从“做完“到“好用“

文档教程Vibe Coding示例工程 【免费下载链接】vibe-vibe The First Systematic Vibe Coding Open-Source Tutorial | From Zero to Full-Stack, Empowering Everyone to Build Products with AI | Live at: www.vibevibe.cn ;首个系统化 Vibe Coding 开源教程 | 零…

2026/10/12 5:47:24 阅读更多 →

日新闻

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

在数码相机、高清显示屏与现代矢量图形技术高度发达的今天,画面可以做到绝对的锐利、平滑与无瑕。然而,当一张秋日手账插画或拍立得照片过于“平整无瑕”时,往往会散发出一种冰冷生硬的“数码塑料感(Digital Plasticity&#xff0…

2026/10/12 0:00:59 阅读更多 →
活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

在现代网页与移动端设计中,横排(Horizontal Layout)早已经成为了绝对的主流。然而,当我们翻开泛黄的线装古籍、宋版木刻诗集,或是欣赏一张茶道雅集的手写便签时,那种**自上而下纵向书写、自右向左逐列铺展&…

2026/10/12 0:00:59 阅读更多 →
周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

每到周日的晚上八点到十点,很多人心里都会悄悄亮起一盏警示灯。 在心理学上,这种现象有一个专门的称谓——“周日夜晚焦虑症(Sunday Scaries)”。明天又是周一,闹钟又要重新在七点响彻卧房;脑海里仿佛有一个…

2026/10/12 0:00:59 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/12 0:16:30 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/12 0:16:43 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 10:45:37 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:53 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:54 阅读更多 →