freeRTOS总结(十四)任务通知

1、任务通知

任务通知: 用来通知任务的,任务控制块中的结构体成员变量ulNotifiedValue就是这个通知值
使用队列、信号量、事件标志组时都需另外创建一个结构体,通过中间的结构体进行间接通信!
在这里插入图片描述
使用任务通知时,任务结构体TCB中就包含了内部对象,可以直接接收别人发过来的"通知"
在这里插入图片描述
也就是说任务通知实现任务之间不同过中间结构体完成消息通讯

任务通知值的更新方式
不覆盖接受任务的通知值
覆盖接受任务的通知值
更新接受任务通知值的一个或多个bit
增加接受任务的通知值
只要合理,灵活的利用任务通知的特点,可以在一些场合中替代队列、信号量、事件标志组!

任务通知的优势及劣势
任务通知的优势:
效率更高:使用任务通知向任务发送事件或数据比使用队列、事件标志组或信号量快得多
使用内存更小 使用其他方法时都要先创建对应的结构体,使用任务通知时无需额外创建结构体
任务通知的劣势:
无法发送数据给ISR:ISR没有任务结构体,所以无法给ISR发送数据。但是ISR可以使用任务通知的功能,发数据给任务。
无法广播给多个任务 :任务通知只能是被指定的一个任务接收并处理
无法缓存多个数据:任务通知是通过更新任务通知值来发送数据的,任务结构体中只有一个任务通知值,只能保持一个数据。
发送受阻不支持阻塞:发送方无法进入阻塞状态等待

2,任务通知值和通知状态

任务都有一个结构体:任务控制块TCB,它里边有两个结构体成员变量:
在这里插入图片描述

任务通知值
任务通知值的更新方式有多种类型:
计数值(数值累加,类似信号量)
相应位置一(类似事件标志组)
任意数值(支持覆写和不覆写,类似队列)

任务通知状态
其中任务通知状态共有3种取值:
在这里插入图片描述

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

3,任务通知相关API函数介绍(熟悉)

任务通知API函数主要有两类:①发送通知 ,②接收通知。
注意:发送通知API函数可以用于任务和中断服务函数中;接收通知API函数只能用在任务中。
①发送通知相关API函数:
在这里插入图片描述

#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 )
BaseType_t	 xTaskGenericNotify(  TaskHandle_t 	xTaskToNotify,
                                   			    UBaseType_t 	uxIndexToNotify,
                                   			    uint32_t 		ulValue,
                                   			    eNotifyAction 	eAction,
                                  			    uint32_t * 		pulPreviousNotificationValue  )

在这里插入图片描述
任务通知方式共有以下几种:

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

在这里插入图片描述
当任务通知用作于信号量时,使用函数获取信号量:ulTaskNotifyTake()
当任务通知用作于事件标志组或队列时,使用此函数来获取: xTaskNotifyWait()

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

此函数用于接收任务通知值,可以设置在退出此函数的时候将任务通知值清零或者减一
在这里插入图片描述
在这里插入图片描述

#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	    ); 

在这里插入图片描述
在这里插入图片描述

4,任务通知模拟信号量实验(掌握)

1、实验目的:学习使用 FreeRTOS 中的任务通知功能模拟二值信号量和计数型信号量
2、实验设计:将设计三个任务:start_task、task1、task2
三个任务的功能如下:
start_task 用来创建task1和task2任务
task1 用于按键扫描,当检测到按键KEY0被按下时,将发送任务通知
task2 用于接收任务通知,并打印相关提示信息


#include "freertos_demo.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./SYSTEM/delay/delay.h"
#include "./MALLOC/malloc.h"
/*FreeRTOS*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.h"
#include "event_groups.h"
/******************************************************************************************************/
/*FreeRTOS配置*/

