freeRTOS--任务通知

news2024/11/25 18:51:54

一、什么是任务通知

使用任务通知可以替换二值信号量、计数信号量、事件标志组,可以替代长度为1的队列,任务通知速度更快、使用的RAM更少。

任务通知值的更新方式:

  1. 发消息给任务,如果有通知未读,不覆盖通知值。
  2. 发消息给任务,直接覆盖通知值。
  3. 发消息给任务,设置通知值的一个或多个 位
  4. 发送消息给任务,递增通知值

任务通知的相关API函数:

1.发送通知

1.发送通知
函数描述
xTaskNotify()
发送通知,带有通知值
xTaskNotifyAndQuery()
发送通知,带有通知值并且保留接收任务的原通知值
xTaskNotifyGive()

发送通知,不带通知值

xTaskNotifyFromISR()
在中断中发送任务通知
vTaskNotifyGiveFromISR()
在中断中发送任务通知

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

 

xTaskToNotify:需要接收通知的任务句柄;
ulValue:用于更新接收任务通知值, 具体如何更新由形参 eAction 决定;
eAction:一个枚举,代表如何使用任务通知的值;

枚举
枚举值描述
eNoAction
发送通知,但不更新值(参数 ulValue 未使用)
eSetBits
被通知任务的通知值按位或 ulValue 。(某些场景下可代替事件组,效率更高)

 

eSetValueWithOverWrite
被通知任务的通知值设置为 ulValue 。(某些场景下可代替 xQueueOverwrite ,效率更高)
eSetValueWithoutOverwrite
如果被通知的任务当前没有通知,则被通知的任务的通知值 设为ulValue
如果被通知任务没有取走上一个通知,又接收到了一个通 知,则这次通知值丢弃,在这种情况下视为调用失败并返回 pdFALSE (某些场景下可代替 xQueueSend ,效率更高)

返回值:如果被通知任务还没取走上一个通知,又接收了一个通知,则这次通知值未能更新并返回
pdFALSE, 而其他情况均返回pdPASS。

BaseType_t xTaskNotifyAndQuery( TaskHandle_t xTaskToNotify,
uint32_t ulValue,
eNotifyAction eAction,
uint32_t *pulPreviousNotifyValue );
参数:
xTaskToNotify:需要接收通知的任务句柄; 
ulValue:用于更新接收任务通知值, 具体如何更新由形参 eAction 决定; 
eAction:一个枚举,代表如何使用任务通知的值;
pulPreviousNotifyValue:对象任务的上一个任务通知值,如果为 NULL, 则不需要回传, 这个时
候就等价于函数 xTaskNotify()。

返回值:
如果被通知任务还没取走上一个通知,又接收了一个通知,则这次通知值未能更新并返回pdFALSE, 而其他情况均返回pdPASS。
BaseType_t xTaskNotifyGive( TaskHandle_t xTaskToNotify );

//参数:xTaskToNotify:接收通知的任务句柄, 并让其自身的任务通知值加 1。
//返回值:总是返回pdPASS。

2.等待通知

等待通知 API 函数只能用在任务,不可应用于中断中!

等待通知

函数描述
ulTaskNotifyTake()
获取任务通知,可以设置在退出此函数的时候将任务通知值清零或者减 一。当任务通知用作二值信号量或者计数信号量的时候,使用此函数来 获取信号量。
xTaskNotifyWait()
获取任务通知,比  ulTaskNotifyTak() 更为复杂,可获取通知值和清除通 知值的指定位

 

uint32_t ulTaskNotifyTake ( BaseType_t xClearCountOnExit , TickType_t xTicksToWait );

参数:xClearCountOnExit:指定在成功接收通知后,将通知值清零或减 1pdTRUE:把通知值清零(二 值信号量);pdFALSE:把通知值减一(计数型信号量); xTicksToWait:阻塞等待任务通知值 的最大时间;

返回值:0:接收失败 非0:接收成功,返回任务通知的通知值

