tags: [source-summary] type: source source: "尚硅谷嵌入式技术之FreeRTOS实时操作系统 V1.0.3 — 第5章 任务挂起与恢复" author: "尚硅谷研究院" date: 2026-07-17
用生活理解:挂起任务就像把员工暂时调离岗位(保留工位和编制),不需要时让他歇着;恢复就像把他叫回来上班。而挂起调度器则像是整个公司暂停运转,所有员工原地待命。
挂起(Suspend) 将任务置于挂起态(Suspended State):
vTaskResume() 手动恢复FreeRTOS 提供两套挂起/恢复机制:
1. 单任务挂起/恢复
| API | 描述 |
|---|---|
vTaskSuspend(TaskHandle_t xTaskToSuspend) |
挂起指定任务 |
vTaskResume(TaskHandle_t xTaskToResume) |
恢复指定任务 |
xTaskResumeFromISR(TaskHandle_t xTaskToResume) |
从中断中恢复任务(中断安全版本) |
2. 调度器级挂起/恢复
| API | 描述 |
|---|---|
vTaskSuspendAll() |
挂起整个调度器,所有任务停止切换 |
xTaskResumeAll() |
恢复调度器,返回 pdTRUE 或 pdFALSE |
| 操作 | 挂起 | 阻塞 | 删除 |
|---|---|---|---|
| 任务存在 | ✅ | ✅ | ❌ |
| 可自动恢复 | ❌ | ✅(超时后) | ❌ |
| 资源释放 | ❌ | ❌ | ✅ |
| 恢复方式 | 手动 resume | 超时/事件触发 | 需重新创建 |
vTaskSuspend(task1) 挂起 task1vTaskResume(task1) 恢复 task1vTaskSuspendAll() 挂起调度器xTaskResumeAll() 恢复调度器vTaskList() 打印所有任务状态File: 03_任务挂起与恢复/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);
void freertos_start(void)
{
/* 动态创建起始任务 */
xTaskCreate((TaskFunction_t)start_task,
(char *)"start_task",
(configSTACK_DEPTH_TYPE)START_TASK_STACK,
(void *)NULL,
(UBaseType_t)START_TASK_PRIORITY,
(TaskHandle_t *)&start_task_handle);
/* 启动调度器 */
vTaskStartScheduler();
}
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);
/* 删除起始任务自身 */
vTaskDelete(NULL);
taskEXIT_CRITICAL();
}
void task1(void *pvParameters)
{
while (1)
{
printf("task1正在运行...\r\n");
LED_Toggle(LED1_Pin);
vTaskDelay(500); // 阻塞延时500ms,让出CPU
}
}
void task2(void *pvParameters)
{
while (1)
{
printf("task2正在运行...\r\n");
LED_Toggle(LED2_Pin);
vTaskDelay(500);
}
}
char task_info[500]; // 用于保存vTaskList输出的任务信息字符串
/**
* @description: 任务3——按键控制挂起/恢复,并打印任务状态
* KEY1=挂起task1 KEY2=恢复task1
* KEY3=挂起调度器 KEY4=恢复调度器
*/
void task3(void *pvParameters)
{
uint8_t key = 0;
while (1)
{
printf("task3正在运行...\r\n");
key = Key_Detect();
if (key == KEY1_PRESS)
{
/* KEY1按下:挂起task1——task1将停止运行 */
printf(">>>>挂起task1....\r\n");
vTaskSuspend(task1_handle);
}
else if (key == KEY2_PRESS)
{
/* KEY2按下:恢复task1——task1重新进入就绪态 */
printf(">>>>恢复task1....\r\n");
vTaskResume(task1_handle);
}
else if (key == KEY3_PRESS)
{
/* KEY3按下:挂起调度器——所有任务停止切换 */
printf("<<<<挂起调度器....\r\n");
vTaskSuspendAll();
}
else if (key == KEY4_PRESS)
{
/* KEY4按下:恢复调度器——任务切换恢复 */
printf("<<<<恢复调度器....\r\n");
xTaskResumeAll();
}
/* 打印当前所有任务的状态信息 */
vTaskList(task_info);
printf("%s\r\n", task_info);
vTaskDelay(500);
}
}
FreeRTOSConfig.h(启用任务状态跟踪功能):
// 任务挂起/恢复API必须包含
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_xResumeFromISR 1
// 任务列表查询支持
#define configUSE_TRACE_FACILITY 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 1
| Function | Parameters | Return | Description |
|---|---|---|---|
vTaskSuspend |
xTaskToSuspend | void | 挂起指定任务,使其进入挂起态 |
vTaskResume |
xTaskToResume | void | 恢复指定任务,使任务就绪 |
xTaskResumeFromISR |
xTaskToResume | BaseType_t | 从中断中恢复任务,返回 pdTRUE 表示需要任务切换 |
vTaskSuspendAll |
无 | void | 挂起调度器,禁止任务切换 |
xTaskResumeAll |
无 | BaseType_t | 恢复调度器,返回 pdTRUE 表示有挂起的切换 |
vTaskList |
pcWriteBuffer | void | 将任务状态写入字符串缓冲区 |
vTaskSuspendAll() 之后调用 vTaskDelay()、xQueueSend() 等会导致断言失败。只在临界代码段中使用。vTaskSuspend() 只针对单个任务,其余任务正常运行;vTaskSuspendAll() 影响所有任务,常用于保护短代码段。vTaskSuspend() 挂起同一个任务,只需一次 vTaskResume() 即可恢复。xTaskResumeFromISR() 而非 vTaskResume(),并根据返回值判断是否需要 portYIELD_FROM_ISR()。