【嵌入式——FreeRTOS】任务通知

【嵌入式——FreeRTOS】任务通知

  • 简介
    • 任务通知值的更新方式
    • 任务通知优势
    • 任务通知劣势
  • 任务通知值和通知状态
    • 任务通知值的类型
    • 任务通知状态
  • 相关API
    • 发送通知相关API函数
    • 接收通知相关API
  • 任务通知模拟二值信号量代码示例
  • 任务通知模拟消息邮箱代码示例
  • 任务通知模拟事件标志组代码示例

简介

任务通知:就是用来通知任务的,任务控制块中的结构体成员变量ulNotifiedValue就是这个通知值。
使用队列、信号量、事件标志组时都需另外创建一个结构体,通过中间的结构体进行间接通信。
使用任务通知时,任务结构体TCB中就包含了内部对象,可以直接接收别人发过来的通知

任务通知值的更新方式

  1. 不覆盖接受任务的通知值
  2. 覆盖接受任务的通知值
  3. 更新接受任务通知值的一个或多个bit
  4. 增加接受任务的通知值

任务通知优势

  1. 效率更高:使用任务通知向任务发送事件或数据比使用队列、事件标志组或信号量快的多。
  2. 使用内存更小:使用其他方法时都要先创建对应的结构体,使用任务通知时无需额外创建结构体

任务通知劣势

  1. 无法发送数据给ISR:ISR没有任务结构体,所以无法给ISR发送数据,但是ISR可以使用任务通知的功能发数据给任务
  2. 无法广播给多个任务:任务通知只能是被指定的一个任务接收并处理
  3. 无法缓存多个数据:任务通知时通过更新任务通知值来发送数据的,任务结构体中只有一个任务通知值,只能保持一个数据
  4. 发送受阻不支持阻塞:发送方无法进入阻塞状态等待

任务通知值和通知状态

任务都有一个结构体:任务控制块TCB,它里边包含两个结构体成员变量

typedef struct tskTaskControlBlock       /* The old naming convention is used to prevent breaking kernel aware debuggers. */
{
	......
	    #if ( configUSE_TASK_NOTIFICATIONS == 1 )
        volatile uint32_t ulNotifiedValue[ configTASK_NOTIFICATION_ARRAY_ENTRIES ]; //用来表示任务通知值
        volatile uint8_t ucNotifyState[ configTASK_NOTIFICATION_ARRAY_ENTRIES ]; //用来表示通知状态
    #endif

}

#define configTASK_NOTIFICATION_ARRAY_ENTRIES    1

任务通知值的类型

  1. 计数值(数值累加,类似信号量)
  2. 相应位置1(类似事件标志组)
  3. 任意数值(支持覆写和不覆写,类似队列)
typedef enum
{
    eNoAction = 0,            /* 无操作*/
    eSetBits,                 /* 更新指定bit*/
    eIncrement,               /* 通知值加1*/
    eSetValueWithOverwrite,   /* 覆写的方式更新通知值*/
    eSetValueWithoutOverwrite /* 不覆写通知值*/
} eNotifyAction;

任务通知状态

  1. 任务未等待通知:任务通知默认的初始化状态
  2. 任务在等待通知:接收方已经准备好了(调用了接收任务通知函数),等待发送方给个通知
  3. 任务在等待接收:发送方已经发送出去(调用了发送任务通知函数),等待接收方接收
#define taskNOT_WAITING_NOTIFICATION              ( ( uint8_t ) 0 ) /* Must be zero as it is the initialised value. */
#define taskWAITING_NOTIFICATION                  ( ( uint8_t ) 1 )
#define taskNOTIFICATION_RECEIVED                 ( ( uint8_t ) 2 )

相关API

发送通知API函数可以用于任务和中断服务函数中,接收通知API函数只能用在任务中。

发送通知相关API函数

函数描述
xTaskNotify()发送通知,带有通知值
xTaskNotifyAndQuery()发送通知,带有通知值并且保留接收任务的原通知值
xTaskNotifyGive()发送通知,不带通知值
xTaskNotifyFromISR()在中断中发送任务通知
xTaskNotifyAndQueryFromISR()在中断中发送任务通知
vTaskNotifyGiveFromISR()在中断中发送任务通知
//xTaskToNotify  接收任务通知的任务句柄
//tskDEFAULT_INDEX_TO_NOTIFY 任务的指定通知
//ulValue 任务通知值(任务通知相关数组成员)
//eAction 通知方式(通知值更新方式) eNotifyAction
#define xTaskNotify( xTaskToNotify, ulValue, eAction ) \
    xTaskGenericNotify( 
	( xTaskToNotify ), 
	( tskDEFAULT_INDEX_TO_NOTIFY ), 
	( ulValue ), 
	( eAction ), 
	NULL )

