關于任務通知特點、優缺點: FreeRTOS任務通知
關于二值信号量特點、本質:二值信号量使用
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2cswmUzIGdWdlW5plMMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL0gzN1MDMwQTMxIjMwAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
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);
}
}
運作結果