/* START_TASK 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
/* TASK1 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
 
#define START_TASK_PRIO         1
#define START_TASK_STACK_SIZE   128
TaskHandle_t    start_task_handler;
void start_task( void * pvParameters );

#define TASK1_PRIO         2
#define TASK1_STACK_SIZE   128
TaskHandle_t  task1_handler;
void task1( void * pvParameters );


/* TASK2 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define TASK2_PRIO         3
#define TASK2_STACK_SIZE   128
TaskHandle_t   task2_handler;
void task2( void * pvParameters );





/**
 * @brief       FreeRTOS例程入口函数
 * @param       无
 * @retval      无
 */
	void freertos_demo(void)
{ 
	


	xTaskCreate((TaskFunction_t) start_task,
							(char *)	"start_task",
							(configSTACK_DEPTH_TYPE) START_TASK_STACK_SIZE,
							(void *) NULL,
							(UBaseType_t) START_TASK_PRIO,
							(TaskHandle_t *)&start_task_handler
	
	);
							
	//开启任务调度
	vTaskStartScheduler();
	
}
void start_task( void * pvParameters )
{
	
	
		taskENTER_CRITICAL();               /* 进入临界区  任何任务和中断都不能打断当前程序运行*/

		xTaskCreate((TaskFunction_t) task1,
							(char *)	"task1",
							(configSTACK_DEPTH_TYPE) TASK1_STACK_SIZE,
							(void *) NULL,
							(UBaseType_t) TASK1_PRIO,
							(TaskHandle_t *)&task1_handler	);
							
		xTaskCreate((TaskFunction_t) task2,
							(char *)	"task2",
							(configSTACK_DEPTH_TYPE) TASK2_STACK_SIZE,
							(void *) NULL,
							(UBaseType_t) TASK2_PRIO,
							(TaskHandle_t *)&task2_handler	);


	vTaskDelete(NULL);//删除当前任务也就是开始任务
	taskEXIT_CRITICAL();
							
	

}
/* 任务一,用于扫描按键,当KEY0按下,发送任务通知值 */
void task1( void * pvParameters )
{
		uint8_t key;
		while(1)
		{
			key=key_scan(0);
			if(key==KEY0_PRES)
			{
				printf("任务通知模拟二值信号量释放!\r\n");
				//发送通知不带通知值 参数为通知的任务句柄
				xTaskNotifyGive(task2_handler);
			}
		
			vTaskDelay(10);
		}
		
}
/* 任务二,读取队列集中的消息并打印*/
void task2( void * pvParameters )
{
	uint32_t rev =0 ;
	while(1)
	{
		//返回值为任务调用期间接收到的任务通知次数
		rev=ulTaskNotifyTake(pdTRUE,portMAX_DELAY);
		if(rev!=0)
		{
			printf("接收任务通知成功,模拟获取二值信号量!\r\n");
			printf("rev val is %ld\r\n",rev);
		}
	}
}

5,任务通知模拟消息邮箱实验(掌握)

1、实验目的:学习使用 FreeRTOS 中的任务通知功能模拟消息邮箱
2、实验设计:将设计三个任务:start_task、task1、task2
三个任务的功能如下:
start_task 用于按键扫描,将按下的按键键值通过任务通知发送给指定任务
task2 用于接收任务通知,并根据接收到的数据做相应动作


#include "freertos_demo.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./SYSTEM/delay/delay.h"
#include "./MALLOC/malloc.h"
/*FreeRTOS*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.h"
#include "event_groups.h"
/******************************************************************************************************/
/*FreeRTOS配置*/

/* START_TASK 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define START_TASK_PRIO         1
#define START_TASK_STACK_SIZE   128
TaskHandle_t    start_task_handler;
void start_task( void * pvParameters );

/* TASK1 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define TASK1_PRIO         2
#define TASK1_STACK_SIZE   128
TaskHandle_t    task1_handler;
void task1( void * pvParameters );


/* TASK2 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define TASK2_PRIO         3
#define TASK2_STACK_SIZE   128
TaskHandle_t    task2_handler;
void task2( void * pvParameters );

/******************************************************************************************************/
/**
 * @brief       FreeRTOS例程入口函数
 * @param       无
 * @retval      无
 */
void freertos_demo(void)
{    
    xTaskCreate((TaskFunction_t         )   start_task,
                (char *                 )   "start_task",
                (configSTACK_DEPTH_TYPE )   START_TASK_STACK_SIZE,
                (void *                 )   NULL,
                (UBaseType_t            )   START_TASK_PRIO,
                (TaskHandle_t *         )   &start_task_handler );
    vTaskStartScheduler();
}


