FreeRTOS使用任務通知作二值信號量

關於任務通知特點、優缺點: FreeRTOS任務通知

關於二值信號量特點、本質:二值信號量使用

 ulTaskNotifyTake()             替代        xSemaphoreTake()

xTaskNotifyGive()               替代        xSemaphoreGive()

vTaskNotifyGiveFromISR   替代        xSemaphoreGiveFromISR()

 API說明

BaseType_t xTaskNotifyGive( TaskHandle_t xTaskToNotify );
//發送任務通知,返回值永遠是pdTRUE參數xTaskToNotify是任務句柄,既要發向的任務
void vTaskNotifyGiveFromISR( TaskHandle_t xTaskHandle, BaseType_t *pxHigherPriorityTaskWoken );
//同上,用於中斷中
uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait );
//獲取任務通知,返回值是任務通知值,參數xClearCountOnExit爲pdTRUE表示用作二值信號量,爲pdFALSE表示用作計數信號量

測試程序

總體設計:3個任務,1箇中斷

lcdtask:計數,LCD顯示並打印,計數到50的時候,發送任務通知給任務totaltask;

totaltask:讀取任務通知,並打印累積讀取到的次數;

serialtask:讀取任務通知,並打印收到的數據;

串口中斷:空閒中斷後,發送任務通知給任務serialtask。

創建任務

#define LCD_TASK_PRIO		              1	     //任務優先級
#define LCD_TASK_STK_SIZE 		      80     //任務堆棧大小
TaskHandle_t LCDTaskHandler;                         //任務句柄
void LCDTaskFunc(void *pvParameters);                //任務函數、

#define TOTAL_COUNT_TASK_PRIO		       2     //任務優先級
#define TOTAL_COUNT_TASK_STK_SIZE 	      50     //任務堆棧大小
TaskHandle_t TotalCountTaskHandler;                  //任務句柄
void TotalCountTaskFunc(void *pvParameters);         //任務函數

#define SERIAL_TASK_PRIO		       4     //任務優先級
#define SERIAL_TASK_STK_SIZE 		      80     //任務堆棧大小
TaskHandle_t SerialTaskHandler;                      //任務句柄
void SerialTaskFunc(void *pvParameters);             //任務函數

void OtherTest(void )
{
    BaseType_t ret;
	
    BoardInitMcu();
    BoardInitPeriph();
	
    ret=xTaskCreate((TaskFunction_t )LCDTaskFunc,     	
		    (const char*    )"lcdtask",   	
		    (uint16_t       )LCD_TASK_STK_SIZE, 
		    (void*          )NULL,				
		    (UBaseType_t    )LCD_TASK_PRIO,	
		    (TaskHandle_t*  )&LCDTaskHandler); 
	
    ret=xTaskCreate((TaskFunction_t )TotalCountTaskFunc,     	
		    (const char*    )"totaltask",   	
		    (uint16_t       )TOTAL_COUNT_TASK_STK_SIZE, 
		    (void*          )NULL,				
		    (UBaseType_t    )TOTAL_COUNT_TASK_PRIO,	
		    (TaskHandle_t*  )&TotalCountTaskHandler);   

    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  LCDTaskFunc(void *pvParameters)
{
    char  string[21] = {0};
    static uint8_t i=0;

    for(;;)
    {
	i++;
		
	sprintf(string, "%03d ", i);
	printf("count :%d\r\n",i);
		
        dis_string(1,0,(uint8_t *)string,1);
		
	if(i==50)
	{
	    xTaskNotifyGive(TotalCountTaskHandler);
	    i=0;
	}
						
        vTaskDelay(500);              //延時500ms,也就是500個時鐘節拍	
    }
}

void TotalCountTaskFunc(void *pvParameters)
{
    static uint32_t i=0;
    uint32_t tasknotifyvalue;
	
    for(;;)
    {	
        tasknotifyvalue= ulTaskNotifyTake( pdTRUE, portMAX_DELAY );
		
	if(tasknotifyvalue)
	{
	    i++;
	    printf(" total :%d\r\n",i);
	}
	else
	{
	    vTaskDelay(10);
	}
    }
}   

void SerialTaskFunc(void *pvParameters)
{
    uint32_t tasknotifyvalue;

    for(;;)
    {
	tasknotifyvalue= ulTaskNotifyTake( pdTRUE, portMAX_DELAY );
		
	if(tasknotifyvalue)
	{
	    printf("serial:%s",SerialFrame.Buff);
	    memset(SerialFrame.Buff,0,255);
	    SerialFrame.Len=0;
	}
	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);

        /*任務通知用作二值信號量*/		
        vTaskNotifyGiveFromISR( SerialTaskHandler, &pxHigherPriorityTaskWoken  );
	portYIELD_FROM_ISR(pxHigherPriorityTaskWoken);
    }
}

運行結果

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章