FREERTOS任务通知

news2024/11/24 10:25:53

v8.2.0 版本开始,FreeRTOS 新增了任务通知(Task Notifictions)这个功能,可以使用任务通知来代替信号量、消息队列、事件标志组等这些东西。使用任务通知的话效率会更高。

有个疑惑:

队列是两个互通消息的任务之外的一个特性,而任务通知是任务本身的属性,如何合理地使用呢?比如任务A向任务B发消息,用队列的话,就是两个任务都可以操作这个队列;但如果是任务通知,消息传递时,用的是任务A的任务通知还是任务B的任务通知呢?

任务通知简介 

任务通知在 FreeRTOS 中是一个可选的功能,要使用任务通知的话就需要将宏configUSE_TASK_NOTIFICATIONS 定义为 1

FreeRTOS 的每个任务都有一个 32 位的通知值,任务控制块中的成员变量 ulNotifiedValue就是这个通知值。任务通知是一个事件,假如某个任务通知的接收任务因为等待任务通知而阻塞的话,向这个接收任务发送任务通知以后就会解除这个任务的阻塞状态。也可以更新接收任务的任务通知值,任务通知更新时可以有如下几种选项:

● 更新时不覆盖接收任务的通知值(如果上次发送给接收任务的通知还没被处理)

● 更新时覆盖接收任务的通知值。

● 更新时更新接收任务通知值的一个或多个 bit

● 更新时增加接收任务的通知值。

合理、灵活的使用上面这些更改任务通知值的方法可以在一些场合中替代队列、二值信号量、计数型信号量和事件标志组。使用任务通知来实现二值信号量功能的时候,解除任务阻塞的时间比直接使用二值信号量要快 45%(FreeRTOS 官方测试结果,使用 v8.1.2 版本中的二值信号量,GCC 编译器,-O2 优化的条件下测试的,没有使能断言函数 configASSERT()),并且使用的 RAM 更少! 这是因为任务通知是任务控制块本身的特征,而不必额外使用队列,因此也就省去了创建队列时使用的空间。

任务通知的发送使用函数 xTaskNotify()或者 xTaskNotifyGive()(还有此函数的中断版本)来完成,这个通知值会一直被保存着,直到接收任务调用函数 xTaskNotifyWait()或者 ulTaskNotifyTake()来获取这个通知值。假如接收任务因为等待任务通知而阻塞的话那么在接收到任务通知以后就会解除阻塞态。

任务通知虽然可以提高速度,并且减少 RAM 的使用,但是任务通知也是有使用限制的:

FreeRTOS 的任务通知只能有一个接收任务,其实大多数的应用都是这种情况。

● 接收任务可以因为接收任务通知而进入阻塞态,但是发送任务不会因为任务通知发送失败而阻塞。

任务通知是任务控制块本身的内容,创建任务时已经有了,所以不必再次专门创建。

发送任务通知

任务通知发送函数有 6 个,如下表所示:

函数 xTaskNotify()

此函数用于发送任务通知,此函数发送任务通知的时候带有通知值,此函数是个宏,真正执行的函数 xTaskGenericNotify(),函数原型如下:

某个任务中,调用该函数,向某个指定的任务发送指定的任务通知值,并指定更新的方式。当通知的方式不同时,就可以模拟队列、二值信号量、计数型信号量和事件标志组。后续详细说明。

函数 xTaskNotifyGive()

发送任务通知,相对于函数 xTaskNotify(),此函数发送任务通知的时候不带有通知值。此函数只是将任务通知值简单的加一,此函数是个宏,真正执行的是函数 xTaskGenericNotify()

此函数原型如下:

疑惑:

这个函数和xTaskNotify函数在选择“通知值+1”时有何区别?一个带通知值,一个不带通知值?既然xTaskNotify是“通知值+1”,那带的通知值有什么用?

函数 xTaskNotifyAndQuery()

此函数和 xTaskNotify()很类似,此函数比 xTaskNotify()多一个参数,此参数用来保存更新前的通知值。此函数是个宏,真正执行的是函数 xTaskGenericNotify(),此函数原型如下: 

任务通知发送函数解析

我们学习了 3 个任务级任务通知发送函数:xTaskNotify()xTaskNotifyGive() xTaskNotifyAndQuery(),这三个函数最终调用的都是函数 xTaskGenericNotify()!此函数在文件 tasks.c 中定义,可自行查阅源码。

大致实现流程如下所述:

(1)、判断参数 pulPreviousNotificationValue 是否有效,因为此参数用来保存更新前的任务通知值。

(2)、如果参数 pulPreviousNotificationValue 有效的话就用此参数保存更新前的任务通知值。

(3)、保存任务通知状态,因为下面会修改这个状态,后面我们要根据这个状态来确定是否将任务从阻塞态解除。

(4)、更新任务通知状态为 taskNOTIFICATION_RECEIVED

(5)、根据不同的更新方式做不同的处理,如果为 eSetBits 的话就将指定的 bit 1。也就是更新接收任务通知值的一个或多个 bit

(6)、如果更新方式为 eIncrement 的话就将任务通知值加一。

(7)、如果更新方式为 eSetValueWithOverwrite 的话就直接覆写原来的任务通知值。

(8)、如果更新方式为 eSetValueWithoutOverwrite 的话就需要判断原来的任务通知值是否被处理(保存起来),如果已经被处理(保存起来)了就更新为任务通知值。如果此前的任务通知值话没有被处理(保存起来)的话就标记 xReturn pdFAIL,后面会返回这个值。

(9)、根据(3)中保存的接收任务之前的状态值来判断是否有任务需要解除阻塞,如果在任务通知值被更新前任务处于 taskWAITING_NOTIFICATION 状态的话就说明有任务因为等待任务通知值而进入了阻塞态。

(10)、将任务从状态列表中移除。

(11)、将任务重新添加到就绪列表中。

(12)、判断刚刚解除阻塞的任务优先级是否比当前正在运行的任务优先级高,如果是的话需要进行一次任务切换。

(13)、返回 xReturn 的值,pdFAIL pdPASS

发送通知后,接收任务就可以开始接收任务通知了。

获取任务通知

获取任务通知的函数有两个,如下表所示:

函数 ulTaskNotifyTake()

此函数为获取任务通知函数,当任务通知用作二值信号量或者计数型信号量的时候可以使用此函数来获取信号量,函数原型如下:

此函数在文件 tasks.c 中有定义,大致实现过程如下:

(1)、判断任务通知值是否为 0,如果为 0 的话说明还没有接收到任务通知。

(2)、修改任务通知状态为 taskWAITING_NOTIFICATION

(3)、如果阻塞时间不为 0 的话就将任务添加到延时列表中,并且进行一次任务调度。

(4)、如果任务通知值不为 0 的话就先获取任务通知值。

(5)、任务通知值大于 0

(6)、参数 xClearCountOnExit 不为 pdFALSE,那就将任务通知值清零。

(7)、如果参数 xClearCountOnExit pdFALSE 的话那就将任务通知值减一。

(8)、更新任务通知状态为 taskNOT_WAITING_NOTIFICATION

函数 xTaskNotifyWait()

此函数也是用来获取任务通知的,不过此函数比 ulTaskNotifyTake()更为强大,不管任务通知用作二值信号量、计数型信号量、队列和事件标志组中的哪一种,都可以使用此函数来获取任务通知。但是当任务通知用作二值信号量和计数型信号量的时候推荐使用函数 ulTaskNotifyTake()。此函数原型如下:

说实话,前两个参数没太明白啥意思。

待补充理解。

任务通知模拟二值信号量

前面说了,根据 FreeRTOS 官方的统计,使用任务通知替代二值信号量的时候任务解除阻塞的时间要快 45%,并且需要的 RAM 也更少。其实通过我们上面分析任务通知发送和获取函数的过程可以看出,任务通知的代码量很少,所以执行时间与所需的 RAM 也就相应的会减少。

二值信号量就是值最大为 1 的信号量,这也是名字中“二值”的来源。当任务通知用于替代二值信号量的时候任务通知值就会替代信号量值,函数 ulTaskNotifyTake()就可以替代信号量获取函数xSemaphoreTake(),函数 ulTaskNotifyTake()的参数 xClearCountOnExit 设置为 pdTRUE。这样在每次获取任务通知的时候模拟的信号量值就会清零。函数xTaskNotifyGive()vTaskNotifyGiveFromISR()用于替代函数 xSemaphoreGive()xSemaphoreGiveFromISR()

任务通知模拟计数型信号量

不同与二值信号量,计数型信号量值可以大 1,这个最大值在创建信号量的时候可以设置。当计数型信号量有效的时候任务可以获取计数型信号量,信号量值只要大于 0 就表示计数型信号量有效。

