05-任务创建与删除.md 13 KB


tags: [source-summary] type: source source: "尚硅谷嵌入式技术之FreeRTOS实时操作系统 V1.0.3 — 第4章 任务创建和删除" author: "尚硅谷研究院" date: 2026-07-17

created: 2026-07-17

任务创建与删除

用生活理解:公司招人(创建任务)需要分配工位(栈)和建立档案(TCB);人员可以按编制内(静态)或外聘(动态)两种方式入职;裁员(删除任务)时需清理工位和档案。

Concept

Basic concept

FreeRTOS 中,一个任务(Task)包含三要素:

  • 任务函数:用户编写的无限循环函数
  • 堆栈(Stack):保存任务上下文(寄存器、局部变量)
  • TCB(Task Control Block):任务控制块,记录任务状态、优先级等信息

Working principle

FreeRTOS 创建任务时:

  1. 分配栈空间和 TCB 内存
  2. 将任务加入就绪链表
  3. 调度器根据优先级和时间片选择运行的任务

动态创建xTaskCreate)由内核自动分配栈和 TCB 内存:

  • 优点:使用简单,无需预先规划内存
  • 缺点:依赖 heap 管理,需要确保堆空间充足

静态创建xTaskCreateStatic)由用户预先分配栈和 TCB 内存:

  • 优点:不依赖堆分配,适合安全关键系统
  • 缺点:需要提前计算任务数量并分配内存

删除任务时使用 vTaskDelete(),任务被删除后不会再次运行,任务占用的资源会被释放。

Core API

动态创建:xTaskCreate

Function Params Description
xTaskCreate pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask 动态创建一个新任务
pvTaskCode 任务函数指针
pcName 任务名称(用于调试)
usStackDepth 栈深度(单位 word,STM32 中 1 word = 4 字节)
pvParameters 传递给任务函数的参数
uxPriority 任务优先级(0~configMAX_PRIORITIES-1)
pxCreatedTask 返回任务句柄
返回 pdPASS 创建成功
errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY 创建失败(内存不足)

静态创建:xTaskCreateStatic

Function Params Description
xTaskCreateStatic pvTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, puxStackBuffer, pxTaskBuffer 静态创建一个新任务
puxStackBuffer 用户预先分配的栈空间
pxTaskBuffer 用户预先分配的 TCB 空间
返回 非 NULL 任务句柄
NULL 创建失败(用户未提供内存)

删除任务:vTaskDelete

Function Params Description
vTaskDelete xTask 删除指定任务
xTask 待删除任务句柄;传 NULL 表示删除自身
注意 传 NULL 时会在函数末尾触发一次任务切换

空闲任务与定时器任务内存钩子(静态分配)

configSUPPORT_STATIC_ALLOCATION = 1 时,必须提供以下两个钩子函数:

Function Description
vApplicationGetIdleTaskMemory 提供空闲任务的 TCB 和栈缓冲区
vApplicationGetTimerTaskMemory 提供定时器任务的 TCB 和栈缓冲区

Experiment

Requirements

  • P01:动态创建 3 个任务,task1 翻转 LED1,task2 翻转 LED2,task3 检测按键删除 task1
  • P02:使用静态创建实现同样功能,并提供空闲任务和定时器任务的内存

Code Implementation

P01:动态创建

File: 01_任务创建与删除_CubeMX/Core/Src/freertos_demo.c

#include "freertos_demo.h"
#include "FreeRTOS.h"
#include "task.h"
#include "LED.h"
#include "Key.h"

/* 起始任务配置 */
#define START_TASK_STACK 128
#define START_TASK_PRIORITY 1
TaskHandle_t start_task_handle;
void start_task(void *pvParameters);

/* 任务1配置 */
#define TASK1_STACK 128
#define TASK1_PRIORITY 2
TaskHandle_t task1_handle;
void task1(void *pvParameters);

/* 任务2配置 */
#define TASK2_STACK 128
#define TASK2_PRIORITY 3
TaskHandle_t task2_handle;
void task2(void *pvParameters);

/* 任务3配置 */
#define TASK3_STACK 128
#define TASK3_PRIORITY 4
TaskHandle_t task3_handle;
void task3(void *pvParameters);

/**
 * @description: 启动FreeRTOS
 */
void freertos_start(void)
{
    /* 1. 创建起始任务(所有任务在起始任务中统一创建) */
    xTaskCreate((TaskFunction_t)start_task,               // 任务函数指针
                (char *)"start_task",                     // 任务名称(用于调试标识)
                (configSTACK_DEPTH_TYPE)START_TASK_STACK, // 栈空间大小 128 word × 4 = 512 字节
                (void *)NULL,                             // 传递给任务的参数
                (UBaseType_t)START_TASK_PRIORITY,         // 任务优先级
                (TaskHandle_t *)&start_task_handle);      // 返回任务句柄

    /* 2. 启动调度器:将CPU控制权交给FreeRTOS */
    vTaskStartScheduler();
}

