这篇文章在于 详细解释 FreeRTOS 中任务的创建过程,包括任务创建的本质过程、API 详解、两种创建方式(动态/静态)、任务函数规范、常见错误及实践建议。
这里参照:RTOS官方文档:https://www.freertos.org/zh-cn-cmn-s/Documentation/02-Kernel/04-API-references/01-Task-creation/01-xTaskCreate
FreeRTOS 的“任务”
在 FreeRTOS 中,每个任务(Task)就是一个可以独立运行的“线程”或“执行单元”,具有:
自己的函数入口(任务函数)
独立的堆栈空间
独立的上下文(CPU 寄存器、程序计数器)
FreeRTOS 通过任务调度器(Scheduler)来在这些任务之间切换执行权,实现 “多任务并发”。
创建任务的方式
动态创建任务(最常用)(上述官网链接)
xTaskCreate()
是 FreeRTOS 中最常用的任务创建函数,适合一般嵌入式系统中动态创建任务,使用时需合理配置堆大小和任务优先级,确保系统资源充足。
使用 API 函数:xTaskCreate()
BaseType_t xTaskCreate(TaskFunction_t pvTaskCode,const char * const pcName,const configSTACK_DEPTH_TYPE uxStackDepth,void *pvParameters,UBaseType_t uxPriority,TaskHandle_t *pxCreatedTask
);
参数说明:
pvTaskCode 任务入口函数(必须是 void func(void *pvParameters) 形式)
pcName 任务名(调试用途)
uxStackDepth 堆栈大小(单位是“字”,不是字节) STM32 上 1 word = 4 字节
pvParameters 创建任务时传入的参数指针
uxPriority 任务优先级(0 ~ configMAX_PRIORITIES - 1)
pxCreatedTask 任务句柄的地址(可为 NULL)返回值:
pdPASS:创建成功
errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY:内存不足,任务创建失败
由于官方文档里的链接内容过于理论化,不易理解,这里用大白话翻译一下:
xTaskCreate()
函数详解:
功能说明:
用于创建一个新的任务并将其加入到就绪列表中。
必须启用FreeRTOSConfig.h
中的宏:
#define configSUPPORT_DYNAMIC_ALLOCATION 1
使用动态内存分配方式从 FreeRTOS 的堆中分配 任务堆栈 和 任务控制块。
使用注意事项:
- 堆栈大小单位是“字”(word)
- 在 Cortex-M3/M4 中,1 word = 4 字节
所以128
表示 512 字节堆栈空间- 任务函数不能 return
- 必须是一个无限循环
for(;;)
或while(1){}
- 若任务要结束,需使用
vTaskDelete(NULL)
- pvParameters 传参要小心生命周期
- 不要传局部变量地址
- 可以传入静态变量或常量值
- 优先级不能超过
configMAX_PRIORITIES - 1
- 否则调度器行为不确定
- 建议使用
tskIDLE_PRIORITY + x
这种写法
完整的任务创建示例
/********************************************************************************* @file Project/STM32F10x_StdPeriph_Template/main.c * @author MCD Application Team* @version V3.5.0* @date 08-April-2011* @brief Main program body******************************************************************************* @attention** THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.** <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>*******************************************************************************/ /* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include <stdio.h>
#include "FreeRTOS.h"
#include "task.h"
#include "usart.h"
#include "gpio.h"//------------------------- start_task --------------------------------------------//
void start_task(void *pvParameters); //任务函数入口
TaskHandle_t StartTask_Handler; //任务句柄 _任务身份证_每个任务都有独立的任务
#define START_STK_SIZE 64 //任务堆栈大小
#define START_TASK_PRO 1 //任务优先级
//-----------------------------------------------------------------------//在主函数中创建任务
void Start()
{
//------------------------- start_task --------------------------------------------////初始化函数xTaskCreate((TaskFunction_t) start_task, //任务函数入口(const char * ) "start_task", //任务函数名称(uint16_t ) START_STK_SIZE, //任务堆栈大小(void * ) NULL, //任务参数入口(UBaseType_t ) START_TASK_PRO, //任务优先级(TaskHandle_t *) StartTask_Handler ); //任务句柄vTaskStartScheduler(); //开启任务调度器
}int main(void)
{NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 ); //RTOS需要将中断优先级分组分配到第四组usart_init(115200);MX_GPIO_Init();printf("Create Task! \r\n");Start();while(1) // 不会执行到这里{}}//任务函数(必须是无限循环)
void start_task(void *pvParameters) //任务函数入口
{printf("start Task Run! \r\n");while(1){GPIO_WriteBit(GPIOC, GPIO_Pin_7, Bit_RESET); //绿灯闪烁vTaskDelay(500);GPIO_WriteBit(GPIOC, GPIO_Pin_7, Bit_SET); //绿灯关闭vTaskDelay(500);vTaskDelay(10);}
}/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
FreeRTOS 中,任务是最基本的执行单元。你可以通过 xTaskCreate()
或 xTaskCreateStatic()
创建任务,并通过调度器进行任务切换,从而实现多任务并发执行。任务函数必须是无限循环,并适当使用延时函数避免占用 CPU。
静态创建任务(更可控) (不详细介绍,较少使用)
使用 API 函数:xTaskCreateStatic()
TaskHandle_t xTaskCreateStatic(TaskFunction_t pvTaskCode,const char * const pcName,const uint32_t ulStackDepth,void *pvParameters,UBaseType_t uxPriority,StackType_t *puxStackBuffer,StaticTask_t *pxTaskBuffer
);
用户自己提供堆栈数组 + TCB 缓存
更适合内存受限嵌入式场景
不依赖 FreeRTOS 的堆(heap_4.c
)
动态 vs 静态任务创建对比:
项目 | 动态创建 xTaskCreate | 静态创建 xTaskCreateStatic |
---|---|---|
内存分配 | 使用 FreeRTOS 堆 | 用户手动提供 |
灵活性 | 高 | 稍低 |
控制性 | 低 | 高 |
适合场景 | 一般应用 | 内存受限、认证项目 |
最后,解释一下任务句柄的用途:任务句柄 类似于每个任务的身份证,每个任务都有独立的任务句柄标识。
创建任务时可以返回任务句柄(TaskHandle_t
),用于:
- 删除任务:
vTaskDelete(xHandle);
- 挂起任务:
vTaskSuspend(xHandle);
- 恢复任务:
vTaskResume(xHandle);
- 获取任务状态:
eTaskGetState(xHandle);
以上,便是 FreeRTOS 任务的创建。
以上,欢迎有从事同行业的电子信息工程、互联网通信、嵌入式开发的朋友共同探讨与提问,我可以提供实战演示或模板库。希望内容能够对你产生帮助!