FreeRTOS实时操作系统(十三)任务通知

news2024/11/24 9:28:48

系列文章目录


文章目录

  • 系列文章目录
  • 任务通知
  • 任务通知值和通知状态
    • 任务通知值
    • 通知状态
  • 任务通知API函数
    • 发送通知函数
    • 接收通知函数
  • 实验测试
    • 模拟二值信号量实验
    • 模拟计数型信号量
    • 模拟事件标志组实验
    • 模拟消息邮箱实验


任务通知

任务通知:用来通知任务的,任务控制块中的结构体成员变量 ulNotifiedValue就是这个通知值。
(相比队列、信号量和事件标志组,内存消耗比较小,不需要创建)

更新方式:
可以覆盖或不覆盖接收任务的通知值
更新接受任务通知值的一个或多个bit
增加接收任务的通知值

优势:
效率更高,比队列、信号量和事件标志组速度更快
使用内存更小,无需额外创建结构体
劣势:
无法发送数据给ISR,但ISR可以发送数据给任务
无法广播给多个任务:任务通知只能指定一个任务接收处理
无法缓存多个数据:结构体中只有一个任务通知值,只能保存一个数据
发送受阻不支持阻塞:发送方无法进入阻塞状态

任务通知值和通知状态

任务通知值

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

typedef  struct  tskTaskControlBlock 
{
	… …
    	#if ( configUSE_TASK_NOTIFICATIONS  ==  1 )
        	volatile  uint32_t  ulNotifiedValue [ configTASK_NOTIFICATION_ARRAY_ENTRIES ];
        	volatile  uint8_t   ucNotifyState [ configTASK_NOTIFICATION_ARRAY_ENTRIES ];
    	endif
	… …
} tskTCB;
#define  configTASK_NOTIFICATION_ARRAY_ENTRIES	1  	/* 定义任务通知数组的大小, 默认: 1 */

一个是 uint32_t 类型,用来表示通知值
一个是 uint8_t 类型,用来表示通知状态

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

通知状态

#define	taskNOT_WAITING_NOTIFICATION  	( ( uint8_t ) 0 )		 /* 任务未等待通知 */
#define 	taskWAITING_NOTIFICATION		( ( uint8_t ) 1 )		 /* 任务在等待通知 */
#define 	taskNOTIFICATION_RECEIVED                 	( ( uint8_t ) 2 )		 /* 任务在等待接收 */

任务未等待通知:任务通知的默认初始化,什么都不管
等待通知:接收方已经准备好了(调用了接收任务通知函数),等待发送方给个通知
等待接收:发送方已经发送出去(调用了发送任务通知函数),等待接收方接收

任务通知API函数

分为发送通知和接收通知两种

发送可以在任务或中断服务函数中,接收只能用在任务中。

发送通知函数

函数描述
xTaskNotify()发送通知,带有通知值(事件标志组)
xTaskNotifyAndQuery()发送通知,带有通知值并且保留接收任务的原通知值
xTaskNotifyGive()发送通知,不带通知值(信号量)
xTaskNotifyFromISR()在中断中发送任务通知
xTaskNotifyAndQueryFromISR()在中断中发送任务通知
vTaskNotifyGiveFromISR()在中断中发送任务通知

详细内容: 发送通知的函数:

#define   	xTaskNotifyAndQuery( xTaskToNotify ,  ulValue ,  eAction ,  pulPreviousNotifyValue  )	\ 
		    xTaskGenericNotify( ( xTaskToNotify ), 
					  ( tskDEFAULT_INDEX_TO_NOTIFY ), 
					  ( ulValue ), 
					  ( eAction ),
					  ( pulPreviousNotifyValue ) )

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

看到其核心函数都是xTaskGenericNotify()

BaseType_t	 xTaskGenericNotify(  TaskHandle_t 	xTaskToNotify,
                       			   UBaseType_t 	uxIndexToNotify,
                       			    uint32_t 		ulValue,
                       			    eNotifyAction 	eAction,
                      			    uint32_t * 		pulPreviousNotificationValue  )
形参描述
xTaskToNotify接收任务通知的任务句柄
uxIndexToNotify任务的指定通知(任务通知相关数组成员)
ulValue任务通知值
eAction通知方式(通知值更新方式)
pulPreviousNotificationValue用于保存更新前的任务通知值(为NULL则不保存)

任务通知方式:

typedef  enum
{    
	eNoAction = 0, 			/* 无操作 */
	eSetBits				/* 更新指定bit */
	eIncrement				/* 通知值加一 */
 	eSetValueWithOverwrite		/* 覆写的方式更新通知值 */
	eSetValueWithoutOverwrite	/* 不覆写通知值 */
} eNotifyAction;

接收通知函数

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

ulTaskNotifyTake在将任务通知用作信号量的时候
xTaskNotifyWait在将任务通知用作事件标志组或者队列的时候

