FreeRTOS:任务通知

news2024/12/24 19:27:49

目录

  • 一、任务通知简介
  • 二、发送任务通知
    • 2.1 函数xTaskNotify()
    • 2.2函数xTaskNotifyFromISR()
    • 2.3函数xTaskNotifyGive()
    • 2.4函数vTaskNotifyGiveFromISR()
    • 2.5函数xTaskNotifyAndQuery()
    • 2.6函数xTaskNotifyAndQueryFromISR()
  • 三、获取任务通知
    • 3.1函数ulTaskNotifyTake()
    • 3.2函数xTaskNotifyWait()

一、任务通知简介

任务通知在FreeRTOS中是一个可选的功能,要使用任务通知的话就需要将宏 configUSR_TASK_NOTIFICATIONS定义为1。
  FreeRTOS的每个任务都有一个32位的通知值,任务控制款中的成员变量ulNotifiedValue就是这个通知值。任务通知是一个事件,假如某个任务通知的接收任务因为等待任务通知而阻塞的话,向这个接收任务发送任务通知以后就会解除这个任务的阻塞状态。也可以更新接收任务的任务通知值,任务通知可以通过如下方法更新接收任务的通知值:
  1. 不覆盖接收任务的通知值(如果上次发送给接收任务的通知还没有被处理)。
  2. 覆盖接收任务的通知值。
  3. 更新接收任务通知值的一个或多个bit。
  4. 增加接收任务的通知值。
  合理、灵活地使用上面这些更改任务通知值的方法可以在一些场合中替代队列、二值信号量、计数型信号量和时间标志组。使用任务通知来实现二值信号量功能的时候,解除任务阻塞的时间比直接使用二值信号量要快45%(FreeRTOS官方测试结果,使用v8.1.2版本中的二值信号量,GCC编译器,-O2优化条件下测试的,没有使能断言函数configASSERT()),并且使用的RAM更少!
  任务通知的发送使用函数xTaskNotify()或者xTaskNotifyGive()(还有次函数的中断版本)来完成,这个通知值会一直保存着,直到接收任务调用函数xTaskNotifyWait()或者ulTaskNotifyTake()来获取这个通知值。假如接收任务因为等待任务通知而阻塞的话那么在接收到任务通知以后就会解除阻塞态。
  任务通知虽然可以提高速度,并且减少RAM的使用,但是任务通知也是由使用限制的:
  1. FreeRTOS的任务通知只能有一个接收任务,其实大多数的应用都是这种情况。
  2. 接收任务可以因为接收任务通知而进入阻塞态,但是发送任务不会因为任务通知发送失败而阻塞。

二、发送任务通知

任务通知发送函数有6个,如表:
在这里插入图片描述

2.1 函数xTaskNotify()

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

BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify, 
                        uint32_t ulValue, 
                        eNotifyAction eAction )

参数:

xTaskToNotify:任务句柄,指定任务通知是发送给哪个任务的。

ulValue:任务通知值。

eAction:任务通知更新的方法,eNotifyAction是个枚举类型,在文件task.h中有如下定义:

/* Actions that can be performed when vTaskNotify() is called. */
typedef enum
{
    eNoAction = 0,               /* Notify the task without updating its notify value. */
    eSetBits,                    /* 更新指定bit。Set bits in the task's notification value. */
    eIncrement,                  /* 任务通知值加一。Increment the task's notification value. */
    eSetValueWithOverwrite,      /* 覆写的方式更新通知值。Set the task's notification value to a specific value even if the previous value has not yet been read by the task. */
    eSetValueWithoutOverwrite    /* 不覆写通知值。Set the task's notification value if the previous value has been read by the task. */
} eNotifyAction;

此参数可以选择枚举类型中的任意一个,不同的应用环境选择也不同。

返回值:

pdFAIL:但参数eAction设置为eSetValueWithoutOverwrite的时候,如果任务通知值没有更新成功就返回pdFAIL。

pdPASS:eAction设置为其他选项的时候统一返回pdPASS。

2.2函数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。

2.3函数xTaskNotifyGive()

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

BaseType_t xTaskNotifyGive( TaskHandle_t xTaskToNotify )

参数:

xTaskToNotify:任务句柄,指定任务通知是发送给哪个任务的。

返回值:

pdPASS:此函数只会返回pdPASS。

