2. 多任务并发执行
任务目标
在STM32F407开发板上基于FreeRTOS创建两个独立任务:一个任务以500ms周期翻转LED,另一个任务以200ms周期翻转蜂鸣器。通过观察两个任务互不阻塞地交替运行,理解RTOS时间片轮转调度与任务并发执行的基本概念。
硬件连接
- LED:连接至GPIOB Pin0(低电平点亮)
- 蜂鸣器:连接至GPIOB Pin1(高电平驱动)
完整代码
/* FreeRTOS + STM32F407 多任务并发示例 */
#include "FreeRTOS.h"
#include "task.h"
#include "stm32f4xx.h"
/* 任务函数声明 */
void vLEDTask(void *pvParameters);
void vBuzzerTask(void *pvParameters);
/* GPIO初始化 */
static void GPIO_Init(void)
{
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN;
/* PB0-LED, PB1-Buzzer 推挽输出 */
GPIOB->MODER |= (GPIO_MODER_MODER0_0 | GPIO_MODER_MODER1_0);
GPIOB->OTYPER &= ~(GPIO_OTYPER_OT_0 | GPIO_OTYPER_OT_1);
GPIOB->OSPEEDR |= (GPIO_OSPEEDER_OSPEEDR0 | GPIO_OSPEEDER_OSPEEDR1);
GPIOB->PUPDR &= ~(GPIO_PUPDR_PUPDR0 | GPIO_PUPDR_PUPDR1);
/* 初始状态:LED灭,蜂鸣器关 */
GPIOB->BSRR = GPIO_BSRR_BS0 | GPIO_BSRR_BS1;
}
/* LED任务:500ms翻转 */
void vLEDTask(void *pvParameters)
{
(void)pvParameters;
for (;;) {
GPIOB->ODR ^= GPIO_ODR_OD0; /* 翻转PB0 */
vTaskDelay(pdMS_TO_TICKS(500)); /* 延时500ms */
}
}
/* 蜂鸣器任务:200ms翻转 */
void vBuzzerTask(void *pvParameters)
{
(void)pvParameters;
for (;;) {
GPIOB->ODR ^= GPIO_ODR_OD1; /* 翻转PB1 */
vTaskDelay(pdMS_TO_TICKS(200)); /* 延时200ms */
}
}
int main(void)
{
GPIO_Init();
/* 创建两个独立任务,优先级相同 */
xTaskCreate(vLEDTask, "LED", 128, NULL, 1, NULL);
xTaskCreate(vBuzzerTask, "Buzzer", 128, NULL, 1, NULL);
/* 启动调度器 */
vTaskStartScheduler();
/* 正常不会执行到这里 */
for (;;);
}
工程配置说明
- 需在工程中包含FreeRTOS内核源码(tasks.c、list.c、queue.c、port.c等)
- FreeRTOSConfig.h中配置:
configUSE_PREEMPTION为1,configTICK_RATE_HZ为1000 - 系统时钟配置为168MHz(使用标准库或HAL初始化均可)
运行与验证
- 编译并下载程序到开发板
- 观察现象:LED以约0.5秒间隔闪烁,蜂鸣器以约0.2秒间隔鸣响
- 两个任务独立运行,互不阻塞——LED闪烁频率不受蜂鸣器影响,反之亦然
通过判定标准:LED闪烁周期约为500ms(亮250ms/灭250ms),蜂鸣器鸣响周期约为200ms(响100ms/停100ms),且两者节奏各自保持稳定,说明FreeRTOS调度器正确实现了两个任务的时间片轮转并发执行。
关键机制说明
两个任务优先级相同(均为1),FreeRTOS采用时间片轮转调度:每个tick(1ms)检查一次就绪任务,两个任务通过vTaskDelay主动让出CPU,在延时期间任务进入阻塞态,调度器运行另一个就绪任务。由于延时时间不同(500ms vs 200ms),两个任务以各自独立的节奏交替获得CPU执行权,宏观上表现为“并发”运行。
上图展示了两个任务在1秒时间窗内的执行时序:LED任务每500ms切换一次状态(运行250ms后阻塞),蜂鸣器任务每200ms切换一次状态。由于延时时间不同,两个任务以各自独立的节拍运行,互不干扰,体现了RTOS多任务并发调度的核心特性。