首页 > 其他分享 >【嵌入式——FreeRTOS】任务通知

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

时间:2024-07-05 09:31:35浏览次数:15  
标签:task2 FreeRTOS 通知 嵌入式 发送 任务 bit 接收

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

简介

任务通知:就是用来通知任务的,任务控制块中的结构体成员变量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;
		}
	}
}

标签:task2,FreeRTOS,通知,嵌入式,发送,任务,bit,接收
From: https://blog.csdn.net/weixin_39723539/article/details/140198461

相关文章

  • 从零开始学习嵌入式——C语言数值传递(值传递和地址传递)
        C语言实现主函数与被调用子函数变量之间数值交换的方法。 1、值传递:主函数中的数值并未实现交换。2、地址传递:交换的是指针指向,a,b并未实现交换 3、传递地址,交换地址实现值的交换 4、传入地址,定义的子函数 知道了主函数传递的地址参数才能对主函数当中......
  • FreeRTOS之队列上锁和解锁(详解)
     这篇文章将记录我学习实时操作系统FreeRTOS的队列上锁和解锁的知识,在此分享给大家,希望我的分享能给你带来不一样的收获!目录一、简介 二、队列上锁函数prvLockQueue()1、函数初探2、应用示例  三、队列解锁函数prvUnLockQueue() 1、函数初探及详细注释详细注释解......
  • 嵌入式软件架构(第一部分)
    事件驱动架构非常适合实时和资源受限的嵌入式系统,这些系统响应能力和高效的资源利用率至关重要。事件驱动架构中,系统响应来自各种来源的事件或异步消息,例如硬件中断、用户输入或网络消息。系统旨在通过调用特定的事件处理程序或回调来处理事件。此架构通过依赖事件作为主要通......
  • 基于全数字实时仿真的嵌入式DevOps解决方案
    ​为丰富浙江省信息技术应用创新(以下简称“信创”)产业生态,在全社会各领域形成示范效应,浙江省经信厅联合省密码管理局开展2023年浙江省深化信创典型案例评选工作。经过征集申报、专家评选、名单公示等程序,确定36个应用示范案例和24个典型解决方案。【典型解决方案】基于全数......
  • 使用阿里云语音服务实现设备异常实时通知
    随着物联网的普及,设备异常通知方式也变得多种多样。从传统的后台异常列表,到短信通知,再到微信消息通知等。然而,当设备探测到火警等紧急异常时,需要实时通知到相关人员。本文将介绍如何借助阿里云的语音服务来实现这一功能。1.准备工作1.1资质申请首先,登录阿里云语音服务,进行......
  • 探索鸿蒙开发:鸿蒙系统如何引领嵌入式技术革新
    嵌入式技术已经成为现代社会不可或缺的一部分。而在这个领域,华为凭借其自主研发的鸿蒙操作系统,正悄然引领着一场技术革新的浪潮。本文将探讨鸿蒙开发的特点、优势以及其对嵌入式技术发展的深远影响。鸿蒙操作系统的特点鸿蒙,作为华为推出的全新操作系统,具有许多显著的特点......
  • FreeRTOS移植到STM32
    本内容主要是讲解关于如果把FreeRTOS移植到STM32中去的操作。明白各部分的作用以及打通思路,具体操作按照下列进行相应的操作。第一:早一个STM32的裸机程序我们这里用的是STM32F103的芯片为例。 二、去官网上下载FreeRTOSV9.0.0源码在移植之前,我们首先要获取到......
  • 电子计算机类比赛的“武林秘籍”-电赛光电设计大赛计算机设计大赛嵌入式芯片与系统设
    电子计算机类比赛的“武林秘籍”-电赛光电设计大赛计算机设计大赛嵌入式芯片与系统设计竞赛,你要的都在这里!为什么需要参加电子计算机类比赛对于实现短期目标而言:电子计算机类学科竞赛获奖可以实现:保研加分、综测加分(申请奖学金)、校内奖金经费和校外比赛收益、助力评奖评优、丰......
  • 《安富莱嵌入式周报》第339期:单片机运行苹果早期Mac系统模拟器,2GHz示波器有源探头,下一
    周报汇总地址:http://www.armbbs.cn/forum.php?mod=forumdisplay&fid=12&filter=typeid&typeid=104 视频版https://www.bilibili.com/video/BV1Kf421Q7Lh目录1、开源2GHz的示波器有源探头2、模拟矩阵开关面包板Jumperless推出下一代JumperlessV53、软件相关(1)Swifton......
  • 邮件通知提醒邮箱设置教程及API代码示例!
    邮件通知的警告功能如何配置?详细教程与API代码示例!无论是业务提醒、账户活动警告,还是个人事务,邮件通知已经成为一种重要的沟通工具。AokSend将详细介绍如何设置邮件通知提醒邮箱,并提供相应的API代码示例,帮助你更高效地管理信息流。邮件通知:选择务提供商常见的有Gmail、Outl......