FreeRTOS(CMSIS)-(6)-任务通知

目录

一、什么是任务通知

二、任务通知值的更新方式

三、任务通知的优势和劣势

3-1 任务通知的优势

3-2 任务通知的劣势

四、任务通知相关 API 函数

4-1 发送通知

4-2 等待通知

五、测试程序


一、什么是任务通知

        FreeRTOS 从版本 V8.2.0 开始提供任务通知这个功能,每个任务都有一个 32 位的通知值。按照 FreeRTOS官方的说法,使用消息通知比通过二进制信号量方式解除阻塞任务快 45%, 并且更加省内存(无需创建队列)。
       在大多数情况下,任务通知可以替代二值信号量、计数信号量、事件标志组,可以替代长度为 1 的队列(可以保存一个 32 位整数或指针值),并且任务通知速度更快、使用的RAM更少!

二、任务通知值的更新方式

FreeRTOS 提供以下几种方式发送通知给任务 :
1.发送消息给任务,如果有通知未读, 不覆盖通知值
2.发送消息给任务,直接覆盖通知值
3.发送消息给任务,设置通知值的一个或者多个位
4.发送消息给任务,递增通知值
通过对以上方式的合理使用,可以在一定场合下替代原本的队列、信号量、事件标志组等

三、任务通知的优势和劣势

3-1 任务通知的优势

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

3-2 任务通知的劣势

1. 只有任务可以等待通知,中断服务函数中不可以,因为中断没有 TCB 。
2. 通知只能一对一,因为通知必须指定任务。
3. 等待通知的任务可以被阻塞, 但是发送消息的任务,任何情况下都不会被阻塞等待。
4. 任务通知是通过更新任务通知值来发送数据的,任务结构体中只有一个任务通知值,只能保持一个数据。

四、任务通知相关 API 函数

4-1 发送通知

/*
 * -------------函数---------------------------------------描述-------------------
 *| xTaskNotify()                | 发送通知,带有通知值
 *|------------------------------|----------------------------------------------
 *| xTaskNotifyAndQuery()        | 发送通知,带有通知值并且保留接收任务的原通知值
 *|------------------------------|----------------------------------------------
 *| xTaskNotifyGive()            | 发送通知,不带通知值
 *|------------------------------|----------------------------------------------
 *| xTaskNotifyFromISR()         | 在中断中发送任务通知
 *|------------------------------|----------------------------------------------
 *| xTaskNotifyAndQueryFromISR() | 在中断中发送任务通知
 *|------------------------------|----------------------------------------------
 *| vTaskNotifyGiveFromISR()     | 在中断中发送任务通知
 *|------------------------------|----------------------------------------------
 *
 * */
/*
 *  参数:
 *        xTaskToNotify:需要接收通知的任务句柄;
 *        ulValue:用于更新接收任务通知值, 具体如何更新由形参 eAction 决定;
 *        eAction:一个枚举,代表如何使用任务通知的值;
 *
 *
 *         -------------枚举值-------------------------------描述------------------------
 *        | eNoAction                    | 发送通知,但不更新值(参数ulValue未使用)
 *        |------------------------------|----------------------------------------------
 *        | eSetBits                     | 被通知任务的通知值按位或ulValue。(某些场景下可代替事件组,效率更高)
 *        |------------------------------|----------------------------------------------
 *        | eIncrement                   | 被通知任务的通知值增加1(参数ulValue未使用),相当于xTaskNotifyGive
 *        |------------------------------|----------------------------------------------
 *        | eSetValueWithOverWrite       | 被通知任务的通知值设置为 ulValue。(某些场景下可代替xQueueOverwrite ,效率更高)
 *        |------------------------------|----------------------------------------------
 *        | eSetValueWithoutOverwrite    | 如果被通知的任务当前没有通知,则被通知的任务的通知值设为ulValue。如果被通知任务没有取走上一个通知,又接收到了一个通知,则这次通知值丢弃,在这种情况下视为调用失败并返回 pdFALSE(某些场景下可代替 xQueueSend ,效率更高)
 *        |------------------------------|----------------------------------------------
 *
 *  返回值:
 *        如果被通知任务还没取走上一个通知,又接收了一个通知,则这次通知值未能更新并返回 pdFALSE, 而其他情况均返回pdPASS。
 *
 *
 *
 *        BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify,uint32_t ulValue,eNotifyAction eAction );
 *
 * */
