52Hz——FreeRTOS学习笔记——任务的创建
主要API
xTaskCreate
xTaskCreateStatic
两者区别
特性 xTaskCreate xTaskCreateStatic 内存分配 动态分配(从FreeRTOS堆中) 静态分配(用户提供内存块) TCB和栈内存来源 FreeRTOS内存管理器自动分配 用户预先定义好的全局数组 是否需要用户管理内存 不需要,创建/删除由内核管理 需要用户预先分配内存 内存确定性 不确定(依赖堆内存状态) 确定(编译时即确定)
xTaskCreateStatic补充
FreeRTOS 在启动调度器 (
vTaskStartScheduler()
) 时,必须创建一个空闲任务。这个任务在没有任何其他任务运行时工作,进行内存清理等维护工作。使用静态分配时,你需要实现
vApplicationGetIdleTaskMemory
函数来为空闲任务提供必要的内存块。这个函数有三个参数,都是输出参数,意味着你需要在这些参数指向的位置填写合适的内存地址或大小值:
参数 类型 说明 ppxIdleTaskTCBBuffer
StaticTask_t**
指向空闲任务任务控制块(TCB) 内存地址的指针。 ppxIdleTaskStackBuffer
StackType_t**
指向空闲任务堆栈空间起始地址的指针。 pulIdleTaskStackSize
uint32_t*
指向空闲任务堆栈深度的指针。
vTaskDelay与Hal_Delay
特性 vTaskDelay
(FreeRTOS)HAL_Delay
(HAL库)工作原理 协作式任务调度 忙等待阻塞 CPU行为 让出CPU,其他任务可以运行 独占CPU,空转消耗 适用场景 FreeRTOS多任务环境 裸机程序或初始化代码 对系统影响 提高CPU利用率,支持多任务 浪费CPU资源,阻塞整个系统 精度影响 受任务调度影响,可能有少许抖动 相对精确,但会被中断打断 总结:逻辑开发与FreeRTOS开发 根本区别
方面 裸机开发 FreeRTOS 开发 程序结构 单一超级循环 多任务并行 时间管理 主动等待/轮询 事件驱动/阻塞等待 资源访问 直接访问全局变量 通过IPC机制安全访问 响应性 受最长任务影响 优先级保障实时性 开发思维 顺序思维,关注执行流程 并发思维,关注任务划分 调试难度 相对简单(单线程) 复杂(并发问题) 适用场景 简单应用,资源受限 复杂应用,需要多任务 根本转变:从时间分片的手工管理(裸机)到任务调度的自动管理(FreeRTOS)。
选择哪种方式取决于项目的复杂度。简单的项目用裸机更高效,复杂的项目用 FreeRTOS 更易于管理和维护。
案例
#include "MyTesk.h"
#include "stdio.h"typedef enum{TASK_PREORIY_0,TASK_PREORIY_1,TASK_PREORIY_2,TASK_PREORIY_3,TASK_PREORIY_4,}task_preority;// void led01_task(void *pvParameters);
// TaskHandle_t led01_task_handle;
// #define LED01_TASK_NAME "led01_task"
// #define LED01_TASK_STACK_DEPTH 128// void led02_task(void *pvParameters);
// TaskHandle_t led02_task_handle;
// #define LED02_TASK_NAME "led02_task"
// #define LED02_TASK_STACK_DEPTH 128// void led03_task(void *pvParameters);
// TaskHandle_t led03_task_handle;
// #define LED03_TASK_NAME "led03_task"
// #define LED03_TASK_STACK_DEPTH 128void led01_task(void *pvParameters);
TaskHandle_t Led01_Task_Handle;
#define LED01_TASK_NAME "led01_task"
#define LED01_TASK_STACK_DEPTH 128
StackType_t Led01_Stack_Buff[LED01_TASK_STACK_DEPTH];
StaticTask_t Led01_Task_TCB;//空闲任务相关参数
#define IDLE_TASK_STACK_DEPTH 128
StackType_t Idle_Stack_Buff[IDLE_TASK_STACK_DEPTH];
StaticTask_t Idle_Task_TCB;void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer, StackType_t ** ppxIdleTaskStackBuffer, uint32_t * pulIdleTaskStackSize )
{*ppxIdleTaskTCBBuffer = &Idle_Task_TCB;*ppxIdleTaskStackBuffer = Idle_Stack_Buff;*pulIdleTaskStackSize = IDLE_TASK_STACK_DEPTH;
}void Mytask_Start_Work(void){// 创建任务 自动分配任务栈// xTaskCreate(led01_task, LED01_TASK_NAME, LED01_TASK_STACK_DEPTH, NULL, 4, &led01_task_handle);// xTaskCreate(led02_task, LED02_TASK_NAME, LED02_TASK_STACK_DEPTH, NULL, 4, &led02_task_handle);// xTaskCreate(led03_task, LED03_TASK_NAME, LED03_TASK_STACK_DEPTH, NULL, 4, &led03_task_handle);//静态创建 任务 任务栈手动指定 Led01_Stack_Buff[LED01_TASK_STACK_DEPTH]xTaskCreateStatic(led01_task, LED01_TASK_NAME, LED01_TASK_STACK_DEPTH, NULL, TASK_PREORIY_4, Led01_Stack_Buff, &Led01_Task_TCB);//启动调度器vTaskStartScheduler();}void led01_task(void *pvParameters)
{while (1){Int_LED_Toggle(LED1_GPIO_Port, LED1_Pin);vTaskDelay(200);}}void led02_task(void *pvParameters)
{while (1){Int_LED_Toggle(LED2_GPIO_Port, LED2_Pin);vTaskDelay(200);}
}void led03_task(void *pvParameters)
{while (1){Int_LED_Toggle(LED3_GPIO_Port, LED3_Pin);vTaskDelay(200);}
}