一、前言
在嵌入式开发中,当项目复杂度增加时,使用实时操作系统(RTOS)可以显著提高开发效率和系统可靠性。本教程将详细介绍如何在STM32平台上使用FreeRTOS(目前最流行的开源RTOS),并提供多任务LED控制和队列通信两个实战案例。
二、开发环境准备
1. 硬件准备
-
STM32开发板(以STM32F103C8T6最小系统板为例)
-
USB转TTL模块(用于串口通信)
-
LED和电阻若干
2. 软件准备
-
STM32CubeMX v6.9.2
-
Keil MDK-ARM v5.37
-
串口调试助手(推荐XCOM v2.6)
三、FreeRTOS基础配置
步骤1:创建CubeMX工程
-
打开CubeMX → 选择对应型号
-
配置时钟树(72MHz)
-
开启USART1(用于调试输出)
-
关键操作:在Middleware中选择FreeRTOS → Interface选择CMSIS_V1
步骤2:配置FreeRTOS参数
参数项 | 推荐值 | 说明 |
---|---|---|
TOTAL_HEAP_SIZE | 4096 | 堆空间根据任务数量调整 |
MAX_PRIORITIES | 7 | 优先级数量 |
USE_PREEMPTION | Enabled | 启用抢占式调度 |
四、实战案例1:多任务LED控制
1. 创建任务
// 在freertos.c中添加任务声明
osThreadId_t led1TaskHandle;
const osThreadAttr_t led1Task_attributes = {
.name = "led1Task",
.stack_size = 128 * 4,
.priority = (osPriority_t) osPriorityNormal,
};
void StartLed1Task(void *argument) {
for(;;) {
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_12);
osDelay(500); // 非阻塞延时
}
}
// 在main函数中创建任务
led1TaskHandle = osThreadNew(StartLed1Task, NULL, &led1Task_attributes);
2. 添加第二个LED任务
// 在MX_FREERTOS_Init函数中创建多个任务
void MX_FREERTOS_Init(void) {
osThreadNew(StartLed1Task, NULL, &led1Task_attributes);
osThreadNew(StartLed2Task, NULL, &led2Task_attributes);
}
3. 关键点解析
-
每个任务需要独立的堆栈空间
-
使用
osDelay()
代替HAL_Delay实现非阻塞延时 -
默认采用时间片轮转调度
五、实战案例2:任务间通信(队列)
1. 创建消息队列
// 定义队列(最大10个元素,每个元素sizeof(int))
osMessageQueueId_t msgQueue;
msgQueue = osMessageQueueNew(10, sizeof(int), NULL);
2. 生产者任务
void ProducerTask(void *arg) {
int count = 0;
while(1) {
osMessageQueuePut(msgQueue, &count, 0, osWaitForever);
count++;
osDelay(1000);
}
}
3. 消费者任务
void ConsumerTask(void *arg) {
int received;
while(1) {
if(osMessageQueueGet(msgQueue, &received, NULL, 100) == osOK) {
printf("Received: %d\r\n", received);
}
}
}
4. 运行效果
Received: 0
Received: 1
Received: 2
...
六、高级应用技巧
1. 优先级配置建议
任务类型 | 推荐优先级 |
---|---|
紧急事件处理 | osPriorityHigh |
用户界面 | osPriorityLow |
数据采集 | osPriorityNormal |
2. 内存优化技巧
-
使用
uxTaskGetStackHighWaterMark()
监控堆栈使用 -
合理设置
configMINIMAL_STACK_SIZE
-
启用
configUSE_MALLOC_FAILED_HOOK
3. 常见问题排查
-
HardFault_Handler:检查堆栈溢出
-
任务无法调度:确认已调用
osKernelStart()
-
队列满错误:增大队列长度或优化处理速度
七、总结
通过本教程,我们掌握了:
✅ FreeRTOS在STM32上的基本配置
✅ 多任务创建与管理
✅ 使用队列实现任务通信
建议在实际项目中根据需求选择合适的内核对象(信号量、事件标志组等)。