FreeRTOS任务通知

news/2024/10/12 16:29:39

FreeRTOS任务通知

FreeRTOS 新增了任务通知(Task Notifictions)这个功能,可以使用任务通知来代替信号量、消息队列、事件标志组等这些东西。使用任务通知的话效率会更高,任务通知在 FreeRTOS 中是一个可选的功能,
使用队列、信号量、事件标志组时都需另外创建一个结构体,通过中间的结构体进行间接通信!过程如下图所示:

在这里插入图片描述
要使用任务通知的话就需要将宏configUSE_TASK_NOTIFICATIONS 定义为 1。FreeRTOS 的每个任务都有一个 32 位的通知值,任务控制块中的成员变量 ulNotifiedValue就是这个通知值。过程如下图所示:
在这里插入图片描述

任务通知是一个事件,假如某个任务通知的接收任务因为等待任务通知而阻塞的话,向这个接收任务发送任务通知以后就会解除这个任务的阻塞状态。也可以更新接收任务的任务通知值,任务通知可以通过如下方法更新接收任务的通知值:
不覆盖接收任务的通知值(如果上次发送给接收任务的通知还没被处理)。
覆盖接收任务的通知值。
更新接收任务通知值的一个或多个 bit
增加接收任务的通知值
所以根据以上四种情况可以在一些情况下合理替代队列、二值信号量、计数型信号量、事件标志组。任务通知虽然可以提高速度,并且减少RAM的使用,并且任务通知是有使用限制的:
1:RTOS的任务通知只能有一个接收任务。
2:接收任务可以因为接受任务通知而进入阻塞态,但是发送任务不会因为任务通知发送失败而阻塞。
在这里插入图片描述

在这里插入图片描述
上图为任务结构体存储的部分内容,从上图我们可以RTOS中默认数组的大小就是1,也可以看到一个是 uint32_t 类型,用来表示通知值,一个是 uint8_t 类型,用来表示通知状态。

任务通知值

任务通知值的更新方式有多种类型:
1 计数值(数值累加,类似与信号量)
2 相应位置1(类似事件标志组)
3 任意数值(支持覆写和不覆写,类似队列)

任务通知状态

在这里插入图片描述在这里插入图片描述

任务通知发送函数

任务通知发送函数有以下6个:
在这里插入图片描述
此函数用于发送任务通知,此函数发送任务通知的时候带有通知值,此函数是个宏,真正执行的函数

xTaskGenericNotify()

函数原型如下:

BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction )
xTaskToNotify: 任务句柄,指定任务通知是发送给哪个任务的。
ulValue: 任务通知值。
eAction: 任务通知更新的方法,eNotifyAction 是个枚举类型,在文件 task.h 中有如下定义:
返回值: 
pdFAIL: 当参数 eAction 设置为 eSetValueWithoutOverwrite 的时候,如果任务通知值没有
更新成功就返回 pdFAIL。
pdPASS: eAction 设置为其他选项的时候统一返回 pdPASS。

eAction如下图枚举的类型一样,依次为:
eSetBits更新指定的Bit,eIncrement通知值加1,eSetValueWithOverwrite,覆写的方式更新通知值。
eSetValueWithoutOverwrite,不覆写通知值。
在这里插入图片描述

函数 xTaskNotifyFromISR()

此函数用于发送任务通知,是函数 xTaskNotify()的中断版本,此函数是个宏,真正执行的是函数 xTaskGenericNotifyFromISR(),此函数原型如下:

BaseType_t xTaskNotifyFromISR( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, 
BaseType_t * pxHigherPriorityTaskWoken );
参数:
xTaskToNotify: 任务句柄,指定任务通知是发送给哪个任务的。
ulValue: 任务通知值。
eAction: 任务通知更新的方法。
pxHigherPriorityTaskWoken: 记退出此函数以后是否进行任务切换,这个变量的值函数会自动设置的,用户不用
进行设置,用户只需要提供一个变量来保存这个值就行了。当此值为 pdTRUE 的时候在退出中断服务
函数之前一定要进行一次任务切换。
返回值: 
pdFAIL: 当参数 eAction 设置为 eSetValueWithoutOverwrite 的时候,如果任务通知值没有
更新成功就返回 pdFAIL。
pdPASS: eAction 设置为其他选项的时候统一返回 pdPASS。

