FreeRTOS学习笔记_任务创建和删除

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


任务创建和删除的API函数(熟悉)

任务的创建和删除本质就是调用FreeRTOS的API函数,主要如下:

API函数描述
xTaskCreate()动态方式创建任务
xTaskCreateStatic()静态方式创建任务
vTaskDelete()删除任务
  • 动态创建任务:任务的任务控制块以及任务的栈空间所需的内存,均由 FreeRTOS 从 FreeRTOS 管理的堆中分配。
  • 静态创建任务:任务的任务控制块以及任务的栈空间所需的内存,需用户分配提供。

动态创建任务函数函数说明

BaseType_t xTaskCreate

(
    TaskFunction_t pxTaskCode,                  /* 指向任务函数的指针 */
    const char * const pcName,               /* 任务名字,最大长度configMAX_TASK_NAME_LEN */
    const configSTACK_DEPTH_TYPE usStackDepth,  /* 任务堆栈大小,默认单位4字节 */
    void * const pvParameters,                  /* 传递给任务函数的参数 */
    UBaseType_t uxPriority,                     /* 任务优先级,范围:0 ~ configMAX_PRIORITIES - 1 */
    TaskHandle_t * const pxCreatedTask          /* 任务句柄,就是任务的任务控制块 */)  

返回值说明如下:

  • pdPASS:任务创建成功。
  • errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY:任务创建失败。

动态创建任务步骤

  • 将宏configSUPPORT_DYNAMIC_ALLOCATION 配置为 1。
  • 定义函数入口参数。
  • 编写任务函数。

此函数创建的任务会立刻进入就绪态,由任务调度器调度运行。

动态创建任务函数内部实现

  • 申请堆栈内存&任务控制块内存。
  • TCB结构体成员赋值。
  • 添加新任务到就绪列表中。

任务控制块结构体成员介绍。

typedef struct tskTaskControlBlock      

{

    volatile StackType_t * pxTopOfStack; /* 任务栈栈顶,必须为TCB的第一个成员 */

    ListItem_t xStateListItem;                  /* 任务状态列表项 */

    ListItem_t xEventListItem;                  /* 任务事件列表项 */

    UBaseType_t uxPriority;                     /* 任务优先级,数值越大,优先级越大 */

    StackType_t * pxStack;                      /* 任务栈起始地址 */

    char pcTaskName[ configMAX_TASK_NAME_LEN ]; /* 任务名字 */  

    …

    省略很多条件编译的成员

} tskTCB;

任务栈栈顶,在任务切换时的任务上下文保存、任务恢复息息相关。每个任务都有属于自己的任务控制块,类似身份证。

  1. 静态创建任务函数函数说明
TaskHandle_t xTaskCreateStatic

(

    TaskFunction_t pxTaskCode,          /* 指向任务函数的指针 */

    const char * const pcName,          /* 任务函数名 */

    const uint32_t ulStackDepth,        /* 任务堆栈大小,单位是4字节 */

    void * const pvParameters,          /* 传递的任务函数参数 */

    UBaseType_t uxPriority,             /* 任务优先级 */

    StackType_t * const puxStackBuffer, /* 任务堆栈,一般为数组,由用户分配 */

    StaticTask_t * const pxTaskBuffer   /* 任务控制块指针,由用户分配 */

)

返回值如下:

  • NULL:用户没有提供相应的内存,任务创建失败。
  • 其他值:任务句柄,任务创建成功。
  • 静态创建任务步骤
  • 将宏configSUPPORT_STATIC_ALLOCATION 配置为 1。定义空闲任务&定时器任务的任务堆栈及TCB。
  • 实现接口函数:
  • vApplicationGetIdleTaskMemory()
  • vApplicationGetTimerTaskMemory()(如果开启软件定时器)
  • 定义函数入口参数。
  • 编写任务函数。