//pulPreviousNotifyValue 用于保存更新前的任务通知值(为NULL则不保存)
#define xTaskNotifyAndQuery( xTaskToNotify, ulValue, eAction, pulPreviousNotifyValue ) \
    xTaskGenericNotify( 
	( xTaskToNotify ), 
	( tskDEFAULT_INDEX_TO_NOTIFY ), 
	( ulValue ), 
	( eAction ), 
	( pulPreviousNotifyValue ) )


#define xTaskNotifyGive( xTaskToNotify ) \
    xTaskGenericNotify( 
	( xTaskToNotify ), 
	( tskDEFAULT_INDEX_TO_NOTIFY ), 
	( 0 ), 
	eIncrement, 
	NULL )

接收通知相关API

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

当任务通知用作于信号量时,使用函数获取信号量ulTaskNotifyTake。
当任务通知用作于事件标志组或队列时,使用此函数来获取xTaskNotifyWait。

//tskDEFAULT_INDEX_TO_NOTIFY 任务的指定通知(任务通知相关数组成员)
//xClearCountOnExit 指定在成功接收通知后,将通知值清零或减1 pdTRUE:清零 pdFALSE:把通知值减1
//xTicksToWait 阻塞等待任务通知值的最大时间
//返回值 0 接收失败 非0 接收成功,返回任务通知的通知值
#define ulTaskNotifyTake( xClearCountOnExit, xTicksToWait ) \
    ulTaskGenericNotifyTake( 
	( tskDEFAULT_INDEX_TO_NOTIFY ), 
	( xClearCountOnExit ), 
	( xTicksToWait ) )

//tskDEFAULT_INDEX_TO_NOTIFY 任务的指定通知(任务通知相关数组成员)
//ulBitsToClearOnEntry 等待前清零指定任务通知值的bit位(旧值对应bit值清0)
//ulBitsToClearOnExit 成功等待后清零指定的任务通知值bit(新值对应bit清0)
//pulNotificationValue 用于取出通知值(如果不需要取出设为NULL)
//xTicksToWait 阻塞等待任务通知值的最大时间
//返回值 pdTRUE等待任务通知成功 pdFALSE等待任务通知失败
#define xTaskNotifyWait( ulBitsToClearOnEntry, ulBitsToClearOnExit, pulNotificationValue, xTicksToWait ) \
    xTaskGenericNotifyWait( 
	tskDEFAULT_INDEX_TO_NOTIFY, 
	( ulBitsToClearOnEntry ), 
	( ulBitsToClearOnExit ), 
	( pulNotificationValue ), 
	( xTicksToWait ) )

任务通知模拟二值信号量代码示例

#include "queue.h"
#inculde "sempht.h"

TaskHandle_t	task1_handler;
TaskHandle_t	task2_handler;

void init(){
	//创建两个任务 task1 task2
}

//发送任务通知值
void task1(){
	uint8_t = key = 0;
	while(1){
		if(满足条件){
			xTaskNotifyGive(task2_handler);
		}
	}
}

//接收任务通知值
void task2(){
	uint32_t ret = 0;
	while(1){
		if(满足条件){
			ret = ulTaskNotifyTake(pdTRUE,portMAX_DELAY);
			if(ret != 0){
				printf("接收任务通知成功"\r\n);
			}
		}
	}
}

任务通知模拟消息邮箱代码示例

#include "queue.h"
#inculde "sempht.h"

TaskHandle_t	task1_handler;
TaskHandle_t	task2_handler;

void init(){
	//创建两个任务 task1 task2
}

//发送任务通知值
void task1(){
	uint8_t = key = 0; //通知值
	while(1){
		key = key_scan(0);
		if(key != 0){
			xTaskNotify(task2_handler,key ,eSetValueWithOverwrite);
		}
	}
}

//接收任务通知值
void task2(){
	uint32_t ret = 0;
	uint32_t notify_val = 0; //通知值
	while(1){
		if(满足条件){
			//0xFFFFFFFF  bit位全部清零
			ret = xTaskNotifyWait(0,0xFFFFFFFF,&notify_val ,portMAX_DELAY);
			switch(notify_val){
				case KEY0_PRES:
					printf("key0");
					break;
				case KEY1_PRES:
					printf("key1");
					break;
			}
			
		}
	}
}

任务通知模拟事件标志组代码示例

#include "queue.h"
#inculde "sempht.h"
#define EVENTBIT_0 (1 << 0)
#define EVENTBIT_1 (1 << 1)