BaseType_t xTaskNotifyWait ( uint32_t ulBitsToClearOnEntry ,
uint32_t ulBitsToClearOnExit ,
uint32_t * pulNotificationValue ,
TickType_t xTicksToWait );
ulBitsToClearOnEntry :函数执行前清零任务通知值那些位 。
ulBitsToClearOnExit :表示在函数退出前,清零任务通知值那些位,在清 0 前,接收到的任务通知值会先被保存到形参 *pulNotificationValue 中。
pulNotificationValue :用于保存接收到的任务通知值。 如果 不需要使 用,则设置为 NULL 即可 。
xTicksToWait :等待消息通知的最大等待时间。

 二、实验

1.模拟二值信号量和计数型信号量

void StartTaskSend(void const * argument)
{
  
  for(;;)
  {
		if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == RESET)
			{
			if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == RESET)
			{
				xTaskNotifyGive(TaskReceiveHandle);
				//printf("任务通知:模拟二值信号量发送成功 !\r\n");
				printf("任务通知:模拟计数型信号量发送成功 !\r\n");
			}
			while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == RESET);
			}
				
				
    osDelay(1);
  }
}
void StartTaskReceive(void const * argument)
{
  
	uint32_t rev;

  for(;;)
  {
		if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) == RESET)
			{
			if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) == RESET)
			{
				//rev = ulTaskNotifyTake(pdTRUE,portMAX_DELAY);//当为pdTRUE的时候,模拟的为二值信号量
				rev = ulTaskNotifyTake(pdFALSE,portMAX_DELAY);//当为pdFALSE的时候,模拟的是计数型信号量
				if(rev != 0)
				//printf("任务通知:模拟二值信号量接收成功 !\r\n");
							printf("任务通知:模拟计数型信号量接收成功 ! rev=%d \r\n",rev);
			}
			while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) == RESET);
			}
				
    osDelay(1);
  }
 
}

模拟计数型信号量实验结果:

模拟二值信号量结果:

2.模拟事件标志组和模拟邮箱

2.1模拟事件标志组

void StartTaskSend(void const * argument)
{
 
	uint16_t buf = 100;
	BaseType_t status;
  for(;;)
  {
		if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==GPIO_PIN_RESET)
		{
		osDelay(20);
			if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==GPIO_PIN_RESET)
				{	
				printf("将bit0位置为1\r\n");
					xTaskNotify(taskReceiveHandle,0x01,eSetBits);
			}
				while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==GPIO_PIN_RESET);
		}
		
			if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1)==GPIO_PIN_RESET)
		{
		osDelay(20);
			if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1)==GPIO_PIN_RESET)
				{	
				printf("将bit1位置为1\r\n");
					xTaskNotify(taskReceiveHandle,0x02,eSetBits);
			}
				while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1)==GPIO_PIN_RESET);
		}
    osDelay(10);
  }
  
}
void StartTaskRecive(void const * argument)
{

	uint32_t notify_val = 0, event_bit = 0;
 
  for(;;)
  {	
	xTaskNotifyWait(0,0XFFFFFFFF,&notify_val,portMAX_DELAY);
		if(notify_val & 0x01)
			event_bit |= 0x01;
		if(notify_val & 0x02)
			event_bit |= 0x02;
		if(event_bit == (0x01 | 0x02))
		{
			printf("任务通知模拟事件标志组接收成功!\r\n");
			event_bit = 0; 
		}
    osDelay(1);
  }

}

实验结果:

 2.2 模拟邮箱

StartTaskSend:

void StartTaskSend(void const * argument)
{
  
	uint16_t buf = 100;
	BaseType_t status;
 
  for(;;)
  {
		if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==GPIO_PIN_RESET)
		{
		osDelay(20);
			if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==GPIO_PIN_RESET)
				{	
				printf("按键1按下\r\n");
					xTaskNotify(taskReceiveHandle,1,eSetValueWithOverwrite);//相比于事件标志组,改为了eSetValuewithOverwrit,ulValue变成了1
			}
				while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==GPIO_PIN_RESET);
		}
		
			if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1)==GPIO_PIN_RESET)
		{
		osDelay(20);
			if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1)==GPIO_PIN_RESET)
				{	
				printf("按键2按下\r\n");
					xTaskNotify(taskReceiveHandle,2,eSetValueWithOverwrite);//eSetValueWithoutOverwrite相比于eSetValueWithOverwrite会复写,不影响最终实验结果
			}
				while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1)==GPIO_PIN_RESET);
		}
    osDelay(10);
  }
  
}