此函数创建的任务会立刻进入就绪态,由任务调度器调度运行。

  • 静态创建内部实现
  • TCB结构体成员赋值
  • 添加新任务到就绪列表中

任务删除函数

函数说明

void vTaskDelete( TaskHandle_t xTaskToDelete )

参数说明:xTaskToDelete待删除任务的任务句柄。当传入的参数为NULL,则代表删除任务自身(当前正在运行的任务)。

该函数用于删除已被创建的任务,被删除的任务将从就绪态任务列表、阻塞态任务列表、挂起态任务列表和事件列表中移除。

需要注意的是,空闲任务会负责释放被删除任务中由系统分配的内存,但是由用户在任务删除前申请的内存,则需要由用户在任务被删除前提前释放,否则将导致内存泄露。

  1. 删除任务流程使用删除任务函数,需将宏INCLUDE_vTaskDelete 配置为 1入口参数输入需要删除的任务句柄(NULL代表删除本身)内部实现过程获取所要删除任务的控制块

通过传入的任务句柄,判断所需要删除哪个任务,NULL代表删除自身。

  • 将被删除任务,移除所在列表

将该任务在所在列表中移除,包括:就绪、阻塞、挂起、事件等列表。

  • 判断所需要删除的任务

如果删除任务自身,需先添加到等待删除列表,内存释放将在空闲任务执行;如果删除其他任务,释放内存,任务数量--。

  • 更新下个任务的阻塞时间

更新下一个任务的阻塞超时时间,以防被删除的任务就是下一个阻塞超时的任务。

  1. 任务创建和删除实验(动态方法)(掌握)

动态创建,堆栈是在FreeRTOS管理的堆内存里,注意任务不要重复创建。

xxxxx_STACK_SIZE 128

uxTaskGetStackHighWaterMark()获取指定任务的任务栈的历史剩余最小值,根据这个结果适当调整启动任务的大小。

  1. 实验目标

学会 xTaskCreate( ) 和 vTaskDelete( ) 的使用:

  • start_task:用来创建其他的三个任务。
  • task1:实现LED1每500ms闪烁一次。
  • task2:实现LED2每500ms闪烁一次。
  • task3:判断按键KEY1是否按下,按下则删掉task1。
    • FreeRTOSConfig.h代码清单
#define configSUPPORT_DYNAMIC_ALLOCATION                1
  1.  freertos_demo.c代码清单任务设置
/* 启动任务函数 */

#define START_TASK_PRIORITY 1

#define START_TASK_STACK_DEPTH 128

TaskHandle_t start_task_handler;

void Start_Task(void *pvParameters);

/* Task1 任务 配置 */

#define TASK1_PRIORITY 2

#define TASK1_STACK_DEPTH 128

TaskHandle_t task1_handler;

void Task1(void *pvParameters);

/* Task2 任务 配置 */

#define TASK2_PRIORITY 3

#define TASK2_STACK_DEPTH 128

TaskHandle_t task2_handler;

void Task2(void *pvParameters);

/* Task3 任务 配置 */

#define TASK3_PRIORITY 4

#define TASK3_STACK_DEPTH 128

TaskHandle_t task3_handler;

void Task3(void *pvParameters);
  • 入口函数
/**

 * @description: FreeRTOS入口函数:创建任务函数并开始调度

 * @return {*}

 */

void FreeRTOS_Start(void)

{

    xTaskCreate((TaskFunction_t)Start_Task,

                (char *)"Start_Task",

                (configSTACK_DEPTH_TYPE)START_TASK_STACK_DEPTH,

                (void *)NULL,

                (UBaseType_t)START_TASK_PRIORITY,

                (TaskHandle_t *)&start_task_handler);

    vTaskStartScheduler();

}
  • 启动任务函数
void Start_Task( void * pvParameters )

