【STM32】FreeRTOS 任务的创建(二)

这篇文章在于 详细解释 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()

c 复制代码
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 中的宏:

c 复制代码
#define configSUPPORT_DYNAMIC_ALLOCATION 1

使用动态内存分配方式从 FreeRTOS 的堆中分配 任务堆栈任务控制块。

使用注意事项:
  1. 堆栈大小单位是"字"(word)
    • 在 Cortex-M3/M4 中,1 word = 4 字节
      所以 128 表示 512 字节堆栈空间
  2. 任务函数不能 return
    • 必须是一个无限循环 for(;;)while(1){}
    • 若任务要结束,需使用 vTaskDelete(NULL)
  3. pvParameters 传参要小心生命周期
    • 不要传局部变量地址
    • 可以传入静态变量或常量值
  4. 优先级不能超过 configMAX_PRIORITIES - 1
    • 否则调度器行为不确定
    • 建议使用 tskIDLE_PRIORITY + x 这种写法
完整的任务创建示例
c 复制代码
/**
  ******************************************************************************
  * @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>&copy; 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()

c 复制代码
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 任务的创建。

以上,欢迎有从事同行业的电子信息工程、互联网通信、嵌入式开发的朋友共同探讨与提问,我可以提供实战演示或模板库。希望内容能够对你产生帮助!

相关推荐
炸膛坦客20 小时前
Cortex-M3 内核 MCU-STM32F1 开发之路:(一)单片机 MCU 的构成,包括 FLASH 和 SRAM 的区别,以及引脚类型
stm32·单片机·嵌入式硬件
A9better20 小时前
嵌入式开发学习日志39——stm32之I2C总线物理层与常用术语
stm32·单片机·嵌入式硬件·学习
三佛科技-1873661339720 小时前
FT62FC3X 8位MCU单片机选型表,详细解析FT62FC31A/32A/33A/35A/3FA
单片机·嵌入式硬件
充哥单片机设计20 小时前
【STM32项目开源】基于STM32的智能衣柜系统
stm32·单片机·嵌入式硬件
Try1harder21 小时前
极海APM32F107V6 + 合宙Air780E
单片机·嵌入式硬件·物联网·合宙air780
文火冰糖的硅基工坊21 小时前
[嵌入式系统-134]:智能体以及其嵌入式硬件架构
科技·嵌入式硬件·架构·嵌入式·gpu
电鱼智能的电小鱼21 小时前
服装制造企业痛点解决方案:EFISH-SBC-RK3588 柔性化吊挂调度方案
网络·人工智能·嵌入式硬件·算法·制造
清风6666661 天前
基于单片机的便携式温湿度检测烘干机设计
单片机·嵌入式硬件·毕业设计·课程设计
刻BITTER1 天前
用CMake 实现U8g2 的 SDL2 模拟环境
c++·stm32·单片机·嵌入式硬件·arduino
c#上位机1 天前
wpf中Grid的MouseDown 事件无法触发的原因
c#·wpf