/*
 *  参数:
 *          xTaskToNotify:需要接收通知的任务句柄;
 *          ulValue:用于更新接收任务通知值, 具体如何更新由形参 eAction 决定;
 *          eAction:一个枚举,代表如何使用任务通知的值;
 *          pulPreviousNotifyValue:对象任务的上一个任务通知值,如果为 NULL, 则不需要回传, 这个时候就等价于函数 xTaskNotify()。
 *
 *  返回值:
 *         如果被通知任务还没取走上一个通知,又接收了一个通知,则这次通知值未能更新并返回 pdFALSE, 而其他
 *         情况均返回pdPASS。
 *
 *
 *         BaseType_t xTaskNotifyAndQuery( TaskHandle_t xTaskToNotify,uint32_t ulValue,eNotifyAction eAction,uint32_t *pulPreviousNotifyValue );
 *
 * */

/*
 *  参数:
 *         xTaskToNotify:接收通知的任务句柄, 并让其自身的任务通知值加 1。 
 *  返回值:
 *         总是返回 pdPASS。
 * 
 *         BaseType_t xTaskNotifyGive( TaskHandle_t xTaskToNotify );
 * 
 * */

4-2 等待通知

  等待通知API函数只能用在任务,不可应用于中断中!

/*
 *         -------------函数-------------------------------描述------------------------
 *        | ulTaskNotifyTake()           | 获取任务通知,可以设置在退出此函数的时候将任务通知值清零或者减一。当任务通知用作二值信号量或者计数信号量的时候,使用此函数来获取信号量。
 *        |------------------------------|----------------------------------------------
 *        | xTaskNotifyWait()            | 获取任务通知,比 ulTaskNotifyTak()更为复杂,可获取通知值和清除通知值的指定位
 *        |------------------------------|----------------------------------------------
 *
 * */
/*
 *  参数:
 *         xClearCountOnExit:指定在成功接收通知后,将通知值清零或减 1,pdTRUE:把通知值清零(二值信号量);pdFALSE:把通知值减一(计数型信号量);
 *         xTicksToWait:阻塞等待任务通知值的最大时间;
 *
 *  返回值:
 *         0:接收失败
 *         非0:接收成功,返回任务通知的通知值
 *
 *
 *         uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit,TickType_t xTicksToWait );
 *
 *
 * */
/*
 *  BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry,uint32_t ulBitsToClearOnExit,uint32_t *pulNotificationValue,TickType_t xTicksToWait );
 * 
 * 
 *  ulBitsToClearOnEntry:函数执行前清零任务通知值那些位 。
 *  ulBitsToClearOnExit:表示在函数退出前,清零任务通知值那些位,在清 0 前,接收到的任务通知值会先被
 *  保存到形参*pulNotificationValue 中。
 *  pulNotificationValue:用于保存接收到的任务通知值。 如果 不需要使用,则设置为 NULL 即可 。
 *  xTicksToWait:等待消息通知的最大等待时间。
 * 
 * 
 * */

五、测试程序

#include "wu_task.h"


/*
 * FreeRTOS中任务共存在4种状态:
   (1)Running 运行态
--------------------------当任务处于实际运行状态称之为运行态,即CPU的使用权被这个任务占用(同一时间仅一个任务处于运行态)。
   (2)Ready 就绪态
--------------------------处于就绪态的任务是指那些能够运行(没有被阻塞和挂起),但是当前没有运行的任务,因为同优先级或更高优先级的任务正在运行。
   (3)Blocked 阻塞态
--------------------------如果一个任务因延时,或等待信号量、消息队列、事件标志组等而处于的状态被称之为阻塞态。
   (4)Suspended 挂起态
--------------------------类似暂停,通过调用函数 vTaskSuspend() 对指定任务进行挂起,挂起后这个任务将不被执行,只有调用函数 xTaskResume() 才可以将这个任务从挂起态恢复。
 *
 * 常用的一些函数用法:
 *              osThreadSuspend(WUTask02Handle);//挂起态  暂停任务
 *              osThreadResume(WUTask02Handle);//就绪态 恢复任务
 *              osThreadTerminate(defaultTaskHandle);//删除任务 终止一个线程的执行并将其从活动线程中移除
 *
 *
 * */

extern osMessageQId WUQueue01Handle;//声明一个外部的信号量队列(消息队列)
extern osSemaphoreId WUBinarySem01Handle;//声明一个外部的二进制信号量句柄
extern osSemaphoreId WUCountingSem01Handle;//声明一个外部的计数信号量句柄
extern osMutexId WUMutex01Handle;//声明一个外部的互斥锁(互斥量)