1.ulTaskNotifyTake

#define ulTaskNotifyTake( xClearCountOnExit , xTicksToWait ) 			\
ulTaskGenericNotifyTake( ( tskDEFAULT_INDEX_TO_NOTIFY ),( xClearCountOnExit ), (xTicksToWait ) ) 

用于接收任务通知值,可以设置在退出此函数的时候将任务通知值清零或者减一。(信号量)

形参描述
uxIndexToWaitOn任务的指定通知(任务通知相关数组成员)
xClearCountOnExit指定在成功接收通知后,将通知值清零或减 1,pdTRUE:把通知值清零;pdFALSE:把通知值减一
xTicksToWait阻塞等待任务通知值的最大时间
返回值描述
0接收失败
非0接收成功,返回任务的通知值

2.xTaskNotifyWait

#define xTaskNotifyWait(ulBitsToClearOnEntry, ulBitsToClearOnExit, pulNotificationValue, xTicksToWait) \
xTaskGenericNotifyWait( tskDEFAULT_INDEX_TO_NOTIFY,( ulBitsToClearOnEntry ), ( ulBitsToClearOnExit ), ( pulNotificationValue ), ( xTicksToWait ) 

用于获取通知值和清除通知值的指定位值,适用于模拟队列和事件标志组,使用该函数来获取任务通知 。

BaseType_t  xTaskGenericNotifyWait( UBaseType_t uxIndexToWaitOn,
									uint32_t ulBitsToClearOnEntry,
									uint32_t ulBitsToClearOnExit,
									uint32_t * pulNotificationValue,
									TickType_t xTicksToWait	); 
形参描述
uxIndexToWaitOn任务的指定通知(任务通知相关数组成员)
ulBitesToClearOnEntry等待前清零指定任务通知值的比特位(旧值对应bit清0),将需要清零的位置1:例如0x01
ulBitesToClearOnExit成功等待后清零指定的任务通知值比特位(新值对应bit清0)
pulNotificationValue用来取出通知值(如果不需要取出,可设为NULL)
xTicksToWait阻塞等待任务通知值的最大时间
返回值描述
pdTRUE等待任务通知成功
pdFALSE等待任务通知失败

实验测试

模拟二值信号量实验

开始任务:创建任务1和任务2
任务1完成任务通知的功能
任务2完成接收任务通知,并且打印相关提示信息

void task1( void * pvParameters )
{
    while(1) 
    {
		printf("任务通知模拟二值信号量释放!\r\n");
		xTaskNotifyGive(task2_handler);
        vTaskDelay(20);
    }
}

void task2( void * pvParameters )
{
	uint32_t rev = 0;
    while(1)
    {
		 rev = ulTaskNotifyTake(pdTRUE , portMAX_DELAY);
        if(rev != 0)
        {
            printf("接收任务通知成功,模拟获取二值信号量!\r\n");
        }
    }
}

在这里插入图片描述

模拟计数型信号量

计数型信号量和二值信号量没啥区别,就是多次进行了任务通知,采用pdTRUE的形参在接收任务通知的时候,将通知值全部清空。

开始任务:创建任务1和任务2
任务1完成任务通知(计数型信号量不断累计)的功能
任务2完成接收任务通知,并且打印相关提示信息

void task1( void * pvParameters )
{
    while(1) 
    {
		printf("任务通知模拟计数型信号量释放!\r\n");
		xTaskNotifyGive(task2_handler);
        vTaskDelay(20);
    }
}

void task2( void * pvParameters )
{
	uint32_t rev = 0;
    while(1)
    {
		 rev = ulTaskNotifyTake(pdTRUE , portMAX_DELAY);
        if(rev != 0)
        {
            printf("rev:%d\r\n",rev);
        }
		vTaskDelay(1000);
    }
}

在这里插入图片描述

模拟事件标志组实验

开始任务:创建任务1和任务2
任务1完成任务通知,设置不同标志位
任务2完成接收任务通知,并且打印相关提示信息

#define EVENTBIT_0  (1 << 0)
#define EVENTBIT_1  (1 << 1)
 
void task1( void * pvParameters )
{
    while(1) 
    {
		printf("将bit0位置1\r\n");
		xTaskNotify( task2_handler, EVENTBIT_0, eSetBits );//模拟事件标志组,eSetBits代表更新指定bit的更新方式
		printf("将bit1位置1\r\n");
		xTaskNotify( task2_handler, EVENTBIT_1, eSetBits );
		vTaskDelay(10);
    }
}

void task2( void * pvParameters )
{
	 uint32_t notify_val = 0,event_bit = 0;
    while(1)
    {
		 xTaskNotifyWait( 0, 0xFFFFFFFF, &notify_val, portMAX_DELAY ); //成功等待后清零,因为通知值是32位,所以是0xFFFFFFFF
        if(notify_val & EVENTBIT_0)
        {
            event_bit |= EVENTBIT_0;
        }
        if(notify_val & EVENTBIT_1)
        {
            event_bit |= EVENTBIT_1;
        }
        if(event_bit == (EVENTBIT_0|EVENTBIT_1))
        {
            printf("任务通知模拟事件标志组接收成功!!\r\n");
            event_bit = 0;
        }
		
    }
}

在这里插入图片描述

模拟消息邮箱实验

开始任务:创建任务1和任务2
任务1完成任务通知,发送给指定任务
任务2完成接收任务通知,根据接收到数据完成信息打印

void task1( void * pvParameters )
{
	uint8_t key = 6;
    while(1) 
    {
		if(task2_handler != NULL)
		{
		printf("任务通知模拟消息邮箱发送,发送的键值为:%d\r\n",key);
		xTaskNotify( task2_handler, key, eSetValueWithOverwrite );
		}
		vTaskDelay(10);
    }
}

void task2( void * pvParameters )
{
	uint32_t noyify_val = 0;
    while(1)
    {
		xTaskNotifyWait( 0, 0xFFFFFFFF, &noyify_val, portMAX_DELAY );
		 printf("接收到的通知值为:%d\r\n",noyify_val);
    }
}

在这里插入图片描述

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

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

相关文章

ATMEGA16 Proteus仿真自动人体感应电风扇DS18B20温度 -0069

ATMEGA16 Proteus仿真自动人体感应电风扇DS18B20温度 -0069 Proteus仿真小实验&#xff1a; ATMEGA16 Proteus仿真自动人体感应电风扇DS18B20温度 -0069 功能&#xff1a; Protues版本&#xff1a;7.8 程序编写&#xff1a;ICCAVR:7.12 硬件组成&#xff1a;ATMEGA16单片机…

嵌入式开发之编码器速度采集

光电编码器&#xff0c;是一种通过光电转换将输出轴上的机械几何位移量转换成脉冲或数字量的传感器。这是应用最多的传感器&#xff0c;光电编码器是由光源、光码盘和光敏元件组成。光栅盘是在一定直径的圆板上等分地开通若干个长方形孔。由于光电码盘与电动机同轴&#xff0c;…

spark和zeppelin认证不一致:Only one of --proxy-user or --principal can be provided

spark和zeppelin认证不一致&#xff1a;Only one of --proxy-user or --principal can be provided 如果配置principal认证方式&#xff0c;zeppelin走的是hadoop权限&#xff0c;如果配置proxy-user认证方式&#xff0c;zeppelin走的是当前登录用户的权限&#xff08;ranger控…

GitHub上cambel的ur3项目调试经验

按照https://github.com/cambel/ur3/wiki/Compile-from-source配置环境时&#xff0c;遇到以下问题&#xff1a; catkin clean时报错 [clean] Error: The current or desired workspace could not be determined. Please run catkin clean from within a catkin workspace or…

【学会动态规划】第 N 个泰波那契数(1)

目录 动态规划怎么学&#xff1f; 1. 题目解析 2. 算法原理 1. 状态表示 2. 状态转移方程 3. 初始化 4. 填表顺序 5. 返回值 3. 代码编写 4. 空间优化 写在最后 动态规划怎么学&#xff1f; 学习一个算法没有捷径&#xff0c;更何况是学习动态规划&#xff0c; 跟…

MySQL 中索引是如何实现的,有哪些类型的索引,如何进行优化索引

MySQL 中的索引 前言 上篇文章聊完了 MySQL 中的锁&#xff0c;这里接着来看下 MySQL 中的索引。 一般当我们数据库中的某些查询比较慢的时候&#xff0c;正常情况下&#xff0c;一顿分析下来&#xff0c;大多数我们会考虑对这个查询加个索引&#xff0c;那么索引是如何工作的呢…

从零开始的前后端分离项目学习(前后端从零环境搭建)

一、 前后端分离介绍&#xff1a; 前端独立编写客户端代码&#xff08;用户交互数据展示&#xff09;&#xff0c;后端独立编写服务端代码&#xff08;提供数据处理接口&#xff09;&#xff0c;并提供数据接口就行。 前端通过Ajax访问后端数据借口&#xff0c;将model展示到…

使用VESD脉冲离子风机5年内至少可节省一半的维护成本

之前的文章有给大家详细介绍过&#xff0c;来自VESD的脉冲离子风机&#xff0c;它有着特殊的设计&#xff1a;插拔式结构和可水洗针架&#xff0c;因此对我们的很多客户来说&#xff0c;这款风机性价比是非常高的。 早在15年以前&#xff0c;VESD就对市面上大部分风机进行过测试…

解决Google浏览器网页覆盖问题

在使用 Google 进行搜索的时候出现打开新页面会覆盖当前页面的问题 针对此问题&#xff0c;解决方法如下&#xff1a; 1、首先在浏览器的地址栏中随便搜索内容 2、页面的 右上角有个⚙️的设置图标&#xff0c;点进去 点击 “查看所有设置” 3、在结果打开方式中进行勾选 设…

uniapp打包APP实现应用内整包更新或热更新

思路&#xff1a; 1.首先要理解更新方式的区别 静默更新、弱更新以及强制更新。 APP更新机制-静默更新、弱更新、强更新 - 知乎 2.其次要理解不同更新方式要用到的插件----------这里推荐插件应用市场的插件。 app升级、整包更新和热更新组件 支持vue3 支持打开安卓、苹果应…

使用 SMT求解机 根据变迁关系生成迁移后系统的状态

本文的例子来源于2011年发布的论文 IC3: Where Monolithic and Incremental Meet 文章目录 Ⅰ、变迁系统的介绍状态图变迁公式 Ⅱ、SMT求解机简介公式的计算计算另一状态 结果展示参考文献 Ⅰ、变迁系统的介绍 状态图 论文中给出了一个系统的状态迁移图和它的的变迁公式。现在…

【近场社交项目】数据库系统期末设计——概念设计部分

数据库系统期末设计——概念设计部分&#x1f60e; 前言&#x1f64c;项目设计&#xff08;1&#xff09;各个实体属性ER图&#xff08;2&#xff09;各个业务功能的ER图 总结撒花&#x1f49e; &#x1f60e;博客昵称&#xff1a;博客小梦 &#x1f60a;最喜欢的座右铭&#x…

【Redis】特殊数据类型 Geo (地理位置)

&#x1f3af;前言 除了五中基本的数据类型外&#xff0c;Redis还支持两种特殊的数据类型&#xff0c;第一种 Geo (地理位置)&#xff1a;用于存储地理位置相关的数据&#xff0c;例如经纬度、距离等。第二种 Stream (流)&#xff1a;是一个高级的列表类型&#xff0c;支持对列…

Python基于pandas库导出excel文件

将Pandas数据框架导出到Excel文件中 让我们看看如何将Pandas数据框架导出到Excel文件中。 实列代码&#xff1a; import time import pandas as pd from io import BytesIO from flask import make_response,def export_navi():# 所有DataFrame合并集合df_list []# 创建一个数…

理工大学|校企联手创典范,布局存储新未来

某理工大学地质灾害防治与地质环境保护国家重点实验室的前身是1989年由原国家计委、国家教委批准&#xff0c;在某理工大学&#xff08;原某地质学院&#xff09;“地质工程”国家重点学科基础上建立的国家专业实验室&#xff0c;该实验室是我国地质灾害防治领域目前唯一的国家…

唯一无副作用禁用Win10/11更新方法,一键暂停1000周

作为一个现代化的系统&#xff0c;Windows 很早便配备了自动更新功能以快速获取新功能、修复安全漏洞。 不过到实际使用中嘛&#xff0c;自动弹出、重启自动进行、新版本大量 Bug … 体验十分糟糕。 种种原因导致&#xff0c;经常就有朋友要禁止 Win10/11 自动更新方法。 我们…

MySQL-存储函数练习

创建表并插入数据 ​ 字段名 数据类型 主键 外键 非空 唯一 自增 ​ id INT 是 否 是 是 否 ​ name VARCHAR(50) 否 否 是 否 否 ​ glass VARCHAR(50) 否 否 是 否 否mysql>…

vue项目启动前端时让本地局域网其他设备访问本项目时的配置

文章目录 编辑package.json优化 编辑package.json "dev": "vite --host [本机ip]" ,案例 优化 这样的话实用性更好&#xff0c;我们访问的话依然可以正常访问服务端的ip "dev": "vite --host 0.0.0.0" ,

Kylin麒麟系统设置开机自动登录roo账户

1.安装麒麟系统后&#xff0c;默认root用户是不开启的&#xff0c;首先得设置root用户密码命令。 sudo passwd root 此时会要求输入密码&#xff0c;输入您当前用户登录密码即可。 2.以root权限修改 /usr/share/lightdm/lightdm.conf.d/60-kylin.conf 文件,如提示输入密码&am…

itheima苍穹外卖项目学习笔记--Day1:项目介绍与开发环境搭建

苍穹外卖 Day1:a. 项目概述b. 开发环境搭建(1). 前端环境搭建(2). 后端环境搭建(3). 前后端联调 c. 完善登录功能d. Swagger Day1: a. 项目概述 b. 开发环境搭建 (1). 前端环境搭建 前端工程基于 nginx 运行启动nginx&#xff1a;双击 nginx.exe 即可启动 nginx 服务&#x…