当前位置: 首页 > news >正文

FreeRTOS任务创建与删除

任务的创建与删除本质就是调用API函数

  • xTaskCreate()-动态方式创建任务

      特点:任务的任务块,以及任务的栈空间所需内存由FreeRTOS自己分配

  • xTaskCreateStatic()-静态方式创建任务

      特点:任务的任务块,以及任务的栈空间所需内存由用户分配

  • vTaskDelete()删除任务,删除创建好的任务

一.xTaskCreate()-动态方式创建任务

整体函数返回值

  • BaseType_t:FreeRTOS 定义的基础类型(通常为 typedef int BaseType_t),表示函数执行状态:
    • pdPASS(或 pdTRUE):任务创建成功。
    • 错误码(如 errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY):内存分配失败或参数错误。

最后一项也就是任务块,作用是操作系统管理任务的数据中心,它存储了任务的所有状态信息

1.任务步骤

2.解释TCB

注意:TCB结构体成员赋值也就是给任务控制块结构体成员赋值,

任务控制块是操作系统管理任务的数据中心,它存储了任务的所有状态信息,包括:

  • 执行上下文:CPU 寄存器值(如 PC、SP、R0-R15)。
  • 任务状态:就绪、运行、阻塞、挂起等。
  • 优先级:决定任务调度顺序。
  • 堆栈指针:指向任务专用的堆栈空间。
  • 时间片计数:用于时间片轮转调度。
  • 阻塞时间:任务等待事件的剩余时间。
  • 链表节点:用于挂载到不同状态列表(就绪列表、阻塞列表等)。

3.实例教程

根据上面的第一步:将宏configSUPPORT_DYNAMIC_ALLOCATION配置为1

  • 找到FreeRTOSConfig.h文件

 一般默认为动态(也就是1)

  • 创建任务,使用xTaskCreate

这里定义了一个启动任务,在这个任务创建其它任务。

void freertos_demo(void)
{    xTaskCreate((TaskFunction_t         )   start_task,        /* 任务入口函数指针 */(char *                 )   "start_task",      /* 任务名称(用于调试) */(configSTACK_DEPTH_TYPE )   START_TASK_STACK_SIZE, /* 任务堆栈大小 */(void *                 )   NULL,              /* 传递给任务的参数 */(UBaseType_t            )   START_TASK_PRIO,   /* 任务优先级 */(TaskHandle_t *         )   &start_task_handler /* 任务句柄 */  );/* 启动FreeRTOS调度器 */vTaskStartScheduler();
}
  • 创建完之后,需要再定义任务堆栈大小,定义任务优先级、任务句柄
#define START_TASK_PRIO         1     //定义优先级
#define START_TASK_STACK_SIZE   128   //定义堆栈大小,实际占用512字节(32位系统)
TaskHandle_t    start_task_handler;   //定义句柄
void start_task( void * pvParameters ); //声明一下函数
  • 在start_task里面定义要做的事情
void start_task( void * pvParameters )
{taskENTER_CRITICAL();               /* 进入临界区 */xTaskCreate((TaskFunction_t         )   task1,(char *                 )   "task1",(configSTACK_DEPTH_TYPE )   TASK1_STACK_SIZE,(void *                 )   NULL,(UBaseType_t            )   TASK1_PRIO,(TaskHandle_t *         )   &task1_handler );xTaskCreate((TaskFunction_t         )   task2,(char *                 )   "task2",(configSTACK_DEPTH_TYPE )   TASK2_STACK_SIZE,(void *                 )   NULL,(UBaseType_t            )   TASK2_PRIO,(TaskHandle_t *         )   &task2_handler );xTaskCreate((TaskFunction_t         )   task3,(char *                 )   "task3",(configSTACK_DEPTH_TYPE )   TASK3_STACK_SIZE,(void *                 )   NULL,(UBaseType_t            )   TASK3_PRIO,(TaskHandle_t *         )   &task3_handler );vTaskDelete(NULL);taskEXIT_CRITICAL();                /* 退出临界区 */
}
  • 最后就是将自己的task1、task2、task3要做的事情再定义一遍,以下是完整代码:
/******************************************************************************************************* @file        freertos.c* @author      正点原子团队(ALIENTEK)* @version     V1.4* @date        2022-01-04* @brief       FreeRTOS 移植实验* @license     Copyright (c) 2020-2032, 广州市星翼电子科技有限公司***************************************************************************************************** @attention** 实验平台:正点原子 F407电机开发板* 在线视频:www.yuanzige.com* 技术论坛:www.openedv.com* 公司网址:www.alientek.com* 购买地址:openedv.taobao.com******************************************************************************************************/#include "freertos_demo.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
/*FreeRTOS*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.h"/******************************************************************************************************/
/*FreeRTOS配置*//* START_TASK 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define START_TASK_PRIO         1
#define START_TASK_STACK_SIZE   128   // 实际占用512字节(32位系统)
TaskHandle_t    start_task_handler;
void start_task( void * pvParameters );/* TASK1 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define TASK1_PRIO         2
#define TASK1_STACK_SIZE   128    // 实际占用512字节(32位系统)
TaskHandle_t    task1_handler;
void task1( void * pvParameters );/* TASK2 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define TASK2_PRIO         3
#define TASK2_STACK_SIZE   128  // 实际占用512字节(32位系统)
TaskHandle_t    task2_handler;
void task2( void * pvParameters );/* TASK3 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define TASK3_PRIO         4
#define TASK3_STACK_SIZE   128
TaskHandle_t    task3_handler;
void task3( void * pvParameters );
/******************************************************************************************************//*** @brief       FreeRTOS例程入口函数* @param       无* @retval      无*/
void freertos_demo(void)
{    xTaskCreate((TaskFunction_t         )   start_task,(char *                 )   "start_task",(configSTACK_DEPTH_TYPE )   START_TASK_STACK_SIZE,(void *                 )   NULL,(UBaseType_t            )   START_TASK_PRIO,(TaskHandle_t *         )   &start_task_handler );vTaskStartScheduler();
}void start_task( void * pvParameters )
{taskENTER_CRITICAL();               /* 进入临界区 ,用来关闭中断,任务切换就不会进行*/xTaskCreate((TaskFunction_t         )   task1,(char *                 )   "task1",(configSTACK_DEPTH_TYPE )   TASK1_STACK_SIZE,(void *                 )   NULL,(UBaseType_t            )   TASK1_PRIO,(TaskHandle_t *         )   &task1_handler );xTaskCreate((TaskFunction_t         )   task2,(char *                 )   "task2",(configSTACK_DEPTH_TYPE )   TASK2_STACK_SIZE,(void *                 )   NULL,(UBaseType_t            )   TASK2_PRIO,(TaskHandle_t *         )   &task2_handler );xTaskCreate((TaskFunction_t         )   task3,(char *                 )   "task3",(configSTACK_DEPTH_TYPE )   TASK3_STACK_SIZE,(void *                 )   NULL,(UBaseType_t            )   TASK3_PRIO,(TaskHandle_t *         )   &task3_handler );vTaskDelete(NULL);taskEXIT_CRITICAL();                /* 退出临界区 ,开始任务切换*/
}/* 任务一,实现LED0每500ms翻转一次 */
void task1( void * pvParameters )
{while(1){printf("task1正在运行!!!\r\n");LED0_TOGGLE();vTaskDelay(500);}
}/* 任务二,实现LED1每500ms翻转一次 */
void task2( void * pvParameters )
{while(1){printf("task2正在运行!!!\r\n");LED1_TOGGLE();vTaskDelay(500);}
}/* 任务三,判断按键KEY0,按下KEY0删除task1 */
void task3( void * pvParameters )
{uint8_t key = 0;while(1){printf("task3正在运行!!!\r\n");key = key_scan(0);if(key == KEY0_PRES){if(task1_handler != NULL){printf("删除task1任务\r\n");vTaskDelete(task1_handler);task1_handler = NULL;}}vTaskDelay(10);}
}

注意:若是不加入临界区那么,这里的任务顺序是START_TASK_PRIO——>TASK1——>TASK2——>TASK3——>TASK3——>TASK3——>TASK3.......

加入临界区任务顺序是:TASK3——>TASK2——>TASK1——>TASK3——>TASK3......

二、xTaskCreateStatic()-静态方式创建任务

和动态不一样的点在于最后两个,因为是自己创建,所以堆栈空间自然是由自己分配     