{

    taskENTER_CRITICAL();               /* 进入临界区 */

    xTaskCreate((TaskFunction_t         )   Task1,

                (char *                 )   "Task1",

                (configSTACK_DEPTH_TYPE )   TASK1_STACK_DEPTH,

                (void *                 )   NULL,

                (UBaseType_t            )   TASK1_PRIORITY,

                (TaskHandle_t *         )   &task1_handler );

    xTaskCreate((TaskFunction_t         )   Task2,

                (char *                 )   "Task2",

                (configSTACK_DEPTH_TYPE )   TASK2_STACK_DEPTH,

                (void *                 )   NULL,

                (UBaseType_t            )   TASK2_PRIORITY,

                (TaskHandle_t *         )   &task2_handler );

    xTaskCreate((TaskFunction_t         )   Task3,

                (char *                 )   "Task2",

                (configSTACK_DEPTH_TYPE )   TASK3_STACK_DEPTH,

                (void *                 )   NULL,

                (UBaseType_t            )   TASK3_PRIORITY,

                (TaskHandle_t *         )   &task3_handler );

    vTaskDelete(NULL);                  

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

}
  • task1函数
/**

 * @description: LED1每500ms翻转一次

 * @param {void *} pvParameters

 * @return {*}

 */

void Task1(void * pvParameters)

{

    while(1)

    {

        printf("task1运行....\r\n");

        LED_Toggle(LED1_Pin);

        vTaskDelay(500);

    }

}
  • task2函数
/**

 * @description: LED2每500ms翻转一次

 * @param {void *} pvParameters

 * @return {*}

 */

void Task2(void * pvParameters)

{

    while(1)

    {

        printf("task2运行....\r\n");

        LED_Toggle(LED2_Pin);

        vTaskDelay(500);

    }

}
  • task3函数
/**

 * @description: 按下KEY1删除task1

 * @param {void *} pvParameters

 * @return {*}

 */

void Task3(void * pvParameters)

{

    uint8_t key = 0;

    while(1)

    {

        printf("task3正在运行...\r\n");

        key = Key_Detect();

        if(key == KEY1_PRESS)

        {

            if(task1_handler != NULL)

            {

                printf("删除task1任务...\r\n");

                vTaskDelete(task1_handler);

                task1_handler = NULL;

            }

        }

        vTaskDelay(10);

    }

}
  1. 任务创建和删除实验(静态方法)(掌握)实验目标

学会 xTaskCreateStatic( )和 vTaskDelete( ) 的使用:

  • start_task:用来创建其他的三个任务。
  • task1:实现LED1每500ms闪烁一次。
  • task2:实现LED2每500ms闪烁一次。
  • task3:判断按键KEY1是否按下,按下则删掉task1。
    • FreeRTOSConfig.h代码清单
#define configSUPPORT_STATIC_ALLOCATION   1
  1. freertos_demo.c代码清单任务设置
/* START_TASK 任务 配置

 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务

 */

#define START_TASK_PRIO         1

#define START_TASK_STACK_SIZE   128

TaskHandle_t    start_task_handler;

StackType_t     start_task_stack[START_TASK_STACK_SIZE];

StaticTask_t    start_task_tcb;

void start_task( void * pvParameters );

/* TASK1 任务 配置

 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务

 */

#define TASK1_PRIO         2

#define TASK1_STACK_SIZE   128

TaskHandle_t    task1_handler;

StackType_t     task1_stack[TASK1_STACK_SIZE];

StaticTask_t    task1_tcb;

void task1( void * pvParameters );

/* TASK2 任务 配置

 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务

 */

#define TASK2_PRIO         3

#define TASK2_STACK_SIZE   128

TaskHandle_t    task2_handler;

StackType_t     task2_stack[TASK2_STACK_SIZE];

StaticTask_t    task2_tcb;

void task2( void * pvParameters );

/* TASK3 任务 配置

 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务

 */

#define TASK3_PRIO         4

#define TASK3_STACK_SIZE   128

TaskHandle_t    task3_handler;

StackType_t     task3_stack[TASK3_STACK_SIZE];