StartTaskRecive:

void StartTaskRecive(void const * argument)
{

	uint32_t notify_val = 0, event_bit = 0;

  for(;;)
  {	
	xTaskNotifyWait(0,0XFFFFFFFF,&notify_val,portMAX_DELAY);
		printf("接收到的通知值为:%d\r\n",notify_val);
    osDelay(1);
  }

}

实验结果:

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

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

相关文章

成功解决:com.alibaba.druid.support.logging.JakartaCommonsLoggingImpl.

文章底部有个人公众号:热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享? 踩过的坑没必要让别人在再踩,自己复盘也能加深记忆。利己利人、所谓双赢。 前言 使用Spring 整合 mybatis的时候 报错…

Linux Traefik工具Dashboard结合内网穿透实现远程访问

文章目录 前言1. Docker 部署 Trfɪk2. 本地访问traefik测试3. Linux 安装cpolar4. 配置Traefik公网访问地址5. 公网远程访问Traefik6. 固定Traefik公网地址 前言 Trfɪk 是一个云原生的新型的 HTTP 反向代理、负载均衡软件,能轻易的部署微服务。它支持多种后端 (D…

【Mac开发环境搭建】Docker安装Redis、Nacos

文章目录 Dokcer安装Redis拉取镜像创建配置文件创建容器连接测试Redis连接工具[Quick Redis]设置Redis自启动 Docker安装Nacos Dokcer安装Redis 拉取镜像 docker pull redis创建配置文件 # bind 127.0.0.1 -::1 bind 0.0.0.0 # 是否启用保护模式 protected-mode no# redis端口…

服务器集群配置LDAP统一认证高可用集群(配置tsl安全链接)-centos9stream-openldap2.6.2

写在前面 因之前集群为centos6,已经很久没升级了,所以这次配置统一用户认证也是伴随系统升级到centos9时一起做的配套升级。新版的openldap配置大致与老版本比较相似,但有些地方配置还是有变化,另外,铺天盖地的帮助文…

【数据结构】【版本1.2】【线性时代】——链表之王(双向带头循环)

目录 引言 链表的分类 双向链表的结构 双向链表的实现 定义 创建新节点 初始化 打印 尾插 头插 判断链表是否为空 尾删 头删 查找与修改 指定插入 指定删除 销毁 顺序表和双向链表的优缺点分析 双向链表oj题 源代码 dlist.h dlist.c test.…

Python实现求解上个工作日逻辑

目录 一、需求描述二、代码实现三、测试结果 一、需求描述 因工作需要,现需获取任意一个日期的上个工作日,要求考虑法定假日及周末。 例如:2024年2月10日(春节)的上一个工作日为2024年2月9日,2024年2月17…

【入门篇】1.7 Redis 之 codis 入门介绍

文章目录 1. 简介2. Codis的安装与配置下载编译源码安装1. 安装 Go 运行环境2. 设置编译环境3. 下载 Codis 源代码4. 编译 Codis 源代码 Docker 部署 3. Codis的架构Codis的架构图和组件Codis的工作流程 4. Codis的核心特性自动数据分片数据迁移高可用性全面支持Redis命令分布式…

java代码审计(入门级)—基础漏洞合集

目录 (一)前言 (二)经典漏洞的代码审计 1、SQL注入 漏洞原理: 连接数据库的方式: 代码审计 2、XXE(XML外部实体注入) 漏洞原理 代码审计: 3、xss 漏洞原理 X…

LeetCode之二叉树

发现更多计算机知识,欢迎访问Cr不是铬的个人网站 最近数据结构学到二叉树,就刷了刷力扣,写这篇文章也是辅助记忆。 103二叉树锯齿形遍历 要解出本道题,首先要会层次遍历。层次遍历我们都知道用一个队列去实现就行。但是力扣这里…

【软件安装】Centos系统中安装docker容器(华为云HECS云耀服务器)

这篇文章,主要介绍Centos系统中安装docker容器(华为云HECS云耀服务器)。 目录 一、安装docker 1.1、卸载旧版本docker 1.2、更新repo镜像 1.3、安装依赖包 1.4、添加docker-ce镜像 1.5、安装docker-ce 1.6、查看docker安装版本 1.7、…

MATLAB 机械臂逆运动学进行轨迹控制建模

系列文章目录 文章目录 系列文章目录前言一、模型概览1.1 Target Pose Generation 目标姿势生成1.2 Inverse Kinematics 逆运动学1.3 Manipulator Dynamics 机械手动力学1.4 Pose Measurement 姿势测量 二、机械手定义三、生成航点四、模型设置五、模拟机械手运动六、将结果可视…

振南技术干货集:比萨斜塔要倒了,倾斜传感器快来!(2)

注解目录 1、倾斜传感器的那些基础干货 1.1 典型应用场景 (危楼、边坡、古建筑都是对倾斜敏感的。) 1.2 倾斜传感器的原理 1.2.1 滚珠式倾斜开关 1.2.2 加速度式倾斜传感器 1)直接输出倾角 2)加速度计算倾角 3)倾角精度的提高 (如果…

2023年亚太杯数学建模思路 - 复盘:人力资源安排的最优化模型

文章目录 0 赛题思路1 描述2 问题概括3 建模过程3.1 边界说明3.2 符号约定3.3 分析3.4 模型建立3.5 模型求解 4 模型评价与推广5 实现代码 建模资料 0 赛题思路 (赛题出来以后第一时间在CSDN分享) https://blog.csdn.net/dc_sinor?typeblog 1 描述 …

【LeetCode】每日一题 2023_11_16 最长奇偶子数组(枚举,模拟)

文章目录 刷题前唠嗑K 个元素的最大和题目描述代码与解题思路 结语 刷题前唠嗑 LeetCode? 启动!!! 今天早上概率论期中,被爆杀完之后,下午数电,今天很疲惫很疲惫,一直拖到了现在,终…

【论文阅读】A Survey on Video Diffusion Models

视频扩散模型(Video Diffusion Model)最新综述GitHub 论文汇总-A Survey on Video Diffusion Models。 paper:[2310.10647] A Survey on Video Diffusion Models (arxiv.org) 0. Abstract 本文介绍了AIGC时代视频扩散模型的全面回顾。简要介…

目标检测—YOLO系列(一)(YOLOv1/2/v3/4/5/x/6/7/8)

目标检测概述 什么是目标检测? 滑动窗口(Sliding Window) 滑动窗口的效率问题和改进 滑动窗口的效率问题:计算成本很大 改进思路 1:使用启发式算法替换暴力遍历 例如 R-CNN,Fast R-CNN 中使用 Selectiv…

docker 部署日志平台出错汇总

第一次运行elasticsearch:8.11.1镜像,报错如下: [rootmaster ~]# docker run --name es03 --net elastic -p 9200:9200 -it -m 1GB docker.elastic.co/elasticsearch/elasticsearch:8.11.1 docker: Error response from daemon: driver failed programmi…

网络编程TCP/UDP通信

1 网络通信概述 1.1 IP 和端口 所有的数据传输,都有三个要素 :源、目的、长度。 怎么表示源或者目的呢?请看图 所以,在网络传输中需要使用“IP 和端口”来表示源或目的。 1.2 网络传输中的 2 个对象:server 和 cl…

面向配电网韧性提升的移动储能预布局与动态调度策略(matlab代码)

欢迎关注威♥“电击小子程高兴的MATLAB小屋”获取更多资料 该程序复现《面向配电网韧性提升的移动储能预布局与动态调度策略》,具体摘要内容见下图,程序主要分为两大模块,第一部分是灾前预防代码,该部分采用两阶段优化算法&#…

YOLOv8-Seg改进策略:全新的聚焦式线性注意力模块Focused Linear Attention | ICCV2023

🚀🚀🚀本文改进:深入分析了现有线性注意力方法的缺陷,并提出了一个全新的聚焦的线性注意力模块(Focused Linear Attention),同时具有高效性和很强的模型表达能力。 🚀🚀🚀YOLOv8-seg创新专栏:http://t.csdnimg.cn/KLSdv 学姐带你学习YOLOv8,从入门到创新,…