1.任务步骤

  • 需将宏configSUPPORT_STATIC_ALLOCATION 配置为 1
  • 定义空闲任务&定时器任务的任务堆栈及TCB

       由于静态创建不使用堆内存,FreeRTOS 无法自动为空闲任务分配内存。因此,用户必须通过实现vApplicationGetIdleTaskMemory()回调函数,手动提供空闲任务所需的 TCB 和堆栈空间。

  • 实现两个接口函数   {      vApplicationGetIdleTaskMemory( )      提供空闲任务所需的 TCB 和堆栈空间  ,这个必须要有

                                      {       vApplicationGetTimerTaskMemory ( )  提供定时器任务的内存

  • 定义函数入口参数
  • 编写任务函数

注意: 

  • 空闲任务是系统必需的最低优先级任务,负责回收任务资源和实现低功耗模式。
  • 软件定时器任务管理所有软件定时器的回调执行,简化了定时功能的实现。
  • 在静态内存分配模式下,必须为这两个任务预分配内存并通过回调函数告知内核,否则系统无法正常启动或定时器功能失效。

2.实例教程

[1]空闲任务配置

       调用函数:vApplicationGetIdleTaskMemory

/* 功能:    空闲任务内存分配入口参数:StaticTask_t **(指向任务控制块指针的指针)内核通过这个参数获取预分配的空闲任务控制块(TCB)的地址StackType_t **(指向任务堆栈指针的指针)内核通过这个参数获取预分配的空闲任务堆栈的起始地址。uint32_t *(指向无符号 32 位整数的指针)内核通过这个参数获取预分配的空闲任务堆栈的大小(单位:字,Word)。返回参数: 无
*/void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer,StackType_t ** ppxIdleTaskStackBuffer,uint32_t * pulIdleTaskStackSize )
{* ppxIdleTaskTCBBuffer = &idle_task_tcb;* ppxIdleTaskStackBuffer = idle_task_stack;* pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
}

这里一共有三个入口参数 ,都是要指向指针,所以要先提前定义。

/* 空闲任务配置 */
StaticTask_t idle_task_tcb;
StackType_t  idle_task_stack[configMINIMAL_STACK_SIZE];
[2]软件定时器任务配置

同理

/* 功能:    软件定时器内存分配入口参数:StaticTask_t **(指向任务控制块指针的指针)内核通过这个参数获取预分配的定时器服务任务控制块(TCB)的地址StackType_t **(指向任务堆栈指针的指针)内核通过这个参数获取预分配的定时器服务任务堆栈的起始地址。uint32_t *(指向无符号 32 位整数的指针)内核通过这个参数获取预分配的定时器服务任务堆栈的大小(单位:字,Word)。返回参数: 无
*/
void vApplicationGetTimerTaskMemory( StaticTask_t ** ppxTimerTaskTCBBuffer,StackType_t ** ppxTimerTaskStackBuffer,uint32_t * pulTimerTaskStackSize )
{* ppxTimerTaskTCBBuffer = &timer_task_tcb;* ppxTimerTaskStackBuffer = timer_task_stack;* pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
}
/* 软件定时器任务配置 */
StaticTask_t timer_task_tcb;
StackType_t  timer_task_stack[configTIMER_TASK_STACK_DEPTH];

在上述两个配置当中,任务堆栈大小在 FreeRTOSConfig.h中可以查找到定义及大小。

[3] 创建开始任务

以下是静态创建函数原型,这里注意它的返回值,是一个任务句柄,而动态任务,返回的是一个是否成功的信息,为什么会不一样呢?

    由于内存由用户静态分配,只要参数合法,函数不会失败(无需返回错误码)。

    任务句柄直接返回:简化接口,直接将任务句柄作为返回值。

TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode,const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */const uint32_t ulStackDepth,void * const pvParameters,UBaseType_t uxPriority,StackType_t * const puxStackBuffer,StaticTask_t * const pxTaskBuffer )

 以下对于参数定义,流程和动态方式一样,多了两个参数。