StaticTask_t    task3_tcb;

void task3( void * pvParameters );
  • 空闲任务置及接口函数
/* 空闲任务配置 */

StaticTask_t idle_task_tcb;

StackType_t  idle_task_stack[configMINIMAL_STACK_SIZE];

/* 软件定时器任务配置 */

StaticTask_t timer_task_tcb;

StackType_t  timer_task_stack[configTIMER_TASK_STACK_DEPTH];

/* 空闲任务内存分配 */

void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer,

                                    StackType_t ** ppxIdleTaskStackBuffer,

                                    uint32_t * pulIdleTaskStackSize )

{

    * ppxIdleTaskTCBBuffer = &idle_task_tcb;

    * ppxIdleTaskStackBuffer = idle_task_stack;

    * pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;

}
  • 入口函数
/**

 * @description: FreeRTOS入口函数:创建任务函数并开始调度

 * @return {*}

 */

void FreeRTOS_Start(void)

{

    start_task_handler = xTaskCreateStatic((TaskFunction_t)Start_Task,

                                           (char *)"Start_Task",

                                           (uint32_t)START_TASK_STACK_DEPTH,

                                           (void *)NULL,

                                           (UBaseType_t)START_TASK_PRIORITY,

                                           (StackType_t *)start_task_stack,

                                           (StaticTask_t *)&start_task_tcb);

    vTaskStartScheduler();

}
  • 启动函数
void Start_Task(void *pvParameters)

{

    taskENTER_CRITICAL(); /* 进入临界区 */

    task1_handler = xTaskCreateStatic((TaskFunction_t)Task1,

                                      (char *)"Task1",

                                      (uint32_t)TASK1_STACK_DEPTH,

                                      (void *)NULL,

                                      (UBaseType_t)TASK1_PRIORITY,

                                      (StackType_t *)task1_stack,

                                      (StaticTask_t *)&task1_tcb);

    task2_handler = xTaskCreateStatic((TaskFunction_t)Task2,

                                      (char *)"Task2",

                                      (uint32_t)TASK2_STACK_DEPTH,

                                      (void *)NULL,

                                      (UBaseType_t)TASK2_PRIORITY,

                                      (StackType_t *)task2_stack,

                                      (StaticTask_t *)&task2_tcb);

    task3_handler = xTaskCreateStatic((TaskFunction_t)Task3,

                                      (char *)"Task3",

                                      (uint32_t)TASK3_STACK_DEPTH,

                                      (void *)NULL,

                                      (UBaseType_t)TASK3_PRIORITY,

                                      (StackType_t *)task3_stack,

                                      (StaticTask_t *)&task3_tcb);

    vTaskDelete(start_task_handler);  

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

}
  • task1函数
/**

 * @description: LED1每500ms翻转一次

 * @param {void *} pvParameters

 * @return {*}

 */

void Task1(void * pvParameters)

{

    while(1)

    {

        printf("task1运行....\r\n");

        LED_Toggle(LED1_Pin);

        vTaskDelay(500);

    }

}
  • task2函数
/**

 * @description: LED2每500ms翻转一次

 * @param {void *} pvParameters

 * @return {*}

 */

void Task2(void * pvParameters)

{

    while(1)

    {

        printf("task2运行....\r\n");

        LED_Toggle(LED2_Pin);

        vTaskDelay(500);

    }

}
  • task3函数
/**

 * @description: 按下KEY1删除task1

 * @param {void *} pvParameters

 * @return {*}

 */

void Task3(void * pvParameters)

{

    uint8_t key = 0;

    while(1)

    {

        printf("task3正在运行...\r\n");

        key = Key_Detect();

        if(key == KEY1_PRESS)

        {

            if(task1_handler != NULL)

            {

                printf("删除task1任务...\r\n");

                vTaskDelete(task1_handler);

                task1_handler = NULL;

            }

        }

        vTaskDelay(10);

    }

}