当任务通知用作计数型信号量的时候获取信号量相当于获取任务通知值,使用函数ulTaskNotifyTake()来替代函数 xSemaphoreTake()。函数 ulTaskNotifyTake()的参数xClearOnExit要设置为 pdFLASE,这样每次获取任务通知成功以后任务通知值就会减一。使用任务通知发送函数 xTaskNotifyGive() vTaskNotifyGiveFromISR() 来替代计数型信号量释放函数xSemaphoreGive()xSemaphoreGiveFromISR()

任务通知模拟消息邮箱

任务通知也可用来向任务发送数据,但是相对于用队列发送消息,任务通知向任务发送消息会受到很多限制!

1、只能发送 32 位的数据值。

2、消息被保存为任务的任务通知值,而且一次只能保存一个任务通知值,相当于队列长度为 1

因此说任务通知可以模拟一个轻量级的消息邮箱而不是轻量级的消息队列。任务通知值就是消息邮箱的值。

发送数据可以使用函数 xTaskNotify()或者 xTaskNotifyFromISR(),函数的参数 eAction 设置eSetValueWithOverwrite 或 者 eSetValueWithoutOverwrite 。如果参数 eActioneSetValueWithOverwrite 的话不管接收任务的通知值是否已经被处理,这个通知值都会被更新。参数 eAction eSetValueWithoutOverwrite 的话如果上一个任务通知值话还没有被处理,那么新的任务通知值就不会更新。如果要读取任务通知值的话就使用函数xTaskNotifyWait()

任务通知模拟事件标志组

事件标志组其实就是一组二进制事件标志(),每个事件标志位的具体意义由应用程序编写者来决定。当一个任务等待事件标志组中的某几个标志()的时候可以进入阻塞态,当任务因为等待事件标志()而进入阻塞态以后这个任务就不会消耗 CPU

当任务通知用作事件标志组的话任务通知值就相当于事件组,这个时候任务通知值的每个 bit 用作事件标志 ( ) 。函数 xTaskNotifyWait() 替代事件标志组中的 API 函数 xEventGroupWaitBits()。函数 xTaskNotify()xTaskNotifyFromISR()(函数的参数 eActioneSetBits)替代事件标志组中的 API 函数 xEventGroupSetBits()和xEventGroupSetBitsFromISR()

任务通知暂时就了解这么多,实际开发中先把队列、信号量这些用明白再说。

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

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

相关文章

基于springboot+vue的中山社区医疗综合服务平台