函数 xTaskNotifyGive()

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

BaseType_t xTaskNotifyGive( TaskHandle_t xTaskToNotify );
参数:
xTaskToNotify: 任务句柄,指定任务通知是发送给哪个任务的。
返回值: 
pdPASS: 此函数只会返回 pdPASS。

函数 vTaskNotifyGiveFromISR()

此函数为 xTaskNotifyGive()的中断版本,用在中断服务函数中,函数原型如下:

void vTaskNotifyGiveFromISR( TaskHandle_t xTaskHandle, BaseType_t * pxHigherPriorityTaskWoken );
参数:
xTaskToNotify: 任务句柄,指定任务通知是发送给哪个任务的。
pxHigherPriorityTaskWoken: 记退出此函数以后是否进行任务切换,这个变量的值函数会自动
设置的,用户不用进行设置,用户只需要提供一个变量来保存这
个值就行了。当此值为 pdTRUE 的时候在退出中断服务函数之
前一定要进行一次任务切换。
返回值: 
无。

函数 xTaskNotifyAndQuery()

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

BaseType_t xTaskNotifyAndQuery ( TaskHandle_t xTaskToNotify, 
uint32_t ulValue, 
eNotifyAction eAction 
uint32_t * pulPreviousNotificationValue);
参数:
xTaskToNotify: 任务句柄,指定任务通知是发送给哪个任务的。
ulValue: 任务通知值。
eAction: 任务通知更新的方法。
pulPreviousNotificationValue:用来保存更新前的任务通知值。
返回值: 
pdFAIL: 当参数 eAction 设置为 eSetValueWithoutOverwrite 的时候,如果任务通知值没有
更新成功就返回 pdFAIL。
pdPASS: eAction 设置为其他选项的时候统一返回 pdPASS。

函数 xTaskNotifyAndQueryFromISR()

此函数为 xTaskNorityAndQuery()的中断版本,用在中断服务函数中。此函数同样为宏,真
正执行的是函数 xTaskGenericNotifyFromISR(),此函数的原型如下:

BaseType_t xTaskNotifyAndQueryFromISR ( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t * pulPreviousNotificationValueBaseType_t * pxHigherPriorityTaskWoken );
参数:
xTaskToNotify: 任务句柄,指定任务通知是发送给哪个任务的。
ulValue: 任务通知值。
eAction: 任务通知更新的方法。
pulPreviousNotificationValue:用来保存更新前的任务通知值。
pxHigherPriorityTaskWoken: 记退出此函数以后是否进行任务切换,这个变量的值函数会自动设置的,
用户不用进行设置,用户只需要提供一个变量来保存这个值就行了。当此值为 pdTRUE 的时候在退出中断服务函数之
前一定要进行一次任务切换。
返回值: 
pdFAIL: 当参数 eAction 设置为 eSetValueWithoutOverwrite 的时候,如果任务通知值没有
更新成功就返回 pdFAIL。
pdPASS: eAction 设置为其他选项的时候统一返回 pdPASS。

任务通知通用发送函数源码

任务级任务通知通用发送函数在上面中有3 个任务级任务通知发送函数:xTaskNotify()、xTaskNotifyGive()
和 xTaskNotifyAndQuery(),这三个函数最终调用的都是函数 xTaskGenericNotify()!此函数在文件 tasks.c 中有如下定义,缩减后的函数如下:

BaseType_t xTaskGenericNotify( TaskHandle_t xTaskToNotify, //任务句柄uint32_t ulValue, //任务通知值eNotifyAction eAction, //任务通知更新方式uint32_t * pulPreviousNotificationValue )//保存更新前的//任务通知值
{TCB_t * pxTCB;BaseType_t xReturn = pdPASS;uint8_t ucOriginalNotifyState;configASSERT( xTaskToNotify );pxTCB = ( TCB_t * ) xTaskToNotify;taskENTER_CRITICAL();{if( pulPreviousNotificationValue != NULL ) (1){//如果提供了一个非NULL指针来接收更新前的通知值,则将当前的通知值保存到该位置*pulPreviousNotificationValue = pxTCB->ulNotifiedValue; (2)}//保存任务通知状态,因为下面会修改这个状态,//后面我们要根据这个状态来确定是否将任务从阻塞态解除。ucOriginalNotifyState = pxTCB->ucNotifyState; (3)pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED; (4)switch( eAction ){case eSetBits : (5)pxTCB->ulNotifiedValue |= ulValue;break;case eIncrement : (6)( pxTCB->ulNotifiedValue )++;break;case eSetValueWithOverwrite: (7)pxTCB->ulNotifiedValue = ulValue;break;case eSetValueWithoutOverwrite : (8)if( ucOriginalNotifyState != taskNOTIFICATION_RECEIVED ){pxTCB->ulNotifiedValue = ulValue;}else{xReturn = pdFAIL;}break;case eNoAction:break;}traceTASK_NOTIFY();//如果任务因为等待任务通知而进入阻塞态的话就需要解除阻塞if( ucOriginalNotifyState == taskWAITING_NOTIFICATION ) (9){( void ) uxListRemove( &( pxTCB->xStateListItem ) ); (10)prvAddTaskToReadyList( pxTCB ); (11)/******************************************************************//********************省略相关的条件编译代码************************//******************************************************************/if( pxTCB->uxPriority > pxCurrentTCB->uxPriority ) (12){//解除阻塞的任务优先级比当前运行的任务优先级高,所以需要进行//任务切换。taskYIELD_IF_USING_PREEMPTION();}else{mtCOVERAGE_TEST_MARKER();}}else{mtCOVERAGE_TEST_MARKER();}}taskEXIT_CRITICAL();return xReturn; (13)
}

中断级任务通知发送函数

中 断 级 任 务 通 知 发 送 函 数 也 有 三 个 , 分 别 为 : xTaskNotifyFromISR() 、
xTaskNotifyAndQueryFromISR()和 vTaskNotifyGiveFromISR()。其中函数 xTaskNotifyFromISR()
和 xTaskNotifyAndQueryFromISR()最终调用的都是函数 xTaskGenericNotifyFromISR(),此函数
的原型如下:

BaseType_t xTaskGenericNotifyFromISR( 	TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t * pulPreviousNotificationValue, BaseType_t * pxHigherPriorityTaskWoken )参数:
xTaskToNotify: 任务句柄,指定任务通知是发送给哪个任务的。
ulValue: 任务通知值。
eAction: 任务通知更新的方法。
pulPreviousNotificationValue:用来保存更新前的任务通知值。
pxHigherPriorityTaskWoken: 记退出此函数以后是否进行任务切换,这个变量的值函数会自动
设置的,用户不用进行设置,用户只需要提供一个变量来保存这
个值就行了。当此值为 pdTRUE 的时候在退出中断服务函数之
前一定要进行一次任务切换。
返回值: 
pdFAIL: 当参数 eAction 设置为 eSetValueWithoutOverwrite 的时候,如果任务通知值没有
更新成功就返回 pdFAIL。
pdPASS: eAction 设置为其他选项的时候统一返回 pdPASS。

获取任务通知

获取任务通知的函数有两个:

ulTaskNotifyTake()获取任务通知,可以设置在退出此函数的时候将任务通知值清零或者减一。
当任务通知用作二值信号量或者计数信号量的时候使用此函数来获取信号量。
xTaskNotifyWait()等待任务通知,比 ulTaskNotifyTak()更为强大,全功能版任务通
知获取函数。

函数 ulTaskNotifyTake()

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

uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait );
参数:
xClearCountOnExit: 参数为 pdFALSE 的话在退出函数 ulTaskNotifyTake()的时候任务通知值
减一,类似计数型信号量。当此参数为 pdTRUE 的话在退出函数的时候
任务任务通知值清零,类似二值信号量。
xTickToWait: 阻塞时间。
返回值:
任何值 : 任务通知值减少或者清零之前的值。

函数 xTaskNotifyWait()

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

BaseType_t xTaskNotifyWait(  uint32_t ulBitsToClearOnEntry,uint32_t ulBitsToClearOnExit, uint32_t * pulNotificationValue, TickType_t xTicksToWait );参数:
ulBitsToClearOnEntry:当没有接收到任务通知的时候将任务通知值与此参数的取反值进行按
位与运算,当此参数为 0xffffffff 或者 ULONG_MAX 的时候就会将任务
通知值清零。
ulBitsToClearOnExit:如果接收到了任务通知,在做完相应的处理退出函数之前将任务通知值
与此参数的取反值进行按位与运算,当此参数为 0xffffffff 或者ULONG_MAX 的时候就会将任务通知值清零。
pulNotificationValue:此参数用来保存任务通知值。
xTickToWait: 阻塞时间。
返回值:
pdTRUE: 获取到了任务通知。
pdFALSE: 任务通知获取失败。

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

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

相关文章

uboot-学习笔记

uboot引导程序的作用不同bootloader的对比系统启动自举过程阶段

【软件构造课程相关】幻方及其构造(上)

介绍 ​ 幻方(Magic Square),有时又称魔术方阵或纵横图,由一组排放在正方形中的整数组成,其每行、每列以及每一条主对角线的和均相等。通常幻方由从1到$N2$的连续整数组成,其中N为正方形的行或列的数目。因此N阶幻方有N行N列,并且所填充的数为从1到$N2$。 ​ …

SDL库基础学习

初始化 int SDL_Init(Uint32 flags);* `flags` may be any of the following ORd together:** - `SDL_INIT_TIMER`: timer subsystem* - `SDL_INIT_AUDIO`: audio subsystem* - `SDL_INIT_VIDEO`: video subsystem; automatically initializes the events* subsystem* - `SDL…

2024-5-1 假期第一天 愉快

假期第一天,中午十点多醒的,经过一番挣扎之后还是下定决心去本部开点二硫化硒,于是坐地铁去本部,到了发现皮肤科不开,遂返回,虽然无功而返吗,但是今天天气是真的好,路上骑行看到的风景很美,回来的时候去物美逛了一圈买了点香蕉,买了点饮料,然后又花30买了两杯喜茶,…

WPF上位机 - 使用转换器实现TIA Wincc中的可见性和外观功能

在TIA Wincc 中有这样的功能,使用True or false 控制控件的可见性或者外观的情况。在上位机中需要使用转换器这样对True or false 值转换为 需要的笔刷或者Visible属性。 using System; using System.Collections.Generic; using System.Globalization; using System.Linq; us…

Spring AOP

AOP简介A0P(Aspect Oriented Programming)面向切面编程,一种编程范式,指导开发者如何组织程序结构OOP(object Oriented Programming)面向对象编程作用:在不惊动原始设计的基础上为其进行功能增强 Spring理念:无入侵式/无侵入式AOP核心概念连接点(JoinPoint):程序执行过程…

本地化部署hoppscotch —— 使用docker compose一键部署 + https支持

一、前言 研究了好久,终于完成了hoppscotch本地一键部署,并支持https。hoppscotch的介绍这里就不做过多描述,网络上非常多,这里先放几张使用效果 1、api界面 2、管理界面 2、部署效果: a.使用脚本,./create_and_start.sh(后面会提供),需要传入本机ip(能访问到的),…

关于stm32F103ZET6移植到stm32F103C8T6的步骤

在一次代码移植过程中,突然发现代码移植后不可以使用,代码是stm32f103zet6的代码,刚好当时我使用的是C8T6的芯片我进行移植到C8T6芯片时,代码报错"Error:Flash Download failed - "Cortex_M3"这种报错。当时直接懵逼了。想了半天没有想到原因,我就在想不都…