/**
 * @description: 起始任务函数,负责创建其他任务后自我删除
 */
void start_task(void *pvParameters)
{
    /* 进入临界区:防止创建任务过程中被中断干扰 */
    taskENTER_CRITICAL();

    /* 创建3个实际工作任务 */
    xTaskCreate((TaskFunction_t)task1,
                (char *)"task1",
                (configSTACK_DEPTH_TYPE)TASK1_STACK,
                (void *)NULL,
                (UBaseType_t)TASK1_PRIORITY,
                (TaskHandle_t *)&task1_handle);
    xTaskCreate((TaskFunction_t)task2,
                (char *)"task2",
                (configSTACK_DEPTH_TYPE)TASK2_STACK,
                (void *)NULL,
                (UBaseType_t)TASK2_PRIORITY,
                (TaskHandle_t *)&task2_handle);
    xTaskCreate((TaskFunction_t)task3,
                (char *)"task3",
                (configSTACK_DEPTH_TYPE)TASK3_STACK,
                (void *)NULL,
                (UBaseType_t)TASK3_PRIORITY,
                (TaskHandle_t *)&task3_handle);

    /* 删除起始任务自身:传NULL代表删除当前运行的任务 */
    vTaskDelete(NULL);

    /* 退出临界区 */
    taskEXIT_CRITICAL();
}

/**
 * @description: 任务1——翻转LED1,周期500ms
 */
void task1(void *pvParameters)
{
    while (1)
    {
        printf("task1正在运行...\r\n");
        LED_Toggle(LED1_Pin);          // 翻转LED1
        vTaskDelay(500);               // 阻塞延时500ms,让出CPU
    }
}

/**
 * @description: 任务2——翻转LED2,周期500ms
 */
void task2(void *pvParameters)
{
    while (1)
    {
        printf("task2正在运行...\r\n");
        LED_Toggle(LED2_Pin);          // 翻转LED2
        vTaskDelay(500);               // 阻塞延时500ms,让出CPU
    }
}

/**
 * @description: 任务3——检测按键,按下KEY1则删除task1
 */
void task3(void *pvParameters)
{
    uint8_t key = 0;
    while (1)
    {
        printf("task3正在运行...\r\n");
        key = Key_Detect();
        if (key == KEY1_PRESS)
        {
            /* 确保task1句柄有效 */
            if (task1_handle != NULL)
            {
                /* KEY1按下则删除task1 */
                printf("正在删除Task1....\r\n");
                vTaskDelete(task1_handle);       // 删除指定任务
                task1_handle = NULL;             // 句柄置空防止误用
            }
        }
        vTaskDelay(500);
        // HAL_Delay(500);   // 注意:HAL_Delay是忙等待,会占用CPU
    }
}

P02:静态创建

File: 02_任务创建与删除_静态创建/Core/Src/freertos_demo.c

#include "freertos_demo.h"
#include "FreeRTOS.h"
#include "task.h"
#include "LED.h"
#include "Key.h"

/* 任务栈和TCB变量全部由用户预先定义 */
#define START_TASK_STACK 128
StackType_t start_task_stack[START_TASK_STACK];  // 用户分配的栈空间
StaticTask_t start_task_tcb;                      // 用户分配的TCB空间
TaskHandle_t start_task_handle;

#define TASK1_STACK 128
StackType_t task1_stack[TASK1_STACK];
StaticTask_t task1_tcb;
TaskHandle_t task1_handle;

#define TASK2_STACK 128
StackType_t task2_stack[TASK2_STACK];
StaticTask_t task2_tcb;
TaskHandle_t task2_handle;

#define TASK3_STACK 128
StackType_t task3_stack[TASK3_STACK];
StaticTask_t task3_tcb;
TaskHandle_t task3_handle;

/* ============= 系统任务内存分配(静态分配时必须提供)=============== */
StackType_t idle_task_stack[configMINIMAL_STACK_SIZE];
StaticTask_t idle_task_tcb;

StackType_t timer_task_stack[configTIMER_TASK_STACK_DEPTH];
StaticTask_t timer_task_tcb;

/* 提供空闲任务的栈和TCB */
void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer,
                                   StackType_t **ppxIdleTaskStackBuffer,
                                   uint32_t *pulIdleTaskStackSize)
{
    *ppxIdleTaskTCBBuffer = &idle_task_tcb;
    *ppxIdleTaskStackBuffer = idle_task_stack;
    *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
}

