1. LED闪烁
任务目标
用同一颗LED灯实现1Hz闪烁(亮500ms、灭500ms),分别以裸机主循环延时和RTOS任务延时两种方式编写,对比两者在代码组织、CPU占用和实时响应上的差异。本案例以STM32F407 + HAL库为硬件基础,RTOS选用FreeRTOS(CMSIS-OS v2封装)。
环境与依赖
- 硬件:STM32F407开发板,LED接PD12(或任意GPIO,需在代码中对应修改)
- 软件:STM32CubeIDE(或Keil MDK),STM32CubeF4固件包,FreeRTOS中间件(CubeMX勾选即可)
- 时钟:系统时钟168MHz,HAL库已初始化
裸机轮询实现
裸机方式使用主循环调用HAL_Delay()阻塞延时。代码结构为顺序执行,CPU在延时期间被占用,无法处理其他任务。
// main.c 裸机轮询版本(核心代码)
#include "main.h"
void LED_Blink_Polling(void)
{
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_SET); // LED亮
HAL_Delay(500); // 阻塞500ms
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_RESET); // LED灭
HAL_Delay(500); // 阻塞500ms
}
int main(void)
{
HAL_Init();
SystemClock_Config(); // 168MHz
MX_GPIO_Init(); // PD12配置为推挽输出
while (1)
{
LED_Blink_Polling();
}
}
RTOS任务实现
RTOS方式将LED闪烁封装为独立任务,使用osDelay()主动让出CPU。任务在延时期间进入阻塞态,调度器可运行其他就绪任务,实现并发。
// app_rtos.c RTOS任务版本(核心代码)
#include "cmsis_os.h"
void LED_Blink_Task(void *argument)
{
for (;;)
{
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_SET); // LED亮
osDelay(500); // 阻塞500ms,让出CPU
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_RESET); // LED灭
osDelay(500); // 阻塞500ms,让出CPU
}
}
// 在main.c中创建任务(CubeMX自动生成部分)
// osThreadId_t LEDTaskHandle;
// LEDTaskHandle = osThreadNew(LED_Blink_Task, NULL, &LEDTask_attributes);
代码结构对比
| 维度 | 裸机轮询 | RTOS任务 |
|---|---|---|
| 代码组织 | 主循环顺序执行,功能耦合在while(1)中 | 每个功能独立任务,结构清晰 |
| 延时方式 | HAL_Delay()阻塞CPU | osDelay()让出CPU,任务进入阻塞态 |
| CPU利用率 | 延时期间CPU空转 | 延时期间CPU可运行其他任务 |
| 实时响应 | 需等待当前延时结束 | 高优先级任务可抢占 |
| 扩展性 | 添加功能需修改主循环,耦合度高 | 添加功能只需新建任务 |
实时性差异说明
裸机方式中,若在HAL_Delay(500)期间发生外部中断(如按键),中断服务函数可立即执行,但主循环中的其他非中断逻辑必须等待延时结束才能运行。RTOS方式中,osDelay()使当前任务挂起,调度器立即切换到其他就绪任务;若存在更高优先级任务(如按键处理任务),其响应延迟仅取决于任务切换时间(通常微秒级),而非500ms延时。
运行与验证
- 裸机验证:编译烧录后,观察LED以1Hz频率闪烁(亮500ms、灭500ms)。用示波器或逻辑分析仪测量PD12引脚波形,高电平持续500ms±10ms,低电平持续500ms±10ms。
- RTOS验证:编译烧录后,同样观察LED闪烁频率。在调试器中暂停程序,查看任务列表,确认
LED_Blink_Task状态在Blocked(阻塞)和Running(运行)之间切换。 - 对比验证:在裸机版本主循环中添加一个空操作计数器(如
volatile uint32_t cnt++),在RTOS版本中创建同优先级空任务执行相同计数。运行10秒后比较两者计数值——RTOS版本中空任务计数应显著高于裸机版本(因为裸机CPU被延时占用,而RTOS空任务在延时期间获得CPU)。
通过标准:两种方式LED均以1Hz±10%频率闪烁;RTOS任务状态切换正常;对比实验中RTOS空任务计数值明显大于裸机版本。