2. 多任务并发执行
任务目标
在RTOS中创建两个独立任务,分别控制两个LED以不同频率闪烁(LED1为1Hz,LED2为2Hz),通过实际运行观察两个任务交替占用CPU,理解RTOS的抢占式调度与并发执行机制。
硬件与依赖
- 开发板:STM32F407(含两个板载LED,分别接PD12、PD13)
- RTOS:FreeRTOS V10.4.6(已移植至工程)
- 编译器:arm-none-eabi-gcc 或 Keil MDK
核心代码
/* main.c - FreeRTOS双LED闪烁示例 */
#include "FreeRTOS.h"
#include "task.h"
#include "stm32f4xx_hal.h"
/* 任务函数声明 */
void vLED1Task(void *pvParameters);
void vLED2Task(void *pvParameters);
/* 任务句柄(可选,用于调试/删除) */
TaskHandle_t xLED1TaskHandle = NULL;
TaskHandle_t xLED2TaskHandle = NULL;
int main(void)
{
HAL_Init();
__HAL_RCC_GPIOD_CLK_ENABLE();
/* 配置PD12、PD13为推挽输出 */
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_12 | GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
/* 初始状态:两个LED均熄灭 */
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12 | GPIO_PIN_13, GPIO_PIN_RESET);
/* 创建两个任务,优先级相同(抢占式调度) */
xTaskCreate(vLED1Task, "LED1", 128, NULL, 1, &xLED1TaskHandle);
xTaskCreate(vLED2Task, "LED2", 128, NULL, 1, &xLED2TaskHandle);
/* 启动调度器 */
vTaskStartScheduler();
/* 正常不会执行到这里 */
while (1) {}
}
/* LED1任务:1Hz闪烁(500ms翻转一次) */
void vLED1Task(void *pvParameters)
{
(void)pvParameters;
for (;;)
{
HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_12);
vTaskDelay(pdMS_TO_TICKS(500)); /* 延时500ms */
}
}
/* LED2任务:2Hz闪烁(250ms翻转一次) */
void vLED2Task(void *pvParameters)
{
(void)pvParameters;
for (;;)
{
HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_13);
vTaskDelay(pdMS_TO_TICKS(250)); /* 延时250ms */
}
}
运行与验证
- 将上述代码加入已有FreeRTOS工程(需包含HAL驱动库和FreeRTOS内核源文件)。
- 编译并烧录至STM32F407开发板。
- 观察两个LED的闪烁行为:
| LED | 引脚 | 预期闪烁频率 | 翻转周期 |
|---|---|---|---|
| LED1 | PD12 | 1Hz(亮0.5s,灭0.5s) | 500ms |
| LED2 | PD13 | 2Hz(亮0.25s,灭0.25s) | 250ms |
通过判定标准:两个LED同时独立闪烁,且频率符合上表。若用示波器测量PD12和PD13引脚,可见两路方波频率分别为1Hz和2Hz,相位无固定关系——这证明两个任务在RTOS调度下并发执行,而非顺序轮流完成整个循环。
关键说明
- 两个任务优先级相同(均为1),FreeRTOS使用时间片轮转调度,每个任务运行一个时间片(默认1ms)后切换,宏观上呈现“同时运行”效果。
vTaskDelay()使任务主动释放CPU进入阻塞态,调度器在延时结束后将任务移回就绪态。这是RTOS任务间共享CPU的基本机制。- 若将两个任务优先级设为不同值(如LED1为2、LED2为1),高优先级任务将抢占低优先级任务,LED2只有在LED1阻塞时才能运行——可自行修改优先级对比观察调度差异。