這篇文章在于 詳細解釋 FreeRTOS 中任務的創建過程,包括任務創建的本質過程、API 詳解、兩種創建方式(動態/靜態)、任務函數規范、常見錯誤及實踐建議。
這里參照:RTOS官方文檔:https://www.freertos.org/zh-cn-cmn-s/Documentation/02-Kernel/04-API-references/01-Task-creation/01-xTaskCreate
FreeRTOS 的“任務”
在 FreeRTOS 中,每個任務(Task)就是一個可以獨立運行的“線程”或“執行單元”,具有:
自己的函數入口(任務函數)
獨立的堆棧空間
獨立的上下文(CPU 寄存器、程序計數器)
FreeRTOS 通過任務調度器(Scheduler)來在這些任務之間切換執行權,實現 “多任務并發”。
創建任務的方式
動態創建任務(最常用)(上述官網鏈接)
xTaskCreate()
是 FreeRTOS 中最常用的任務創建函數,適合一般嵌入式系統中動態創建任務,使用時需合理配置堆大小和任務優先級,確保系統資源充足。
使用 API 函數:xTaskCreate()
BaseType_t xTaskCreate(TaskFunction_t pvTaskCode,const char * const pcName,const configSTACK_DEPTH_TYPE uxStackDepth,void *pvParameters,UBaseType_t uxPriority,TaskHandle_t *pxCreatedTask
);
參數說明:
pvTaskCode 任務入口函數(必須是 void func(void *pvParameters) 形式)
pcName 任務名(調試用途)
uxStackDepth 堆棧大小(單位是“字”,不是字節) STM32 上 1 word = 4 字節
pvParameters 創建任務時傳入的參數指針
uxPriority 任務優先級(0 ~ configMAX_PRIORITIES - 1)
pxCreatedTask 任務句柄的地址(可為 NULL)返回值:
pdPASS:創建成功
errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY:內存不足,任務創建失敗
由于官方文檔里的鏈接內容過于理論化,不易理解,這里用大白話翻譯一下:
xTaskCreate()
函數詳解:
功能說明:
用于創建一個新的任務并將其加入到就緒列表中。
必須啟用FreeRTOSConfig.h
中的宏:
#define configSUPPORT_DYNAMIC_ALLOCATION 1
使用動態內存分配方式從 FreeRTOS 的堆中分配 任務堆棧 和 任務控制塊。
使用注意事項:
- 堆棧大小單位是“字”(word)
- 在 Cortex-M3/M4 中,1 word = 4 字節
所以128
表示 512 字節堆棧空間- 任務函數不能 return
- 必須是一個無限循環
for(;;)
或while(1){}
- 若任務要結束,需使用
vTaskDelete(NULL)
- pvParameters 傳參要小心生命周期
- 不要傳局部變量地址
- 可以傳入靜態變量或常量值
- 優先級不能超過
configMAX_PRIORITIES - 1
- 否則調度器行為不確定
- 建議使用
tskIDLE_PRIORITY + x
這種寫法
完整的任務創建示例
/********************************************************************************* @file Project/STM32F10x_StdPeriph_Template/main.c * @author MCD Application Team* @version V3.5.0* @date 08-April-2011* @brief Main program body******************************************************************************* @attention** THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.** <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>*******************************************************************************/ /* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include <stdio.h>
#include "FreeRTOS.h"
#include "task.h"
#include "usart.h"
#include "gpio.h"//------------------------- start_task --------------------------------------------//
void start_task(void *pvParameters); //任務函數入口
TaskHandle_t StartTask_Handler; //任務句柄 _任務身份證_每個任務都有獨立的任務
#define START_STK_SIZE 64 //任務堆棧大小
#define START_TASK_PRO 1 //任務優先級
//-----------------------------------------------------------------------//在主函數中創建任務
void Start()
{
//------------------------- start_task --------------------------------------------////初始化函數xTaskCreate((TaskFunction_t) start_task, //任務函數入口(const char * ) "start_task", //任務函數名稱(uint16_t ) START_STK_SIZE, //任務堆棧大小(void * ) NULL, //任務參數入口(UBaseType_t ) START_TASK_PRO, //任務優先級(TaskHandle_t *) StartTask_Handler ); //任務句柄vTaskStartScheduler(); //開啟任務調度器
}int main(void)
{NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 ); //RTOS需要將中斷優先級分組分配到第四組usart_init(115200);MX_GPIO_Init();printf("Create Task! \r\n");Start();while(1) // 不會執行到這里{}}//任務函數(必須是無限循環)
void start_task(void *pvParameters) //任務函數入口
{printf("start Task Run! \r\n");while(1){GPIO_WriteBit(GPIOC, GPIO_Pin_7, Bit_RESET); //綠燈閃爍vTaskDelay(500);GPIO_WriteBit(GPIOC, GPIO_Pin_7, Bit_SET); //綠燈關閉vTaskDelay(500);vTaskDelay(10);}
}/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
FreeRTOS 中,任務是最基本的執行單元。你可以通過 xTaskCreate()
或 xTaskCreateStatic()
創建任務,并通過調度器進行任務切換,從而實現多任務并發執行。任務函數必須是無限循環,并適當使用延時函數避免占用 CPU。
靜態創建任務(更可控) (不詳細介紹,較少使用)
使用 API 函數:xTaskCreateStatic()
TaskHandle_t xTaskCreateStatic(TaskFunction_t pvTaskCode,const char * const pcName,const uint32_t ulStackDepth,void *pvParameters,UBaseType_t uxPriority,StackType_t *puxStackBuffer,StaticTask_t *pxTaskBuffer
);
用戶自己提供堆棧數組 + TCB 緩存
更適合內存受限嵌入式場景
不依賴 FreeRTOS 的堆(heap_4.c
)
動態 vs 靜態任務創建對比:
項目 | 動態創建 xTaskCreate | 靜態創建 xTaskCreateStatic |
---|---|---|
內存分配 | 使用 FreeRTOS 堆 | 用戶手動提供 |
靈活性 | 高 | 稍低 |
控制性 | 低 | 高 |
適合場景 | 一般應用 | 內存受限、認證項目 |
最后,解釋一下任務句柄的用途:任務句柄 類似于每個任務的身份證,每個任務都有獨立的任務句柄標識。
創建任務時可以返回任務句柄(TaskHandle_t
),用于:
- 刪除任務:
vTaskDelete(xHandle);
- 掛起任務:
vTaskSuspend(xHandle);
- 恢復任務:
vTaskResume(xHandle);
- 獲取任務狀態:
eTaskGetState(xHandle);
以上,便是 FreeRTOS 任務的創建。
以上,歡迎有從事同行業的電子信息工程、互聯網通信、嵌入式開發的朋友共同探討與提問,我可以提供實戰演示或模板庫。希望內容能夠對你產生幫助!