TaskHandle_t	task1_handler;
TaskHandle_t	task2_handler;

void init(){
	//创建两个任务 task1 task2
}

//发送任务通知值
void task1(){
	uint8_t = key = 0; //通知值
	while(1){
		key = key_scan(0);
		if(key == KEY0_PRES){
			//将bit0位置置1
			xTaskNotify(task2_handler,EVENTBIT_0 ,eSetBits);
		} else if(key == KEY1_PRES){
			//将bit1位置置1
			xTaskNotify(task2_handler,EVENTBIT_1 ,eSetBits);
		}
	}
}

//接收任务通知值
void task2(){
	uint32_t event_bit = 0;
	uint32_t notify_val = 0; //通知值

	while(1){
		 
		//0xFFFFFFFF  bit位全部清零
		ret = xTaskNotifyWait(0,0xFFFFFFFF,&notify_val ,portMAX_DELAY);
		if(notify_val & EVENTBIT_0){
			event_bit |= EVENTBIT_0;
		}else if(notify_val & EVENTBIT_1){
			event_bit |= EVENTBIT_1;
		}
		if(event_bit  == (EVENTBIT_0|EVENTBIT_1)){
			printf("任务通知模拟事件标志组接收成功\r\n");			
			event_bit = 0;
		}
	}
}

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

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

相关文章

【Proteus】按键的实现『⒉种』

&#x1f6a9; WRITE IN FRONT &#x1f6a9; &#x1f50e; 介绍&#xff1a;"謓泽"正在路上朝着"攻城狮"方向"前进四" &#x1f50e;&#x1f3c5; 荣誉&#xff1a;2021|2022年度博客之星物联网与嵌入式开发TOP5|TOP4、2021|2222年获评…

微信小程序毕业设计-走失人员的报备平台系统项目开发实战(附源码+论文)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;微信小程序毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计…

【Python学习】流程控制、函数与类详解

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 引言 Python作为一门强大而又简洁的编程语言&#xff0c;提供了丰富的工具和结构来帮助开发者编写清晰、高效的代码。在本文中…

企业搭建知识库:解锁无限潜力的钥匙

在当今这个信息爆炸的时代&#xff0c;企业如何高效地管理、传播与利用知识&#xff0c;已成为衡量其竞争力的重要标尺。知识库&#xff0c;作为这一背景下的产物&#xff0c;正逐步成为企业不可或缺的数字资产。它不仅是一个自助式的数字门户&#xff0c;更是连接员工、客户与…

加入AIGC的小艺还有这些大用处 快来看

说到毕业&#xff0c;有不舍、有迷茫也有期待&#xff0c;在这种复杂的情绪里&#xff0c;手机里的小艺&#xff0c;简直是贴心小棉袄&#xff0c;给了我很多依靠&#xff0c;让我能勇敢的往前走。 在离别时候有太多的不舍&#xff0c;想要写段寄语记录下来&#xff0c;这时候小…

记录AllWinner H700芯片 LCD屏幕显示不正常,有色块问题

现象&#xff1a; 修改后&#xff1a; 文档&#xff1a; 测试命令&#xff08;需要kernel打开 CONFIG_DEVMEMy&#xff09;&#xff1a; 读取&#xff1a; devmem2 $((0x6511000 0x0088)) w 写入&#xff1a; devmem2 $((0x6511000 0x0088)) w 0x7000000 代码&#xff1…

程序员自由创业周记#37:程序员创业的几个方向

程序员自由创业周记#37&#xff1a;程序员创业的几个方向 报志愿 这几天亲戚一外甥报志愿&#xff0c;让我推荐&#xff0c;我基于自己的认知觉得还是计算机相关是第一优选&#xff0c;即便现在各大互联网公司都过得不怎么好&#xff0c;裁员的消息此起彼伏&#xff0c;很多计…

从零到一:eBay自养号测评全流程解析与实操建议

eBay自养号测评是一种通过模拟真实买家行为&#xff0c;为卖家提供市场反馈并提升店铺权重和排名的技术手段。以下是进行eBay自养号测评的具体步骤和注意事项&#xff1a; 一、准备阶段 1. 技术配置&#xff1a;搭建境外服务器&#xff1a;选择稳定的境外服务器&#xff0c;模…

内网学习第6天 liunx定时任务 环境变量和权限配置,以及数据库提权

内网学习的第5天呢&#xff1f;&#xff1f;我就没有写&#xff0c;那个主要就是利用内核漏洞以及suid&#xff0c;来进行提权的。 我在虚拟机上面进行提权&#xff0c;我没有成功&#xff0c;我本地的虚拟机呢&#xff0c;扫出来的漏洞poc也没有让我提权成功。所以我就没有写…

