官方文档参考
34 2.6 xTaskCreate()
[[FreeRTOS_Reference_Manual_V10.0.0.pdf#page=34&selection=0,2,4,13|FreeRTOS_Reference_Manual_V10.0.0, page 34]]
FreeRTOS的任务创建与删除包括:
- 任务创建 [[3. FreeRTOS中Task的创建与删除#^b63126]]
- 任务删除 [[3. FreeRTOS中Task的创建与删除#^906a4d]]
- 任务的自我删除 [[3. FreeRTOS中Task的创建与删除#^0a1af5]]
xTaskCreate
:任务创建
^b63126
task.h
BaseType_t xTaskCreate( TaskFunction_t pvTaskCode,
const char * const pcName,
const [configSTACK_DEPTH_TYPE]
void *pvParameters,
UBaseType_t uxPriority,
TaskHandle_t *pxCreatedTask
);
创建一个新任务并将其添加到准备运行的任务列表中。configSUPPORT_DYNIMIC_ALLOCATION
必须在FreeRTOSConfig.h
中被设置为 1,或保留为定义状态(此时,它默认为 1),才能使用此RTOS API函数。
每个任务都需要RAM来保存任务状态,并由任务用作起堆栈。如果使用xTaskCreateStatic()
,则RAM由应用程序编写者提供,因此可以在编译时进行静态分配。
如果使用了FreeRTOS-MPU
,建议使用xTaskCreateRestricted()
而不是xTaskCreate()
。
参数:
pvTaskCode
:指向任务入口函数的指针(即 实现任务的函数名称)。
- 任务通常以无限循环的形式实现;实现任务的函数绝不能返回或者退出。但是,任务可以自我删除。[[3. FreeRTOS中Task的创建与删除#^0a1af5]]
pcName
:任务的描述性名称。主要是为了方便调试,但也可以用于获取任务句柄。
- 任务名称的最大长度由
FreeRTOSConfig.h
中的configMAX_TASK_LEN
定义。
uxStackDepth
:要分配用于 任务堆栈的 堆栈。例如:如果任务堆栈的宽度为16位,uxStackDepth
为100,则将分配200个字节用于该任务的堆栈;例如,如果堆栈的宽度为32位,uxStackDepth
为400,则将分配1600个字节用于该任务的堆栈。[[堆栈宽度与深度]]
- 堆栈深度与堆栈宽度的乘积不得超过
size_t
类型变量所能包含的最大值。
pvParameters
:作为参数传递给创建任务的值。 ^168f8e
- 如果
pvParameters
设置为变量的地址,则在执行创建的任务时该变量必须仍然存在——因此 传递堆栈变量的地址是无效的。[[传递变量给任务的注意事项]] - 次参数类型是一个
(void *)
类型的指针,可以指向任意类型的变量,使用时注意类型转换。
uxPriority
:创建任务执行的优先级。
- 包含MPU支持的系统可在特权模式下选择性地创建任务,方法是在
uxPriority
中设置portPRIVILEGE_BIT
位。 - 断言优先级低于
configMAX_priority
,如果未定义configASSET
,则优先级会被静默限制为(configMAX_priority - 1
) - 低优先级数字表示低优先级任务。 空闲任务的优先级为零 (tskIDLE_PRIORITY)。
pxCreatedTask
:用于将句柄传递至由xTaskCreate()
函数创建的任务,句柄可以获取当前Task的一些信息。pxCreateTask
是可选的,可设置为NULL
。
返回:
如果任务创建成功,则返回pdPASS
。否则返回errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY
。
示例代码
#include <stdio.h>
#include <inttypes.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_chip_info.h"
#include "esp_flash.h"
#include "esp_system.h"
void myTask1(void *pvPara)
{
while (1) {
printf("Hello, moker, I'm in the task1 now!\n");
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
void app_main(void)
{
printf("Hello world! It's ESP32!\n");
TaskHandle_t myHandle1 = NULL;
xTaskCreate(myTask1, "myTask1 say hello", 1024, NULL, 1, &myHandle1);
}
示例输出
可以看到,任务被创建后,正常执行。因为并没有删除任务,所以任务在app_main()
返回后仍然在继续执行。接下来删除任务。
vTaskDelete
:任务删除
^906a4d
task.h
void vTaskDelete( TaskHandle_t xTask );
INCLUDE_vTaskDelete
必须被定义为 1 才能使用此函数。
此函数的作用为从RTOS内核管理中移除任务。被删除的任务将从所有的就绪、阻塞、挂起和事件的列表中移除。
请注意,空闲任务负责从已删除任务中释放RTOS内核分配的内存。因此,重要的是,如果应用调用了vTaskCreate()
,空闲任务不会失去微控制器的处理时间。任务代码分配的内存不会自动释放,并应在删除任务之前释放。
参数:
xTask:
待删除的任务句柄,传递NULL将导致调用任务被删除。
示例代码
#include <stdio.h>
#include <inttypes.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_chip_info.h"
#include "esp_flash.h"
#include "esp_system.h"
void myTask1(void *pvPara)
{
while (1) {
printf("Hello, moker, I'm in the task1 now!\n");
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
void myTask2(void *pvPara)
{
while (1) {
printf("Hello, moker, I'm in the task2 now!\n");
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
void app_main(void)
{
printf("Hello world! It's ESP32!\n");
TaskHandle_t myHandle1 = NULL;
TaskHandle_t myHandle2 = NULL;
xTaskCreate(myTask1, "myTask1 say hello", 1024, NULL, 1, &myHandle1);
xTaskCreate(myTask2, "myTask2 say hello", 1024, NULL, 1, &myHandle2);
// 等待4s后删除任务myTask1
vTaskDelay(2000 / portTICK_PERIOD_MS);
if (myHandle1 != NULL) {
vTaskDelete(myHandle1);
printf("myTask1 is deleted!\n");
} else {
printf("myHandle1 is not empty!\n");
}
// 等待2s后删除myTask2
if (myHandle2 != NULL) {
vTaskDelete(myHandle2);
printf("myTask2 is deleted!\n");
} else {
printf("myHandle2 is not empty!\n");
}
}
示例输出
可以看到,task1和task2同时开始运行,并且运行2s后删除任务,任务删除完成后才从app_main()
返回。
任务的自我删除
^0a1af5
还有一种方法可以删除创建的任务,即 在任务函数内部追加vTaskDelete(NULL)
,即可达到任务运行完成后,自己删除自己的目的。
示例代码
#include <stdio.h>
#include <inttypes.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_chip_info.h"
#include "esp_flash.h"
#include "esp_system.h"
void myTask1(void *pvPara)
{
int delay = 2; // 设置为2s后自我删除
while (delay--) {
printf("Hello, moker, I'm in the task1 now! Delete in %d second(s).\n", delay);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
vTaskDelete(NULL);
}
void myTask2(void *pvPara)
{
int delay = 3; // 设置为3s后自我删除
while (delay--) {
printf("Hello, moker, I'm in the task2 now! Detele in %d second(s)\n", delay);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
vTaskDelete(NULL);
}
void app_main(void)
{
printf("Hello world! It's ESP32!\n");
xTaskCreate(myTask1, "myTask1 say hello", 2048, NULL, 1, NULL);
xTaskCreate(myTask2, "myTask2 say hello", 2048, NULL, 1, NULL);
}
示例输出
可以看到,task1在运行2s后自我删除,task2在运行3s后自我删除,app_main
在任务完成后返回。