EventGroupHandle_t eventgroup_handle;// 声明事件组句柄

//WUBinarySem01Handle = xSemaphoreCreateBinary();


u8 wu_cs=5;
u8 d1,d2;
uint16_t buf = 100;

// 声明一个事件位变量,初始值为0
EventBits_t wu_bit = 0;


void WU_Task_1(viod)
{
	BaseType_t status;


	if(click()==1)
	{
		wu_cs++;buf=123;
//		status = xQueueSend(WUQueue01Handle, &buf, 0);//写入队列
//		if (status == pdTRUE)
//			d1=1;
//		else
//			d1=0;

//		if (xSemaphoreGive(WUBinarySem01Handle) == pdTRUE)
//			d1=1;
//		else
//			d1=0;

//		if (xSemaphoreGive(WUCountingSem01Handle) == pdTRUE)
//			d1=1;
//		else
//			d1=0;

//	xEventGroupSetBits(eventgroup_handle, 0x01);// KEY1 按下

		xTaskNotifyGive(WUBinarySem01Handle);//任务通知:模拟二值信号量发送成功
		Seria1_Printf("TXD:任务通知:模拟二值信号量发送成功");

	}

//	xSemaphoreTake(WUMutex01Handle, portMAX_DELAY);
//	Seria1_Printf("TaskH: ON! \r\n");
//	HAL_Delay(1000);
//	//osDelay(1000);
//	Seria1_Printf("TaskH: OK! \r\n");
//	xSemaphoreGive(WUMutex01Handle);
//	osDelay(1000);


}


void WU_Task_2(viod)
{
	LED_GREEN_TogglePin;
	osDelay(1000);

//	Seria1_Printf("TaskM: CPU-STOP!!! \r\n");
//	osDelay(1000);

//	wu_bit = xEventGroupWaitBits(eventgroup_handle, 0x01 | 0x02, pdTRUE, pdFALSE, portMAX_DELAY);
//	Seria1_Printf("wu_bit:%#x\r\n", wu_bit);

}




void WU_Task_3(viod)
{
	BaseType_t status;
	uint32_t ydd = 0;

	if(click_2()==1)
	{
		wu_cs--;
//		status = xQueueReceive(WUQueue01Handle, &buf, 0);//读取队列
//		if (status == pdTRUE)
//			d2=1;
//		else
//			d2=0;

//		if(xSemaphoreTake(WUBinarySem01Handle, portMAX_DELAY ) == pdTRUE)
//			d2=1;
//		else
//			d2=0;

//		if (xSemaphoreTake(WUCountingSem01Handle, 0 ) == pdTRUE)
//			d2=1;
//		else
//			d2=0;

//		xEventGroupSetBits(eventgroup_handle, 0x02);// KEY2 按下

		ydd = ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
		if(ydd != 0)
			Seria1_Printf("RXD:任务通知:模拟二值信号量接收成功!\r\n");

	}

//	xSemaphoreTake(WUMutex01Handle, portMAX_DELAY);
//	Seria1_Printf("TaskL: ON! \r\n");
//	HAL_Delay(3000);
//	//osDelay(3000);
//	Seria1_Printf("TaskL: OK! \r\n");
//	xSemaphoreGive(WUMutex01Handle);
//	osDelay(1000);
}



void WU_Task_4(viod)
{
	//Seria1_Printf("WU");
	//Wu_xsp_Proc();
	//Wu_Mai_Proc();
	Wu_Led_Proc();
	Wu_Key_Proc();

	WU_OLED_U8G2_ClearBuffer();

	WU_OLED_U8G2_SetFont(u8g2_font_wqy13_t_gb2312a);//选择字库


//	WU_OLED_U8G2_Printf(0,15,CHINA,"温度:%d℃",16);
//	WU_OLED_U8G2_Printf(0,30,CHINA,"湿度:%d",58);
//
//	d1?WU_OLED_U8G2_Printf(0,45,CHINA,"写入队列值:%d",buf):WU_OLED_U8G2_Printf(0,45,CHINA,"写入队列失败");
//	d2?WU_OLED_U8G2_Printf(0,60,CHINA,"读取队列值:%d",buf):WU_OLED_U8G2_Printf(0,60,CHINA,"读取队列失败");



	WU_OLED_U8G2_SendBuffer();
}












void StartTask02(void const * argument)
{

	while(1)
	{
		WU_Task_2();
	}

}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值