2.4函数vTaskNotifyGiveFromISR()

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

void vTaskNotifyGiveFromISR( TaskHandle_t xTaskHandle, 
                             BaseType_t *pxHigherPriorityTaskWoken )

参数:

xTaskToNotify:任务句柄,指定任务通知是发送给哪个任务的。

pxHigherPriorityTaskWoken:退出此函数以后是否进行任务切换,这个变量的值会自动设置的,用户不用进行设置,用户只需要提供一个变量来保存这个值就行了。当此值为pdTRUE的时候在退出中断服务函数之前一定要进行一次任务切换。

返回值:

无。

2.5函数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。

2.6函数xTaskNotifyAndQueryFromISR()

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

BaseType_t xTaskNotifyFromISR( TaskHandle_t xTaskToNotify, 
                               uint32_t ulValue, 
                               eNotifyAction eAction, 
                               BaseType_t *pxHigherPriorityTaskWoken )

参数:

xTaskToNotify:任务句柄,指定任务通知是发送给哪个任务的。

ulValue:任务通知值。

eAction:任务通知更新的方法。

pulPreviousNotificationValue:用来保存更新前的任务通知值。

pxHigherPriorityTaskWoken:退出此函数以后是否进行任务切换,这个变量的值函数会自动设置,用户不进行设置,用户只需要提供一个变量来保存这个值就行了。当此值为pdTRUE的时候在退出中断服务函数之前一定要进行一次任务切换。

返回值:

pdFAIL:当参数eAction设置为eSetValueWithoutOverwrite的时候,如果任务通知值没有更新成功就返回pdFAIL。

pdPASS:eAction设置为其他选项的时候统一返回pdPASS。

三、获取任务通知

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

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

3.1函数ulTaskNotifyTake()

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

uint32_tulTaskNotifyTake(BaseType_t xClearCountOnExit,
TickType_t xTicksToWait);

在这里插入图片描述
此函数在文件task.c中定义,函数源码如下:

uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait )
{
uint32_t ulReturn;

	taskENTER_CRITICAL();
	{
		if( pxCurrentTCB->ulNotifiedValue == 0UL )(1)
		{
			pxCurrentTCB->ucNotifyState = taskWAITING_NOTIFICATION;(2)

			if( xTicksToWait > ( TickType_t ) 0 )(3)
			{
				prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );
				traceTASK_NOTIFY_TAKE_BLOCK();
				portYIELD_WITHIN_API();
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}
	}
	taskEXIT_CRITICAL();

	taskENTER_CRITICAL();
	{
		traceTASK_NOTIFY_TAKE();
		ulReturn = pxCurrentTCB->ulNotifiedValue;(4)

		if( ulReturn != 0UL )(5)
		{
			if( xClearCountOnExit != pdFALSE )(6)
			{
				pxCurrentTCB->ulNotifiedValue = 0UL;
			}
			else
			{
				pxCurrentTCB->ulNotifiedValue = ulReturn - 1;(7)
			}
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}

		pxCurrentTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;(8)
	}
	taskEXIT_CRITICAL();
	return ulReturn;
}

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

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

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

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

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

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

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

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

3.2函数xTaskNotifyWait()

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

BaseType_txTaskNotifyWait(uint32_tulBitsToClearOnEntry,
uint32_t ulBitsToClearOnExit,
uint32_t*pulNotificationValue,
TickType_t xTicksToWait);

在这里插入图片描述
此函数在文件task.c有定义,源代码为:


BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait )
	{
	BaseType_t xReturn;

		taskENTER_CRITICAL();
		{
			if( pxCurrentTCB->ucNotifyState != taskNOTIFICATION_RECEIVED )(1)
			{
				pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnEntry;(2)
				pxCurrentTCB->ucNotifyState = taskWAITING_NOTIFICATION;(3)

				if( xTicksToWait > ( TickType_t ) 0 )(4)
				{
					prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );
					traceTASK_NOTIFY_WAIT_BLOCK();

					portYIELD_WITHIN_API();
				}
				else
				{
					mtCOVERAGE_TEST_MARKER();
				}
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		taskEXIT_CRITICAL();

		taskENTER_CRITICAL();
		{
			traceTASK_NOTIFY_WAIT();

			if( pulNotificationValue != NULL )(5)
			{
				*pulNotificationValue = pxCurrentTCB->ulNotifiedValue;
			}
			if( pxCurrentTCB->ucNotifyState == taskWAITING_NOTIFICATION )(6)
			{
				xReturn = pdFALSE;
			}
			else
			{
				pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnExit;(7)
				xReturn = pdTRUE;
			}

			pxCurrentTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;(8)
		}
		taskEXIT_CRITICAL();

		return xReturn;
	}

(1)、任务同通状态不为taskNOTIFICATION_RECEIVED。
(2)、将任务通知值与参数ulBitsToClearOnEntry的取反值进行按位与运算。
(3)、任务通知状态改为taskWAITING_NOTIFICATION。
(4)、如果阻塞时间大于0的话就要将任务添加到延时列表中,并且进行一次任务切换。
(5)、如果任务通知状态为taskNOTIFICATION_RECEIVED,并且参数pulNotificationValue有效的话就保存任务通知值。
(6)、如果任务通知的状态又变为taskWAITING_NOTIFICATION的话就标记xReturn为pdFALSE。
(7)、如果任务通知的状态一直为taskNOTIFICATION_RECEIVED的话就将任务通知的值与参数ulBitsToClearOnExit的取反值进行按位与运算,并且标记xReturn为pdTRUE,表示获取任务通知成功。
(8)、标记任务通知的状态为taskNOT_WAITING_NOTIFICATION。

参考视频:正点原子
在这里插入图片描述

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

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

相关文章

[进阶]Java:打印流、Properties、common-io框架

打印流: 作用:打印流可以实现方便、高效的打印数据到文件中去。打印流一般是:PrintStream,PrintWriter两个类。可以实现打印什么数据就是什么数据,例如打印整数97写出去就是97,打印boolean的true&#xff…

chatgpt赋能python:Python截取某段文字的方法

Python截取某段文字的方法 在处理文本数据时,截取某段文字是常见需求。Python作为一门优秀的脚本语言,提供了多种方法来完成这个任务。本篇文章将介绍Python截取某段文字的几种方便易用的方法。 方法一:使用切片 Python中的切片操作可以方…

JavaScript的一些编程题分享

将字符串abc-def-ghi转换为驼峰格式 这里我们的思路是利用字符串方法和正则表达式 const str abc-def-ghi;const camelCaseStr str.replace(/[-_][^-_]/g, match > match.charAt(1).toUpperCase());console.log(camelCaseStr); // abcDefGhi 这里使用了 replace 方法&a…

haproxy

haproxy haproxy一:常见的Web集群调度器1.软件2.硬件3.LVS ,Nginx ,Haproxy 的区别: 二:Haproxy应用分析1.HAProxy的主要特性有:2.HAProxy负载均衡策略非常多,常见的有如下8种: 三&a…

MySQL8.0数据库开窗函数

简介 数据库开窗函数是一种在SQL中使用的函数,它可以用来对结果集中的数据进行分组和排序,以便更好地分析和处理数据。开窗函数与聚合函数不同,它不会将多行数据聚合成一行,而是保留每一行数据,并对其进行分组和排序。…

Linux中/dev/random和/dev/urandom的作用

1./dev/random和/dev/urandom介绍 在Linux环境中,我们会用到/dev/random和/dev/urandom,今天为大家讲讲/dev/random和/dev/urandom的作用以及使用场景。 1.1./dev/random介绍 /dev/random是一个特殊的字符设备文件,用于生成“高质量”的随…

Python面向对象编程1-面向过程的简单纸牌游戏程序 项目1.1 定义纸牌的花色和点数

总项目目标:用面向过程思想设计一个简单的纸牌游戏程序,称为"Higher or Lower"(高还是低)。游戏中,玩家需要猜测接下来的一张牌是比当前牌高还是低。根据猜测的准确性,玩家可以得到或失去相应的积…

Unity UGUI1——基础组件概述

一、UGUI 介绍 ​ UGUI 是 Unity 引擎内自带的 UI 系统,官方称之为:Unity UI ​ 是目前 Unity 商业游戏开发中使用最广泛的 UI 系统开发解决方案 ​ 它是基于 Unity 游戏对象的 UI 系统,只能用来做游戏 UI 功能 ​ 不能用于开发 Unity 编…

【MarkDown】CSDN Markdown之Git图gitGraph详解

Git图 Git图是对不同分支上的Git提交和Git操作(命令)的图形化表示。 这种类型的图特别适合开发人员和DevOps团队分享他们的Git分支策略。例如,它可以更容易地可视化git流的工作方式。 Mermaid可以呈现Git图,但是只有v10.2.3 才支持。 代码…

kubernets 笔记

kubernets 笔记 kubernets 安装 1. 环境准备 硬件要求 内存:2GBCPU:2 核硬盘:30GB 本次环境说明 操作系统:CentOS 7.9内核版本:3.10.0-1160.76.1.el7.x86_64k8s-m:192.168.222.3k8s-s01:192.…

安装Apache、MySQL、PHP、论坛实操

文章目录 一、安装Apache1、准备阶段2、开始安装3、浏览器访问验证 二、部署MySQL三、部署php四、部署BBS论坛 一、安装Apache 1、准备阶段 (1)准备源码包 httpd-2.4.29.tar.gz apr-1.6.2.tar.gz apr-util-1.6.0.tar.gz cd /opt tar xf apr-1.6.2.tar…

【Windows】创建Windows远程桌面快捷方式

【Windows】创建Windows远程桌面快捷方式 1、背景2、操作 1、背景 windows系统自带了远程连接工具,可以实现局域网内的远程控制,参考: 【Windows】局域网内远程桌面控制 https://blog.csdn.net/jn10010537/article/details/130926888 但是w…

【Leetcode -404.左子叶之和 -543.二叉树的直径】

Leetcode Leetcode -404.左子叶之和Leetcode -543.二叉树的直径 Leetcode -404.左子叶之和 题目:给定二叉树的根节点 root ,返回所有左叶子之和。 示例 1: 输入: root [3, 9, 20, null, null, 15, 7] 输出 : 24 解释 : 在这个二叉树中&…

vue三部曲

vue初入 简介 ​ vue生于2014年 Vue等框架与jQuery的区别 ​ jQuery是基于操作dom的库 ​ Vue框架是以数据驱动和组件化开发为核心 留坑、引包、实例化、插值表达式{{}} ​ vue第一个简单案例练习图。 引包 ​ 使用cnpm install vue2下载vue2(version下载指…

ansible的剧本

一、playbooks 概述以及实例操作 1、playbooks 的组成 playbooks 本身由以下各部分组成 (1)Tasks:任务,即通过 task 调用 ansible 的模板将多个操作组织在一个 playbook 中运行 (2)Variables&#xff1…

数据挖掘工程师岗位的工作职责

数据挖掘工程师岗位的工作职责1 职责: 1.负责数据分析,数据挖掘相关的算法、应用的设计与开发; 2.负责公司产品各阶段数据的整理、分析、挖掘及提交数据报告,重点对车辆行为数据进行分析和挖掘,利用数据分析结论推动业务产品的优化; 3.对海量…

python---列表和元组(3)

列表元素的遍历 遍历往往搭配循环 for循环进行遍历 for循环搭配下标的形式 这个可以修改列表中的数值 上述两个代码的区别 通过下标的方式进行赋值才会修改自身 使用while循环遍历 元素的插入操作 使用append往列表末尾来新增元素 使用insert进行插入 列表的查找##…

利用AHB-Lite总线实现ARM Cortex-M0基础的SoC系统;如何设计一个SoC系统;AHB-Lite;ARM Cortex-M0;SoC;

利用AHB-Lite总线实现ARM Cortex-M0基础的SoC系统;如何设计一个SoC系统 一、SoC系统下的软硬件分工Hardware only 和System on Chip的区别例子1:计算时间差值例子2:想实现功能的切换例子3:LED显示 二、SoC系统1. AHB-Lite总线 与 …

chatgpt赋能python:Python如何隐藏输出

Python如何隐藏输出 如果你是一个Python程序员,你可能会遇到需要隐藏输出的情况。这可能是因为你的输出包含敏感信息,或者你只是想使你的输出更加整洁,避免不必要的干扰。在这篇文章中,我们将探讨一些方法来隐藏Python中的输出。…

微擎PHP文件goto解密源码工具

🎉 有需要的朋友记得关赞评,文章底部来交流!!! 🎉 ✨ 源码介绍 1、php 版本需要大于 7 2、需要解密的文件放到 decodeFile 下,解密至 complete 下 3、解密的可以是多个文件,不能放…