/* 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 );/*** @brief       FreeRTOS例程入口函数* @param       无* @retval      无*/
void freertos_demo(void)
{    /* 创建起始任务 - 系统第一个运行的任务 */start_task_handler = xTaskCreateStatic(      /*  */(TaskFunction_t )   start_task,         /* 任务函数指针,指向起始任务的实现 */(char *         )   "start_task",       /* 任务名称,用于调试和可视化工具 */(uint32_t       )   START_TASK_STACK_SIZE, /* 任务堆栈大小,单位为字(Word) */(void *         )   NULL,               /* 传递给任务函数的参数 */(UBaseType_t    )   START_TASK_PRIO,    /* 任务优先级,数值越大优先级越高 */(StackType_t *  )   start_task_stack,   /* 静态分配的任务堆栈数组 */(StaticTask_t * )   &start_task_tcb     /* 任务控制块,存储任务状态信息 */);/* 启动FreeRTOS调度器*/vTaskStartScheduler();
}
[4]在初始任务里面创建其它任务 
void start_task( void * pvParameters )
{taskENTER_CRITICAL();               /* 进入临界区 */task1_handler = xTaskCreateStatic(  (TaskFunction_t )   task1,(char *         )   "task1", (uint32_t       )   TASK1_STACK_SIZE,(void *         )   NULL,(UBaseType_t    )   TASK1_PRIO,(StackType_t *  )   task1_stack,(StaticTask_t * )   &task1_tcb );task2_handler = xTaskCreateStatic(  (TaskFunction_t )   task2,(char *         )   "task2", (uint32_t       )   TASK2_STACK_SIZE,(void *         )   NULL,(UBaseType_t    )   TASK2_PRIO,(StackType_t *  )   task2_stack,(StaticTask_t * )   &task2_tcb );task3_handler = xTaskCreateStatic(  (TaskFunction_t )   task3,(char *         )   "task3", (uint32_t       )   TASK3_STACK_SIZE,(void *         )   NULL,(UBaseType_t    )   TASK3_PRIO,(StackType_t *  )   task3_stack,(StaticTask_t * )   &task3_tcb );vTaskDelete(start_task_handler);taskEXIT_CRITICAL();                /* 退出临界区 */
}

注意:使用 taskENTER_CRITICAL() 和 taskEXIT_CRITICAL() 包裹的代码块就是临界区,其核心目的是 确保代码在执行期间不会被其他任务或中断打断。 

[5]其余任务和动态一样 

三、任务删除函数 

void vTaskDelete(TaskHandle_t xTaskToDelete);

xTaskToDelete   :  待删除任务的句柄(类似于ID卡)

被删除任务将会从就绪态任务列表、阻塞态任务列表、挂起态任务列表和事件列表中移除

注意

1.当传入的参数为NULL,则代表删除任务自身(当前正在运行的任务)

2.动态任务删除时-----任务终止后,FreeRTOS 会自动调用vPortFree()释放 TCB 和堆栈占用的内存,将其归还堆空间。

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

删除任务流程

1、使用删除任务函数,需将宏INCLUDE_vTaskDelete 配置为 1

2、入口参数输入需要删除的任务句柄(NULL代表删除本身)

对于第四点解析:

假设系统中有三个任务:

  • Task1:阻塞 20ms(即将超时的任务,位于链表头)
  • Task2:阻塞 50ms
  • Task3:阻塞 100ms

当删除 Task1 时:

  1. Task1 从阻塞链表移除。
  2. 调度器自动将 Task2 设为新的链表头(下一个超时任务为 50ms)。
  3. 系统滴答计数器将在 50ms 时唤醒 Task2,而非原计划的 20ms。
http://www.dtcms.com/a/289106.html

相关文章:

  • 掌握配置文件(三):运用Profile实现多环境配置隔离
  • 三级知识点汇总(详解)【c++】——3
  • 让不符合要求的任何电脑升级Windows11
  • 《通信原理》学习笔记——第五章
  • 开源安全大模型Foundation-Sec 8B的安全实践
  • 分享如何在保证画质的前提下缩小视频体积实用方案
  • 【记某次线上消息积压问题排查及解决方案】
  • 基于Pytorch的人脸识别程序
  • 基于FPGA实现ARINC818
  • Milvus Dify 学习笔记
  • Unity学习笔记(五)——3DRPG游戏(2)
  • DFS 迷宫问题 难度:★★★★☆
  • Python适配器模式详解:让不兼容的接口协同工作
  • CSS中Padding与Margin的区别
  • 机器学习-线性回归
  • 【数据结构】「队列」(顺序队列、链式队列、双端队列)
  • ubuntu24.04安装CUDA和VLLM
  • 企业级安全威胁检测与响应(EDR/XDR)架构设计
  • WireShark抓包分析TCP数据传输过程与内容详解
  • 多目标轨迹优化车道变换规划:自动驾驶轨迹规划新范式:基于Frenet坐标系的车道变换算法全解析
  • Node.js Express keep-alive 超时时间设置
  • spring boot2升级boot3
  • Linux简单了解历史
  • 大数据之路:阿里巴巴大数据实践——离线数据开发
  • RTC外设详解
  • Unity 新旧输入系统对比
  • XSS内容总结
  • 包装类型+泛型+List+ArrayList
  • [CVPR]DVFL-Net:用于时空动作识别的轻量级蒸馏视频调焦网络
  • 连接语言大模型(LLM)服务进行对话