FreeRTOS任务通知与使用任务通知作事件标志组

目录

特性

应用限制

任务通知用作事件标志组

任务通知用作事件标志组的优点

任务通知用作事件标志组的缺点

部分API

测试程序


特性

每个任务都有一个32位的任务任务通知值,任务通知是直接发送到任务的事件,可以解除接收任务的阻塞。

任务通知可以通过下面四种方式更新任务通知值:

设置接收任务的通知值(不覆盖前面的值);

设置接收任务的通知值(覆盖前面的值);

设置接收任务通知值的一位或多位;

增加接收任务的通知值。

由于任务通知的灵活性,可以在需要使用单队列、二值信号量、计数信号量、事件标志组的时候使用它替代。使用任务通知解锁任务要比上面的方式快45%,且需要的ram更少。 

应用限制

  1. 任务通知只能被用在任务只有一个接收事件的情况下;
  2. 任务通知可以被用来代替队列:接收任务可以等待任务通知进入阻塞态,发送任务不会进入阻塞态,即使没有发送成功。

任务通知用作事件标志组

xTaskNotifyWait()            用来代替      xEventGroupWaitBits()

xTaskNotify()                   用来代替      xEventGroupSetBits()

xTaskNotifyFromISR()    用来代替      xEventGroupSetBitsFromISR()

任务通知用作事件标志组的优点

与xEventGroupSetBitsFromISR()相比,xTaskNotifyFromISR()具有显著的性能优势,因为xTaskNotifyFromISR()完全在ISR中执行,而xEventGroupSetBitsFromISR()必须将一些处理延迟到RTOS守护进程任务。

任务通知用作事件标志组的缺点

任务通知不能组合位判断,当有一位满足条件时,就离开阻塞状态,如果是组合位判断,需要额外判断。

部分API

xTaskNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction );
//发送任务通知,参数xTaskToNotify是发向的任务句柄,ulValue是发送的任务通知值,eAction 是发送的形式
xTaskNotifyFromISR( TaskHandle_t xTaskToNotify, 
uint32_t ulValue, 
eNotifyAction eAction, 
BaseType_t *pxHigherPriorityTaskWoken );//同上,用于中断函数中

xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, 
uint32_t ulBitsToClearOnExit, 
uint32_t *pulNotificationValue, 
TickType_t xTicksToWait );
//接收任务通知,参数ulBitsToClearOnEntry表示读取之前是否清除,设置为0xffffffff将会清除
//参数ulBitsToClearOnExit表示读取之后是否清楚,设置为0xffffffff将会清除
//参数pulNotificationValue用于获取任务通知值
//参数xTicksToWait表示阻塞时间 

发送任务通知的形式eNotifyAction

/* Actions that can be performed when vTaskNotify() is called. */
typedef enum
{
    eNoAction = 0,/* Notify the task without updating its notify value. */
    eSetBits,	                //设置位
    eIncrement,	                //增加任务通知值
    eSetValueWithOverwrite,     //覆盖的方式设置任务通知值
    eSetValueWithoutOverwrite	//不覆盖的方式设置任务通知值
} eNotifyAction;

测试程序

总体设计:2个任务,1个中断

counttask:计数并且打印,计数到50的时候发送任务通知

serialtask:获取任务通知,并判断是何种事件

串口中断:收到数据之后,发送任务通知

创建任务

#define COUNT_TASK_PRIO			    1	 //任务优先级
#define COUNT_TASK_STK_SIZE 		    80   //任务堆栈大小
TaskHandle_t CountTaskHandler;                   //任务句柄
void CountTaskFunc(void *pvParameters);          //任务函数

#define SERIAL_TASK_PRIO		    4	 //任务优先级
#define SERIAL_TASK_STK_SIZE 		    80   //任务堆栈大小
TaskHandle_t SerialTaskHandler;                  //任务句柄
void SerialTaskFunc(void *pvParameters);         //任务函数

#define BIT_0   1<<0
#define BIT_1   1<<1
#define BIT_2   1<<2

void OtherTest(void )
{
    BaseType_t ret;
	
    BoardInitMcu();
    BoardInitPeriph();
		
    ret=xTaskCreate( (TaskFunction_t )CountTaskFunc,     	
		     (const char*    )"counttask",   	
		     (uint16_t       )COUNT_TASK_STK_SIZE, 
		     (void*          )NULL,				
		     (UBaseType_t    )COUNT_TASK_PRIO,	
		     (TaskHandle_t*  )&CountTaskHandler); 
	
    ret=xTaskCreate((TaskFunction_t )SerialTaskFunc,     
		    (const char*    )"serialtask",   
		    (uint16_t       )SERIAL_TASK_STK_SIZE, 
		    (void*          )NULL,
		    (UBaseType_t    )SERIAL_TASK_PRIO,
		    (TaskHandle_t*  )&SerialTaskHandler); 
				
    vTaskStartScheduler(); 
}

各个任务函数

void  CountTaskFunc(void *pvParameters)
{
    static uint8_t i;
	
    for(;;)
    {
	i++;
		
	printf("count =%d\r\n",i);

	if(i==50)
	{
	    i=0;

	    xTaskNotify( SerialTaskHandler, BIT_1, eSetBits );
	}
						
        vTaskDelay(500);                     //延时500ms,也就是500个时钟节拍	
    }
}

void SerialTaskFunc(void *pvParameters)
{
    BaseType_t ret;
    uint32_t pulNotificationValue;
	
    for(;;)
    {
	ret= xTaskNotifyWait(0,   //读取之前,设置相应的位,0:不设置,ffffffffff:设置所有的位                  
			0xffffffff,     //读取之后,清除相应的位
	     &pulNotificationValue, 	//读取到的值
	                        10);  //阻塞时间
	
        if(ret==pdPASS)
        {
	    if((pulNotificationValue&BIT_0)==BIT_0)
	    {
	        printf("serial \r\n");
	    }
	    else
	    {
	        if((pulNotificationValue&BIT_1)==BIT_1)
	        {
		    printf("count \r\n");
	        }
	        else
	        {
		    printf("default");
	        }
	    }
        }
        else
        {
	    vTaskDelay(10);
        }		
    }
}

中断函数

void USART1_IRQHandler( void )
{
    BaseType_t pxHigherPriorityTaskWoken=pdFALSE;
	
    //省略部分代码
    
    if(RESET != __HAL_UART_GET_FLAG(&UartHandle,UART_FLAG_IDLE))
    {                   
	__HAL_UART_CLEAR_IDLEFLAG(&UartHandle);
 	
	/*任务通知用作事件标志组*/
	xTaskNotifyFromISR( SerialTaskHandler, 
                                       (1<<0), 
                                     eSetBits,     
                   &pxHigherPriorityTaskWoken);
	portYIELD_FROM_ISR(pxHigherPriorityTaskWoken);
    }
}

运行结果

与使用事件标志组是一样的。

发布了35 篇原创文章 · 获赞 25 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/freemote/article/details/104413285