【正点原子FreeRTOS学习笔记】————(15)FreeRTOS任务通知

这里写目录标题

一、任务通知的简介(了解)

任务通知:用来通知任务的,任务控制块中的结构体成员变量 ulNotifiedValue就是这个通知值

使用队列、信号量、事件标志组时都需另外创建一个结构体,通过中间的结构体进行间接通信!

使用任务通知时,任务结构体TCB中就包含了内部对象,可以直接接收别人发过来的"通知"

任务通知值的更新方式

1、不覆盖接受任务的通知值

2、覆盖接受任务的通知值

3、更新接受任务通知值的一个或多个bit

4、增加接受任务的通知值

只要合理,灵活的利用任务通知的特点,可以在一些场合中替代队列、信号量、事件标志组!

任务通知的优势及劣势

二、任务通知值和通知状态(熟悉)

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

c 复制代码
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 类型,用来表示通知状态

任务通知值

任务通知值的更新方式有多种类型:

任务通知状态

其中任务通知状态共有3种取值:

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

三、任务通知相关API函数介绍(熟悉)

任务通知API函数主要有两类:①发送通知 ,②接收通知。

注意:发送通知API函数可以用于任务和中断服务函数中;接收通知API函数只能用在任务中。
①发送通知相关API函数:

c 复制代码
#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 )

任务通知方式共有以下几种:

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

②接收通知相关API函数:

总结:

当任务通知用作于信号量时,使用函数获取信号量:ulTaskNotifyTake()

当任务通知用作于事件标志组或队列时,使用此函数来获取: xTaskNotifyWait()

c 复制代码
#define ulTaskNotifyTake( xClearCountOnExit  ,   xTicksToWait ) 			\
        ulTaskGenericNotifyTake( ( tskDEFAULT_INDEX_TO_NOTIFY ),			\
        				         ( xClearCountOnExit ), 					\
        				         ( xTicksToWait ) ) 

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

c 复制代码
#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 );

四、任务通知模拟信号量实验(掌握)

1、实验目的:学习使用 FreeRTOS 中的任务通知功能模拟二值信号量和计数型信号量

2、实验设计:将设计三个任务:start_task、task1、task2

三个任务的功能如下:

a.模拟二值信号量

c 复制代码
/* 任务一,发送任务通知值 */
void task1( void * pvParameters )
{
    uint8_t key = 0;
    
    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");
        }
    }
}

b.计数型信号量

c 复制代码
/* 任务一,发送任务通知值 */
void task1( void * pvParameters )
{
    uint8_t key = 0;
    
    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);
    }
}

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

1、实验目的:学习使用 FreeRTOS 中的任务通知功能模拟消息邮箱

2、实验设计:将设计三个任务:start_task、task1、task2

三个任务的功能如下:

c 复制代码
/* 任务一,发送任务通知值 */
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

三个任务的功能如下:

c 复制代码
#define EVENTBIT_0  (1 << 0)
#define EVENTBIT_1  (1 << 1)

/* 任务一,发送任务通知值*/
void task1( void * pvParameters )
{
    uint8_t key = 0;
    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 notify_val = 0,event_bit = 0;
    while(1)
    {
        xTaskNotifyWait( 0, 0xFFFFFFFF, &notify_val, portMAX_DELAY );
        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;
        }
    }
}
相关推荐
月阳羊几秒前
【硬件-笔试面试题】硬件/电子工程师,笔试面试题-26,(知识点:硬件电路的调试方法:信号追踪,替换,分段调试)
笔记·嵌入式硬件·面试·职场和发展
Dcs26 分钟前
“SQL注入即服务”:一个10年历史系统的奇幻演变
java
秃了也弱了。29 分钟前
reflections:Java非常好用的反射工具包
java·开发语言
Star在努力1 小时前
14-C语言:第14天笔记
c语言·笔记·算法
Amagi.1 小时前
Java设计模式-代理模式
java·代理模式
Joker—H2 小时前
【Java】Reflection反射(代理模式)
java·开发语言·经验分享·代理模式·idea
阿里巴巴淘系技术团队官网博客2 小时前
面向互联网2C业务的分布式类Manus Java框架
java·开发语言·分布式
霜绛2 小时前
机器学习笔记(三)——决策树、随机森林
人工智能·笔记·学习·决策树·随机森林·机器学习
躲在云朵里`3 小时前
Java面试题(中等)
java
懂得节能嘛.3 小时前
【SpringAI实战】实现仿DeepSeek页面对话机器人(支持多模态上传)
java·spring