void start_task( void * pvParameters )
{
    taskENTER_CRITICAL();               /* 进入临界区 */
    
    xTaskCreate((TaskFunction_t         )   task1,
                (char *                 )   "task1",
                (configSTACK_DEPTH_TYPE )   TASK1_STACK_SIZE,
                (void *                 )   NULL,
                (UBaseType_t            )   TASK1_PRIO,
                (TaskHandle_t *         )   &task1_handler );
                
    xTaskCreate((TaskFunction_t         )   task2,
                (char *                 )   "task2",
                (configSTACK_DEPTH_TYPE )   TASK2_STACK_SIZE,
                (void *                 )   NULL,
                (UBaseType_t            )   TASK2_PRIO,
                (TaskHandle_t *         )   &task2_handler );
                             
    vTaskDelete(NULL);
    taskEXIT_CRITICAL();                /* 退出临界区 */
}

/* 任务一,发送任务通知值 */
void task1( void * pvParameters )
{
    uint8_t key = 0;
    
    while(1) 
    {
        key = key_scan(0);
        if((key != 0) && (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 );
        switch(noyify_val)
        {
            case KEY0_PRES:
            {
                printf("接收到的通知值为:%d\r\n",noyify_val);
                LED0_TOGGLE();
                break;
            }
            case KEY1_PRES:
            {
                printf("接收到的通知值为:%d\r\n",noyify_val);
                LED1_TOGGLE();
                break;
            }
            default : break;
        }
    }
}

任务通知模拟事件标志组实验(掌握)

1、实验目的:学习使用 FreeRTOS 中的任务通知功能模拟事件标志组
2、实验设计:将设计三个任务:start_task、task1、task2
三个任务的功能如下:
start_task 用来创建task1和task2任务
task1 用于按键扫描,当检测到按键按下时,发送任务通知设置不同标志位
task2 用于接收任务通知,并打印相关提示信息

#define START_TASK_PRIO         1
#define START_TASK_STACK_SIZE   128
TaskHandle_t    start_task_handler;
void start_task( void * pvParameters );

#define TASK1_PRIO         2
#define TASK1_STACK_SIZE   128
TaskHandle_t  task1_handler;
void task1( void * pvParameters );


/* TASK2 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define TASK2_PRIO         3
#define TASK2_STACK_SIZE   128
TaskHandle_t   task2_handler;
void task2( void * pvParameters );


#define EVENTBIT_0  (1 << 0)
#define EVENTBIT_1  (1 << 1)


/**
 * @brief       FreeRTOS例程入口函数
 * @param       无
 * @retval      无
 */
	void freertos_demo(void)
{ 
	


	xTaskCreate((TaskFunction_t) start_task,
							(char *)	"start_task",
							(configSTACK_DEPTH_TYPE) START_TASK_STACK_SIZE,
							(void *) NULL,
							(UBaseType_t) START_TASK_PRIO,
							(TaskHandle_t *)&start_task_handler
	
	);
							
	//开启任务调度
	vTaskStartScheduler();
	
}
void start_task( void * pvParameters )
{
	
	
		taskENTER_CRITICAL();               /* 进入临界区  任何任务和中断都不能打断当前程序运行*/

		xTaskCreate((TaskFunction_t) task1,
							(char *)	"task1",
							(configSTACK_DEPTH_TYPE) TASK1_STACK_SIZE,
							(void *) NULL,
							(UBaseType_t) TASK1_PRIO,
							(TaskHandle_t *)&task1_handler	);
							
		xTaskCreate((TaskFunction_t) task2,
							(char *)	"task2",
							(configSTACK_DEPTH_TYPE) TASK2_STACK_SIZE,
							(void *) NULL,
							(UBaseType_t) TASK2_PRIO,
							(TaskHandle_t *)&task2_handler	);


	vTaskDelete(NULL);//删除当前任务也就是开始任务
	taskEXIT_CRITICAL();
							
	

}
/* 任务一,用于扫描按键,当KEY0按下,发送任务通知值 */
void task1( void * pvParameters )
{
		uint8_t key;
		while(1)
		{
			key=key_scan(0);
			if(key==KEY0_PRES)
			{
				printf("将bit0位置为1\r\n");
				xTaskNotify(task2_handler,EVENTBIT_0,eSetBits);
			}
			else if(key==KEY1_PRES)
			{
				printf("将bit1位置为1\r\n");
				xTaskNotify(task2_handler,EVENTBIT_1,eSetBits);
			
			}
		
			vTaskDelay(10);
		}
		
}
/* 任务二,读取队列集中的消息并打印*/
void task2( void * pvParameters )
{
	uint32_t rev =0 ;
	uint32_t event_bit =0;
	while(1)
	{
		//接收前通知值不清零,接收后通知值全部清零,通知值给到rev
		xTaskNotifyWait(0,0xFFFFFFFF,&rev,portMAX_DELAY);
		if(rev&EVENTBIT_0)
		{
			event_bit|=EVENTBIT_0;
		}
		if(rev&EVENTBIT_1)
		{
			event_bit|=EVENTBIT_1;
		}
		if(event_bit==(EVENTBIT_0|EVENTBIT_1))
		{
			printf("任务通知模拟事件标志组接收成功!!\r\n");
			event_bit=0;
		}
	}
}

7、模拟计数信号量

#include "freertos_demo.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./SYSTEM/delay/delay.h"
#include "./MALLOC/malloc.h"
/*FreeRTOS*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.h"
#include "event_groups.h"
/******************************************************************************************************/
/*FreeRTOS配置*/

/* START_TASK 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
/* TASK1 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
 
#define START_TASK_PRIO         1
#define START_TASK_STACK_SIZE   128
TaskHandle_t    start_task_handler;
void start_task( void * pvParameters );

#define TASK1_PRIO         2
#define TASK1_STACK_SIZE   128
TaskHandle_t  task1_handler;
void task1( void * pvParameters );


/* TASK2 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define TASK2_PRIO         3
#define TASK2_STACK_SIZE   128
TaskHandle_t   task2_handler;
void task2( void * pvParameters );



/**
 * @brief       FreeRTOS例程入口函数
 * @param       无
 * @retval      无
 */
	void freertos_demo(void)
{ 
	


	xTaskCreate((TaskFunction_t) start_task,
							(char *)	"start_task",
							(configSTACK_DEPTH_TYPE) START_TASK_STACK_SIZE,
							(void *) NULL,
							(UBaseType_t) START_TASK_PRIO,
							(TaskHandle_t *)&start_task_handler
	
	);
							
	//开启任务调度
	vTaskStartScheduler();
	
}
void start_task( void * pvParameters )
{
	
	
		taskENTER_CRITICAL();               /* 进入临界区  任何任务和中断都不能打断当前程序运行*/

		xTaskCreate((TaskFunction_t) task1,
							(char *)	"task1",
							(configSTACK_DEPTH_TYPE) TASK1_STACK_SIZE,
							(void *) NULL,
							(UBaseType_t) TASK1_PRIO,
							(TaskHandle_t *)&task1_handler	);
							
		xTaskCreate((TaskFunction_t) task2,
							(char *)	"task2",
							(configSTACK_DEPTH_TYPE) TASK2_STACK_SIZE,
							(void *) NULL,
							(UBaseType_t) TASK2_PRIO,
							(TaskHandle_t *)&task2_handler	);


	vTaskDelete(NULL);//删除当前任务也就是开始任务
	taskEXIT_CRITICAL();
							
	

}
/* 任务一,用于扫描按键,当KEY0按下,发送任务通知值 */
void task1( void * pvParameters )
{
		uint8_t key;
		while(1)
		{
			key=key_scan(0);
			if(key==KEY0_PRES)
			{
				printf("任务通知模拟计数信号量被释放\r\n");
				xTaskNotifyGive(task2_handler);
			}
			vTaskDelay(10);
		}
		
}
/* 任务二,读取队列集中的消息并打印*/
void task2( void * pvParameters )
{
	uint32_t rev =0 ;
	while(1)
	{
		rev=ulTaskNotifyTake(pdFALSE,portMAX_DELAY);
		if(rev!=0)
		{
			printf("rev:%d\r\n",rev);
		}
		vTaskDelay(1000);
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值