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 */
    }
}

运行与验证

  1. 将上述代码加入已有FreeRTOS工程(需包含HAL驱动库和FreeRTOS内核源文件)。
  2. 编译并烧录至STM32F407开发板。
  3. 观察两个LED的闪烁行为:
LED引脚预期闪烁频率翻转周期
LED1PD121Hz(亮0.5s,灭0.5s)500ms
LED2PD132Hz(亮0.25s,灭0.25s)250ms

通过判定标准:两个LED同时独立闪烁,且频率符合上表。若用示波器测量PD12和PD13引脚,可见两路方波频率分别为1Hz和2Hz,相位无固定关系——这证明两个任务在RTOS调度下并发执行,而非顺序轮流完成整个循环。

关键说明

  • 两个任务优先级相同(均为1),FreeRTOS使用时间片轮转调度,每个任务运行一个时间片(默认1ms)后切换,宏观上呈现“同时运行”效果。
  • vTaskDelay()使任务主动释放CPU进入阻塞态,调度器在延时结束后将任务移回就绪态。这是RTOS任务间共享CPU的基本机制。
  • 若将两个任务优先级设为不同值(如LED1为2、LED2为1),高优先级任务将抢占低优先级任务,LED2只有在LED1阻塞时才能运行——可自行修改优先级对比观察调度差异。