博主主页:猫头鹰源码 博主简介:Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战,欢迎高校老师\讲师\同行交流合作 ​主要内容:毕业设计(Javaweb项目|小程序|Pyt…

Vue.js+SpringBoot开发创意工坊双创管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 管理员端2.2 Web 端2.3 移动端 三、系统展示四、核心代码4.1 查询项目4.2 移动端新增团队4.3 查询讲座4.4 讲座收藏4.5 小程序登录 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpringBootMySQL的创意工坊双创管理…

【机器学习】科学库使用第2篇:机器学习概述,学习目标【附代码文档】

机器学习(科学计算库)完整教程(附代码资料)主要内容讲述:机器学习(常用科学计算库的使用)基础定位、目标,机器学习概述定位,目标,学习目标,学习目标。机器学习概述,1.3 人…

计算机设计大赛 题目: 基于深度学习的疲劳驾驶检测 深度学习

文章目录 0 前言1 课题背景2 实现目标3 当前市面上疲劳驾驶检测的方法4 相关数据集5 基于头部姿态的驾驶疲劳检测5.1 如何确定疲劳状态5.2 算法步骤5.3 打瞌睡判断 6 基于CNN与SVM的疲劳检测方法6.1 网络结构6.2 疲劳图像分类训练6.3 训练结果 7 最后 0 前言 🔥 优…

初识HOOK框架frida

hook是什么 hook框架是一种技术,用于在运行时拦截和修改应用程序的行为,通过hook,可以劫持应用程序的方法调用、修改参数、篡改返回值等,以达到对应用程序的修改、增强或调试的目的。 常见的hook框架有哪些 Xposed Framework&am…

算法体系-11 第十一节:二叉树基本算法(上)

一 两链表相交 1.1 题目描述 给定两个可能有环也可能无环的单链表,头节点head1和head2。请实现一个函数,如果两个链表相交,请返回相交的 第一个节点。如果不相交,返回null 【要求】 如果两个链表长度之和为N,时间复杂…

什么是GPU云服务器?2024腾讯云GPU云服务器全解析!

腾讯云GPU服务器是提供GPU算力的弹性计算服务,腾讯云GPU服务器具有超强的并行计算能力,可用于深度学习训练、科学计算、图形图像处理、视频编解码等场景,腾讯云百科txybk.com整理腾讯云GPU服务器租用价格表、GPU实例优势、GPU解决方案、GPU软…

名词【语法笔记】

1.名词分为几大类 2.每一类,又有几个小类,以及所需要注意什么

python中字典相关知识点总结

1.字典的定义 字典:在Python中,字典是一系列键-值对。每个键都与一个值相关联,程序员可以通过键来访问与之相关联的值。 实际举例: student{name:xincun,age:18} 通过实例我们可以发现,键-值对是两个相关联的值。指…

3.20作业

1.创建一个工人信息库,包含工号(主键),姓名,年龄,薪资 CREATE TABLE work (id int, name char, age int,money float); 2.添加三条工人信息(可以完整信息,也可以非完整信息&#xff…

Twincat实现电机控制

不仅是控制系统的核心部分,而且能够将任何基于PC的系统转换为一个带有PLC、NC、CNC和机器人实时操作系统的实时控制系统。TwinCAT软件在工业自动化领域具有广泛的应用,特别是在机器人关节电机控制方面!!! 在机器人关节电机控制方面,TwinCAT通…

【C语言基础篇】字符串处理函数(二)strcpy的介绍及模拟实现

目录 一、strcpy介绍 函数原型: 函数功能: 函数参数: 函数返回值: 二、strcpy模拟实现 代码: 测试: 个人主页: 倔强的石头的博客 系列专栏 :C语言指南 C语言刷题系列…

JeePlus低代码开发平台存在SQL注入漏洞

漏洞描述 JeePlus低代码开发平台存在SQL注入漏洞 fofa语句 app"JeePlus" 漏洞复现 打开页面 构造payload GET /a/sys/user/validateMobile?mobile1%27and1%3D%28updatexml%281%2Cconcat%280x7e%2C%28selectmd5%281%29%29%2C0x7e%29%2C1%29%29and%271%27%3D%271…

六、循环结构

在python当中有两类循环结构:for循环和while循环 一、遍历for循环 for循环首先判断遍历对象中是否有元素,在依次遍历 for循环常与range()函数使用 for i in range(1,10,):#range()函数依次遍历1~10但不包括10print(i,end ) p…

账号+密码+图片验证码认证

账号密码图片验证码认证 实现步骤 实现账号密码认证,执行流程如下 第一步: 对于验证码服务工程的生成验证码图片的接口在网关处需要放行,否则页面无法获取生成的验证码图片 /**临时放行所有请求 /auth/**认证服务地址 /content/open/**内容管理公开访问文件接口 …

【计算机视觉】Gaussian Splatting源码解读补充(二)

第一部分 目录 三、前向传播(渲染):submodules/diff-gaussian-rasterization/cuda_rasterizer/forward.cu预备知识:CUDA编程基础 三、前向传播(渲染):submodules/diff-gaussian-rasterization/c…

软件工程导论画图题汇总:期末+复试

文章目录 一、数据模型:实体联系图(E-R图)二、行为模型:状态转换图三、功能模型:数据流图四、数据字典五、系统流程图六、层次图七、HIPO图八、结构图九、程序流程图十、盒图十一、PAD图十二、判定表、判定树 一、数据…

Vue2(四):Vue监测数据的原理

一、先来看一个问题 添加一个按钮点击更新马冬梅的信息&#xff1a; <button click"gengxin">点击更新马冬梅的信息</button> methods:{gengxin(){this.person[1].name马老师,this.person[1].age50,this.person[1].sex男}} 下面这种方式就不能奏效&a…

数据库系统概论-第5章 数据库完整性

5.1 实体完整性 5.2 参照完整性 5.3 用户定义完整性 5.4 完整性约束命名子句 5.5 域中的完整性限制 5.6 断言 5.7 触发器 5.8 小结

STM32CubeIDE基础学习-EXTI外部中断实验

STM32CubeIDE基础学习-EXTI外部中断实验 文章目录 STM32CubeIDE基础学习-EXTI外部中断实验前言第1章 硬件介绍第2章 工程配置2.1 工程外设配置部分2.2 生成工程代码部分 第3章 代码编写第4章 实验现象总结 前言 中断概念&#xff1a;让CPU打断正在执行的程序&#xff0c;进而去…