知识图谱构建助手安装配置使用!Sapphire Ventures最全Sales AI图谱:AI如何重塑销售行业?

知识图谱构建助手安装配置使用!Sapphire Ventures最全Sales AI图谱:AI如何重塑销售行业? 项目简介 llmgraph 使您能够从给定的源实体维基百科页面创建 GraphML、GEXF 和 HTML 格式(通过 pyvis 生成)的知识图。知识图谱是通过从 ChatGPT 或 LiteLLM 支持的其他大型语言模型…

从零开始开发跑腿配送系统:技术选型与架构设计

开发一个跑腿配送系统涉及多个技术栈和模块&#xff0c;从前端到后端&#xff0c;再到数据库和实时通信&#xff0c;每一个环节都至关重要。本文将详细介绍从零开始开发跑腿配送系统的技术选型与架构设计&#xff0c;并提供部分代码示例以帮助理解。 一、技术选型 前端技术&am…

视频号矩阵源码:构建短视频生态的基石

在数字化时代&#xff0c;视频内容已成为连接品牌与消费者的重要桥梁。视频号矩阵源码&#xff0c;作为短视频营销自动化的创新引擎&#xff0c;正在帮助内容创作者和营销团队以前所未有的效率和智能&#xff0c;管理和扩展他们的视频内容。本文将深入探讨视频号矩阵源码的核心…

13-错误-ERROR: duplicate key value violates unique constraint “ux_xxx“

13-错误-ERROR: duplicate key value violates unique constraint “ux_xxx” 更多内容欢迎关注我&#xff08;持续更新中&#xff0c;欢迎Star✨&#xff09; Github&#xff1a;CodeZeng1998/Java-Developer-Work-Note 技术公众号&#xff1a;CodeZeng1998&#xff08;纯纯…

代谢组数据分析(十二):岭回归、Lasso回归、弹性网络回归构建预测模型

欢迎大家关注全网生信学习者系列: WX公zhong号:生信学习者Xiao hong书:生信学习者知hu:生信学习者CDSN:生信学习者2介绍 在代谢物预测模型的构建中,我们采用了三种主流的回归分析方法:岭回归、Lasso回归以及弹性网络回归。这三种方法各有其独特的原理和适用场景,因此在…

从0构建一款appium-inspector工具

上一篇博客从源码层面解释了appium-inspector工具实现原理&#xff0c;这篇博客将介绍如何从0构建一款简单的类似appium-inspector的工具。如果要实现一款类似appium-inspector的demo工具&#xff0c;大致需要完成如下六个模块内容 启动 Appium 服务器连接到移动设备或模拟器启…

HTML+CSS笔记

标签 HTML标签 网页的大包围 整体网页内容的外衣 所有的网页文档内容都要写在 html标签内 lang属性&#xff0c;是指内容语言的&#xff0c;目的是让浏览器知晓这个页面的主要展示语言 是什么 只跟浏览器的翻译有关 主要展示的语言如果是英语 en&#xff0c;主要展示的语言如果…

移动硬盘传输中断后无法识别:深度解析与数据救援指南

在日常的数据存储与传输过程中&#xff0c;移动硬盘凭借其大容量、便携性成为众多用户的首选。然而&#xff0c;当我们在复制或移动大量数据时遭遇传输中断&#xff0c;随后发现移动硬盘无法被电脑识别&#xff0c;这无疑是一场数据安全的紧急警报。此情此景&#xff0c;不仅影…

Docker学习笔记(三)Dockerfile

一、什么是Dockerfile Dockerfile 是一个用于自动化构建 Docker 镜像的文本文件&#xff0c;其中包含了从一个基础镜像开始&#xff0c;到最终形成所需定制镜像的所有指令集。这个文件中的每一条指令都对应着构建镜像过程中的一个步骤或一层&#xff0c;指导 Docker 如何安装软…

红蓝对抗下的内网横向移动渗透技术详解

一、利用Windows计划任务横向移动 Windows计划任务是一个非常实用的功能&#xff0c;可以帮助我们自动完成一些重复性的任务。比如&#xff0c;我们可以设定一个计划任务来自动备份文件、更新软件、执行脚本等,本文主要介绍了如何利用Windows计划任务进行横向渗透。 &#xf…

线程池实践篇

文章目录 配置线程池参数定义参数实体bean配置线程池使用 配置线程池参数 定时任务线程池基础参数 # 定时任务线程池基础参数 task:pool:corePoolSize: 5 # 核心线程数maxPoolSize: 20 # 设置最大线程数keepAliveSeconds: 300 # 设置线程活跃时间&#xff0c;单位秒queueCapa…