FreeRTOS_任务挂起与恢复

犀利的毛毛虫 发布于 2025-03-07 244 次阅读


任务的挂起与恢复的API函数(熟悉)

  1. vTaskSuspend():挂起任务, 类似暂停,可恢复
  2. vTaskResume():恢复被挂起的任务
  3. xTaskResumeFromISR():在中断中恢复被挂起的任务

任务挂起函数

void vTaskSuspend( TaskHandle_t xTaskToSuspend )
  • xTaskToSuspend:待挂起任务的任务句柄,为NULL表示挂起任务自身。
  • 需将宏INCLUDE_vTaskSuspend配置为 1。

任务恢复函数

void vTaskResume( TaskHandle_t xTaskToResume )
  • INCLUDE_vTaskSuspend必须定义为 1。
  • 不论任务被使用 vTaskSuspend() 挂起多少次,只需调用 vTaskResume() 一次,即可使其继续执行。被恢复的任务会重新进入就绪状态。

任务恢复函数(中断中恢复)

函数说明

BaseType_t xTaskResumeFromISR( TaskHandle_t xTaskToResume )

返回值如下:

  • pdTRUE:任务恢复后需要进行任务切换。
  • pdFALSE:任务恢复后不需要进行任务切换。

注意事项

  • INCLUDE_vTaskSuspend 和 INCLUDE_xTaskResumeFromISR 必须定义为 1。
  • 在中断服务程序中调用FreeRTOS的API函数时,中断的优先级不能高于FreeRTOS所管理的最高中断优先级。

挂起与恢复调度器

  1. vTaskSuspendAll():挂起任务调度器,调度器不会进行任务切换,当前任务一直运行。
  2. xTaskResumeAll():恢复任务调度器,调度器继续任务切换。

查看任务状态

/* 开启跟踪task信息 */
#define configUSE_TRACE_FACILITY 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 1
void vTaskList( char * pcWriteBuffer )

名称     状态     优先级    堆栈使用  任务编号

'X'(运行) 'B'(阻塞)、'R'(就绪)、'S'(暂停)或 'D'(删除)。

任务挂起与恢复实验(掌握)

  • start_task:用来创建其他的三个任务。
  • task1:实现LED1每500ms闪烁一次。
  • task2:实现LED2每500ms闪烁一次。
  • task3:判断按键按下逻辑,KEY1按下,挂起task1,按下KEY2在任务中恢复task1,KEY3按下,挂起调度器,KEY4按下,恢复调度器,并打印任务的状态。

FreeRTOSConfig.h代码清单

#define INCLUDE_vTaskSuspend                            1
#define INCLUDE_xResumeFromISR                          1
/* 开启跟踪task信息 */
#define configUSE_TRACE_FACILITY 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 1

freertos_demo.c代码清单

#include "freertos_demo.h"
/* freertos相关的头文件,必须的 */
#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
 * @return {*}
 */
void freertos_start(void)
{
    /* 1.创建一个启动任务 */
    xTaskCreate((TaskFunction_t)start_task,               // 任务函数的地址
                (char *)"start_task",                     // 任务名字符串
                (configSTACK_DEPTH_TYPE)START_TASK_STACK, // 任务栈大小,默认最小128,单位4字节
                (void *)NULL,                             // 传递给任务的参数
                (UBaseType_t)START_TASK_PRIORITY,         // 任务的优先级
                (TaskHandle_t *)&start_task_handle);      // 任务句柄的地址

    /* 2.启动调度器:会自动创建空闲任务 */
    vTaskStartScheduler();
}

/**
 * @description: 启动任务:用来创建其他Task
 * @param {void} *pvParameters
 * @return {*}
 */
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();
}

/**
 * @description: 任务一:实现LED1每500ms闪烁一次
 * @param {void} *pvParameters
 * @return {*}
 */
void task1(void *pvParameters)
{

    while (1)
    {
        printf("task1运行...\r\n");
        LED_Toggle(LED1_Pin);
        vTaskDelay(500);
    }
}

/**
 * @description: 任务二:实现LED2每500ms闪烁一次
 * @param {void} *pvParameters
 * @return {*}
 */
void task2(void *pvParameters)
{
    while (1)
    {
        printf("task2运行...\r\n");
        LED_Toggle(LED2_Pin);
        vTaskDelay(500);
    }
}

/**
 * @description: 任务三:判断按键按下逻辑,KEY1按下,挂起task1,按下KEY2在任务中恢复task1,KEY3按下,挂起调度器,KEY4按下,恢复调度器,并打印任务的状态
 * @param {void} *pvParameters
 * @return {*}
 */
char task_info[500]; //定义一个字符数组,用于接收任务信息字符串
void task3(void *pvParameters)
{
    uint8_t key = 0;
    while (1)
    {
        printf("task3运行...\r\n");
        key = Key_Detect();
        if (key == KEY1_PRESS)
        {
            /* key1按下,挂起task1 */
            printf(">>>>挂起task1....\r\n");
            vTaskSuspend(task1_handle);
        }
        else if (key == KEY2_PRESS)
        {
            /* key2按下,恢复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);
    }
}