ESP32 入門到精通 – 使用 xTask
內容
簡介
在 ESP32 IDF(Espressif IoT Development Framework)中,FreeRTOS 是用於管理多任務的即時操作系統核心。任務(Task)是 FreeRTOS 中的核心概念之一,每個任務都是一個獨立的執行緒,可以併發運行。以下是 FreeRTOS 任務在 ESP32 中的作用詳細說明。
xTask & vTask 差別
在 FreeRTOS 中,xTask 和 vTask 前綴用於區分不同類型的 API 函數。理解它們的差別有助於正確地使用這些函數。
1. xTask 函數
xTask 前綴通常用於返回一個值的函數。這個值通常表示函數的執行結果,或者是某些狀態資訊。
返回值類型: 通常是 BaseType_t(表示操作成功或失敗),或者是指標類型(如 TaskHandle_t)。
2. vTask 函數
vTask 前綴用於不返回任何值(void 類型)的函數。這類函數通常執行某種操作,但不需要告訴調用者該操作的結果。
返回值類型: void(不返回值)。
Task 創建
1. 概述
在 FreeRTOS 中,任務是執行程式碼的獨立執行緒。每個任務都有自己的堆疊、優先權、狀態和執行時間片。任務在 FreeRTOS 的調度器下運行,調度器負責在不同任務之間切換。
2. 創建
任務建立使用 xTaskCreate 函數,其基本語法如下:
BaseType_t xTaskCreate(
TaskFunction_t pvTaskCode,
const char * const pcName,
uint16_t usStackDepth,
void *pvParameters,
UBaseType_t uxPriority,
TaskHandle_t *pxCreatedTask
);
各參數的詳細說明:
pvTaskCode: 指向任務函數的指標。這個函數定義了任務的行為,即任務執行的內容。
pcName: 任務的名稱。這個名稱主要用於調試時識別任務,方便查看和追踪任務的執行情況。這個名稱不必唯一。
usStackDepth: 指定任務堆疊的大小,單位是「字」(word),而不是字節(byte)。在大多數平台上,一個字通常是 4 個字節。堆疊大小必須足夠大,以確保任務能夠正常運行。
pvParameters: 傳遞給任務的參數,這個指標在任務啟動時會被傳遞給任務函數。這使得你可以在任務啟動時給它傳遞特定的參數。
uxPriority: 任務的優先級。FreeRTOS 根據這個優先級來調度任務,優先級較高的任務會優先於低優先級任務執行。如果多個任務具有相同的優先級,則按時間片輪轉執行。
pxCreatedTask: 指向任務句柄變數的指標。任務創建成功後,這個變數將保存該任務的句柄。如果你不需要之後再引用這個任務,可以將此參數設為 NULL。
返回值:
這個函數返回 BaseType_t 類型的值。如果任務創建成功,通常返回 pdPASS。如果創建失敗(例如內存不足),則返回 errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY 等錯誤代碼。
示例
void taskFunction(void *pvParameter) {
while (1) {
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
void app_main() {
// Create a new task with the following parameters:
// taskFunction: The function that defines the task's operations.
// "TaskName": The name of the task for debugging purposes.
// 2048: The stack size for the task, in words (not bytes).
// NULL: The parameter passed to the task function (no parameters needed here).
// 5: The priority of the task (higher numbers indicate higher priority).
// NULL: Task handle (not needed in this case, so passing NULL).
xTaskCreate(taskFunction, "TaskName", 2048, NULL, 5, NULL);
}
Task 優先權
任務優先順序決定了任務的執行順序。優先順序較高的任務會比優先順序較低的任務更常獲得 CPU 時間。 FreeRTOS 中的優先權範圍從 0(最低優先權)到 configMAX_PRIORITIES - 1(最高優先權)。
#define tskIDLE_PRIORITY 0 // The priority level assigned to the idle task
#define configMAX_PRIORITIES 5 // The maximum priority level available for tasks
Task Stack
每個任務都有一個堆疊,用於儲存任務執行期間的局部變數和函數呼叫資訊。堆疊的大小在任務建立時指定,必須足夠大以容納任務執行時所需的所有資料。
#define STACK_SIZE 2048 // Task stack size (in words)
void app_main() {
xTaskCreate(taskFunction, "TaskName", STACK_SIZE, NULL, 5, NULL);
}
Task 調度
FreeRTOS 使用時間片輪轉(輪詢調度)和優先權調度來切換任務。當某個任務的時間片用完,或某個更高優先權的任務變成就緒狀態時,調度器會進行任務切換。
vTaskDelay & vTaskDelayUntil
vTaskDelay 用于使任务休眠一段时间。
vTaskDelay(pdMS_TO_TICKS(1000));
vTaskDelayUntil 使任务以固定的时间间隔运行,避免时间漂移。
TickType_t xLastWakeTime = xTaskGetTickCount();
vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(1000));
Task 删除
自行删除。
void taskFunction(void *pvParameter) {
// Perform task operations
vTaskDelete(NULL); // Delete the current task
}
由其他任务删除。
void app_main() {
TaskHandle_t taskHandle;
xTaskCreate(taskFunction, "TaskName", 2048, NULL, 5, &taskHandle);
// Delete the task
vTaskDelete(taskHandle);
}
安裝 VSCode 和 ESP-IDF VSCode 擴展
確保你已經安裝和配置好了 ESP-IDF 開發環境。您也可以參考 ESP32 入門到精通 – 在 VSCode 安裝 ESP-IDF 插件 這篇文章。
新建 ESP32 專案
利用在 VSCode 的 IDF 插件來新建一個 ESP32 專案可參考 ESP32 入門到精通 – 如何用 VSCode 創建 ESP32 專案。
xTask & vTask 範例
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <stdio.h>
// Task to blink an LED
void ledBlinkTask(void *pvParameters) {
while (1) {
// Simulate LED on
printf("LED ON\n");
vTaskDelay(pdMS_TO_TICKS(500)); // Delay for 500 milliseconds
// Simulate LED off
printf("LED OFF\n");
vTaskDelay(pdMS_TO_TICKS(500)); // Delay for 500 milliseconds
}
}
// Task to monitor system status
void monitorTask(void *pvParameters) {
while (1) {
// Simulate monitoring
printf("Monitoring system...\n");
vTaskDelay(pdMS_TO_TICKS(2000)); // Delay for 2 seconds
}
}
// Task that runs and then deletes itself
void selfDeletingTask(void *pvParameters) {
printf("Self-Deleting Task is running...\n");
// Delay for 3 seconds
vTaskDelay(pdMS_TO_TICKS(3000));
printf("Self-Deleting Task will delete itself now.\n");
// Delete this task
vTaskDelete(NULL); // NULL means delete the calling task
}
void app_main() {
// Create LED blink task with priority 3
xTaskCreate(ledBlinkTask, "LED Blink Task", 2048, NULL, 3, NULL);
// Create monitoring task with priority 2
xTaskCreate(monitorTask, "Monitor Task", 2048, NULL, 2, NULL);
// Create a self-deleting task with priority 1
xTaskCreate(selfDeletingTask, "Self-Deleting Task", 2048, NULL, 1, NULL);
}
編譯和燒錄
在 VSCode 中找到 "ESP32-IDF : Build, Flash and Monitor" ICON 執行和燒錄。
查看結果
我們可以查看在終端機的列印結果,如下...
LED ON
LED OFF
LED ON
LED OFF
Monitoring system...
LED ON
LED OFF
LED ON
LED OFF
Self-Deleting Task is running...
Monitoring system...
LED ON
LED OFF
LED ON
LED OFF
Self-Deleting Task will delete itself now.
Monitoring system...
LED ON
LED OFF
...
結論
在 ESP32 IDF 中,FreeRTOS 任務是構建複雜、多功能嵌入式應用的基礎。透過任務,你可以有效管理併發操作、提高系統響應速度、優化資源使用,並實現模組化和可維護的代碼結構。FreeRTOS 的靈活性和強大功能使得它成為 ESP32 上進行嵌入式開發的關鍵工具。