/* 提供定时器任务的栈和TCB */
void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer,
                                    StackType_t **ppxTimerTaskStackBuffer,
                                    uint32_t *pulTimerTaskStackSize)
{
    *ppxTimerTaskTCBBuffer = &timer_task_tcb;
    *ppxTimerTaskStackBuffer = timer_task_stack;
    *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
}

void freertos_start(void)
{
    /* 静态创建起始任务:需要用户提供栈和TCB缓冲区 */
    start_task_handle = xTaskCreateStatic(
        (TaskFunction_t)start_task,
        (char *)"start_task",
        (uint32_t)START_TASK_STACK,
        (void *)NULL,
        (UBaseType_t)START_TASK_PRIORITY,
        (StackType_t *)start_task_stack,   // 用户预分配的栈
        (StaticTask_t *)&start_task_tcb    // 用户预分配的TCB
    );

    vTaskStartScheduler();
}

void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();

    /* 静态创建3个工作任务 */
    task1_handle = xTaskCreateStatic(
        (TaskFunction_t)task1, (char *)"task1",
        (configSTACK_DEPTH_TYPE)TASK1_STACK, (void *)NULL,
        (UBaseType_t)TASK1_PRIORITY,
        (StackType_t *)task1_stack, (StaticTask_t *)&task1_tcb
    );
    task2_handle = xTaskCreateStatic(
        (TaskFunction_t)task2, (char *)"task2",
        (configSTACK_DEPTH_TYPE)TASK2_STACK, (void *)NULL,
        (UBaseType_t)TASK2_PRIORITY,
        (StackType_t *)task2_stack, (StaticTask_t *)&task2_tcb
    );
    task3_handle = xTaskCreateStatic(
        (TaskFunction_t)task3, (char *)"task3",
        (configSTACK_DEPTH_TYPE)TASK3_STACK, (void *)NULL,
        (UBaseType_t)TASK3_PRIORITY,
        (StackType_t *)task3_stack, (StaticTask_t *)&task3_tcb
    );

    vTaskDelete(NULL);
    taskEXIT_CRITICAL();
}
/* task1/task2/task3 与动态创建版本相同 */

Key Config

P01 FreeRTOSConfig.h(默认配置,无需特殊设置):

// 默认配置已启用 vTaskDelete
#define INCLUDE_vTaskDelete  1

P02 FreeRTOSConfig.h(静态分配额外配置):

#define configSUPPORT_STATIC_ALLOCATION  1    // 启用静态分配
#define configUSE_TIMERS                 1    // 启用软件定时器(产生定时器任务)
#define configTIMER_TASK_PRIORITY        4    // 定时器任务优先级
#define configTIMER_QUEUE_LENGTH         5    // 定时器命令队列长度
#define configTIMER_TASK_STACK_DEPTH     256  // 定时器任务栈大小

Core API Reference Table

Function Parameters Return Description
xTaskCreate pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask BaseType_t 动态创建任务
xTaskCreateStatic pvTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, puxStackBuffer, pxTaskBuffer TaskHandle_t 静态创建任务
vTaskDelete xTaskToDelete void 删除任务(NULL=自身)
vTaskStartScheduler void 启动调度器
vApplicationGetIdleTaskMemory ppxIdleTaskTCBBuffer, ppxIdleTaskStackBuffer, pulIdleTaskStackSize void 提供空闲任务内存(静态分配时)
vApplicationGetTimerTaskMemory ppxTimerTaskTCBBuffer, ppxTimerTaskStackBuffer, pulTimerTaskStackSize void 提供定时器任务内存(静态分配时)

Common Issues & Pitfalls

  1. 栈溢出:栈大小设置不当会导致任务异常。调试时可设置 configCHECK_FOR_STACK_OVERFLOW 为 1 或 2,并实现 vApplicationStackOverflowHook()
  2. 删除后句柄未置空:删除任务后其句柄仍指向原 TCB 地址,后续误用会导致崩溃。应在删除后立即将句柄置 NULL
  3. 动态创建失败:堆空间不足时 xTaskCreate 返回 errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY。增大 configTOTAL_HEAP_SIZE 或改用静态创建。
  4. 静态创建必须提供系统任务内存:设置 configSUPPORT_STATIC_ALLOCATION = 1 后,必须实现 vApplicationGetIdleTaskMemory,若启用定时器还必须实现 vApplicationGetTimerTaskMemory
  5. vTaskDelete(NULL) 后需要切换:删除自身时,函数末尾会自动触发一次任务切换,因此无需手动调用 taskYIELD()
  6. 临界区内不要使用阻塞操作taskENTER_CRITICAL() / taskEXIT_CRITICAL() 之间不应调用 vTaskDelay() 等可能导致阻塞的 API。