学习FreeRTOS(first day)
一、认识FreeRTOS
1、我们先来认识一下什么是FressRTOS:
RTOS的全称是Real time operating system,翻译成中文就是实时操作系统
那么操作系统能用来干什么呢?
操作系统是允许多个任务同时运行(多任务),其中的原理是——一个处理器核在某一时刻只能运行一个任务
操作系统中 任务调度器 的责任就是决定在某一时刻究竟运行的哪个 任务 。任务调度在各个任务之间的切换非常快,就给人们造成了同一时刻有多个任务同时运行的错觉。
2、使用STM32CubeMX创建了一个FreeRTOS工程
具体的创建工程文件可参考新建一个FreeRTOS的工程_stm32cubemx创建freertos-CSDN博客
3、现在我们来创建一个让LED和蜂鸣器同时进行的任务(多任务程序)
(1)关于控制LED的c文件,只让LED管脚的电平在高低之间切换,在其中加上延时即可
void Led_Test()
{HAL_GPIO_WritePin(GPIOA,GPIO_PIN_7,GPIO_PIN_RESET);HAL_Delay(500);HAL_GPIO_WritePin(GPIOA,GPIO_PIN_7,GPIO_PIN_SET);HAL_Delay(500);
}
(2)关于控制BEEP的c文件
#include "gpio.h"
#include "FreeRTOS.h"
#include "task.h"
#include "cmsis_os.h"
#include <stdio.h>
#include "usart.h"TaskHandle_t beephandle;void beep_test()
{HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET);HAL_Delay(500);HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET);HAL_Delay(500);
}void beep_task_Init(void)
{for(;;){beep_test();}
}
这里与LED同理,用一个函数封装起来,让蜂鸣器一直响,以便观察
(3)找到fressrtos.c文件

void StartDefaultTask(void *argument)这是嵌入式实时操作系统(RTOS)中一个任务(Task)的入口函数,这里面调用LED让LED闪烁
同时创建一个相同的函数,在FreeRTOS初始化函数中同时调用,就可以得到LED和BEEP同时进行的测试程序
二、任务的创建与删除
1、xTaskCreate函数
xTaskCreate任务创建函数
BaseType_t xTaskCreate( TaskFunction_t pvTaskCode,const char * const pcName,const configSTACK_DEPTH_TYPE uxStackDepth,void *pvParameters,UBaseType_t uxPriority,TaskHandle_t *pxCreatedTask
)
功能:创建新的任务,并将任务加入到FreeRTOS的任务管理系统中,让调度器进行调度
下来我们来分析函数里面的参数:
1>pvTaskCode 任务函数指针,指向任务的函数
函数原型必须严格限定为vTaskFunction(void *pvParameters)
通常是无限循环的(for(;;) 或 while(1)),退出前需调用 vTaskDelete(NULL)
2>pcName 任务字符串名称,仅用于调试和追踪(如通过任务列表查看)
长度由 configMAX_TASK_NAME_LEN 宏定义(默认16个字符)
3>uxStackDepth 任务栈大小,单位:字(32位操作系统中1字 = 4字节)
4>pvParameters传递给任务函数的参数指针,若不需要设置可置NULL
注意:参数的生命周期需覆盖任务的生命周期
5>uxPriority任务优先级,数值越大优先级越高
范围:0 至configMAX_PRIORITIES - 1
空闲任务优先级为0,
| #define configMAX_PRIORITIES | (56) |
6>pxCreatedTask
输出参数,用于接收创建的任务句柄【句柄的本质是任务在内存中所开辟空间的地址】后续可通过该句柄操作任务(如挂起、删除等)
若不需要句柄,可设为NULL
返回值
pdPASS(值为 1):任务创建成功
errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY(值为 0):任务创建失败(通常是内存不足
特点:自动从堆中分配内存
2、osDelay (uint32_t ticks)函数
osDelay () 是 RTOS(实时操作系统)中的一个核心函数,用于将当前运行的任务延迟指定的时间。
ticks 是参数名称,代表 “时钟节拍数”(也叫滴答数)
osDelay(ticks) 的作用是:让当前正在执行的任务进入 “阻塞态”(Blocked State),并在等待 ticks 个系统时钟节拍后,重新变为 “就绪态”(Ready State)
-
什么是时钟节拍?系统时钟节拍是 RTOS 内部的一个周期性中断。你可以把它想象成一个 “心跳”。这个中断的频率(即每秒发生的次数)是在 RTOS 配置文件中设定的,通常是
100Hz(每 10ms 一次) 或1000Hz(每 1ms 一次)。
3、xTaskCreateStatic函数
TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode,const char * const pcName,const uint32_t ulStackDepth,void * const pvParameters,UBaseType_t uxPriority,StackType_t * const puxStackBuffer,StaticTask_t * const pxTaskBuffer
);
1>pvTaskCode
2>pcName
3>uxStackDepth
4>pvParameters
5>uxPriority
这之前的参数与之前的大同小异
6>puxStackBuffer
必须指向至少包含ulStackDepth个索引的StackType_t类型的数组,该数组将用作任务堆栈,因此必须持久存在,它指向一块由用户预先分配好的内存区域,这块区域将作为新任务的堆栈。
// 1. 为任务堆栈静态分配内存
// 假设 StackType_t 是 4 字节,ulStackDepth 是 128
// 那么这块内存的大小就是 128 * 4 = 512 字节
#define TASK_STACK_SIZE 128
StackType_t xTaskStack[TASK_STACK_SIZE]; // 2. 在创建任务时,将数组名(即数组首地址)传递给 puxStackBuffer
xTaskCreateStatic(vTaskFunction, // 任务函数"TaskName", // 任务名称TASK_STACK_SIZE, // 堆栈深度 (ulStackDepth)(void *)¶m, // 传递给任务的参数tskIDLE_PRIORITY + 1,// 任务优先级xTaskStack, // <-- puxStackBuffer: 指向预先分配的堆栈数组&xTaskTCB // <-- pxTaskBuffer: 指向预先分配的TCB变量
);
7>pxTaskBuffer
必须指向StaticTask_t类型的变量。该变量将用于保存新任务的数据结构体(TCB),因此必须持久存在,它指向一个由用户预先分配好的 StaticTask_t 类型的变量,这个变量将用于存储新任务的TCB。
// 1. 为任务TCB静态分配内存
StaticTask_t xTaskTCB; // 这是一个全局变量// 2. 在创建任务时,将这个变量的地址传递给 pxTaskBuffer
xTaskCreateStatic(vTaskFunction, // 任务函数"TaskName", // 任务名称TASK_STACK_SIZE, // 堆栈深度(void *)¶m, // 传递给任务的参数tskIDLE_PRIORITY + 1,// 任务优先级xTaskStack, // puxStackBuffer&xTaskTCB // <-- pxTaskBuffer: 指向预先分配的TCB变量
);
我们要明白任务的两个基本组成部分:
- 任务控制块 (Task Control Block, TCB):这是一个数据结构,RTOS 用它来存储关于任务的所有信息,比如任务的状态、优先级、堆栈指针、任务名称等。它相当于任务的 “身份证” 和 “档案”。
- 任务堆栈 (Task Stack):这是一块内存区域,用于存储任务执行时的局部变量、函数调用的返回地址以及 CPU 的寄存器值。当任务被切换出去时,它的上下文(CPU 寄存器状态)会被保存到自己的堆栈中;当它被切换回来时,上下文再从堆栈中恢复。
