1. 创建第一个RTOS任务
任务目标
在STM32裸机工程基础上移植FreeRTOS,创建两个任务分别控制板载LED以不同频率交替闪烁,通过实际运行观察任务调度与延时效果。
硬件与工程准备
- 硬件:STM32F103C8T6最小系统板(板载LED接PC13),ST-Link调试器
- 软件:STM32CubeIDE(或Keil MDK)+ STM32CubeMX
- CubeMX配置:开启PC13为GPIO输出;RCC选择外部晶振;SYS选择Serial Wire调试;在Middleware中选择FreeRTOS(CMSIS_V1)
核心代码实现
在CubeMX生成的main.c中,找到MX_FREERTOS_Init函数,将默认生成的defaultTask替换为以下两个任务:
/* main.c 中 MX_FREERTOS_Init 函数内 */
void MX_FREERTOS_Init(void) {
/* 创建任务1:LED快速闪烁(200ms周期) */
osThreadDef(taskLED1, TaskLED1, osPriorityNormal, 0, 128);
task1Handle = osThreadCreate(osThread(taskLED1), NULL);
/* 创建任务2:LED慢速闪烁(800ms周期) */
osThreadDef(taskLED2, TaskLED2, osPriorityNormal, 0, 128);
task2Handle = osThreadCreate(osThread(taskLED2), NULL);
}
/* 任务1回调函数:每200ms翻转一次LED */
void TaskLED1(void const *argument) {
for (;;) {
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
osDelay(100); // 100ms延时,翻转间隔200ms
}
}
/* 任务2回调函数:每800ms翻转一次LED */
void TaskLED2(void const *argument) {
for (;;) {
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
osDelay(400); // 400ms延时,翻转间隔800ms
}
}
在main.h中添加任务函数声明与任务句柄全局变量:
/* main.h */
extern osThreadId task1Handle;
extern osThreadId task2Handle;
void TaskLED1(void const *argument);
void TaskLED2(void const *argument);
在main.c文件顶部(用户代码区)定义全局句柄:
/* 用户代码区1 */
osThreadId task1Handle;
osThreadId task2Handle;
编译与烧录
- 在CubeIDE中点击Build按钮编译工程,确认无错误
- 连接ST-Link,点击Run烧录并启动调试
- 程序自动开始运行,无需额外操作
验证方法
观察板载LED闪烁节奏:
- 通过标准:LED呈现两种闪烁频率叠加的效果——快速闪烁(约5Hz)与慢速闪烁(约1.25Hz)同时存在,视觉上表现为不规则的亮灭节奏
- 若LED仅以单一频率闪烁,说明两个任务未正确交替运行,检查任务优先级或延时配置
- 若LED完全不亮,检查GPIO配置或任务是否进入死循环
关键说明
- 两个任务优先级相同(
osPriorityNormal),FreeRTOS使用时间片轮转调度,两个任务交替获得CPU执行权 osDelay使当前任务进入阻塞态,释放CPU给另一个任务,这是RTOS多任务能够“同时”运行的基础- 任务栈大小设为128字(512字节),足够本次简单任务使用;若任务中增加局部数组或调用较深函数,需相应增大
- LED引脚同时被两个任务操作,最终亮灭状态由最近一次执行的翻转决定,因此视觉上呈现两种频率叠加效果