3. 任务优先级实验

任务目标

创建两个不同优先级的RTOS任务,通过串口输出观察高优先级任务抢占低优先级任务的行为,理解基于优先级的抢占式调度机制。

环境依赖

本实验基于FreeRTOS(版本≥10.0),硬件平台为STM32F407开发板(或任意支持FreeRTOS的Cortex-M内核MCU)。需要准备:

  • STM32CubeIDE或Keil MDK开发环境
  • FreeRTOS内核源码(已移植到目标平台)
  • 串口调试助手(115200-8-N-1)

核心实现

创建两个任务:高优先级任务(优先级2)和低优先级任务(优先级1)。低优先级任务持续打印字符L,高优先级任务周期性打印字符H并短暂延时。由于高优先级任务就绪时会立即抢占低优先级任务,串口输出中H会周期性打断L的连续输出。

#include "FreeRTOS.h"
#include "task.h"
#include "uart.h"  // 平台串口驱动,提供 UART_SendString()

// 任务函数声明
void vLowPriorityTask(void *pvParameters);
void vHighPriorityTask(void *pvParameters);

// 任务句柄
TaskHandle_t xLowTaskHandle = NULL;
TaskHandle_t xHighTaskHandle = NULL;

// 低优先级任务:持续打印 'L'
void vLowPriorityTask(void *pvParameters)
{
    (void)pvParameters;
    for (;;)
    {
        UART_SendString("L");
    }
}

// 高优先级任务:周期性打印 'H' 并延时
void vHighPriorityTask(void *pvParameters)
{
    (void)pvParameters;
    const TickType_t xDelay = pdMS_TO_TICKS(200);
    for (;;)
    {
        UART_SendString("H");
        vTaskDelay(xDelay);  // 阻塞自身,让低优先级任务运行
    }
}

// 主函数(在 main.c 中调用)
int main(void)
{
    // 硬件初始化(时钟、GPIO、UART等)——由平台BSP提供
    BSP_Init();

    // 创建低优先级任务(优先级1)
    xTaskCreate(vLowPriorityTask, "Low", 128, NULL, 1, &xLowTaskHandle);

    // 创建高优先级任务(优先级2)
    xTaskCreate(vHighPriorityTask, "High", 128, NULL, 2, &xHighTaskHandle);

    // 启动调度器
    vTaskStartScheduler();

    // 正常情况下不会执行到这里
    for (;;);
}

运行与验证

  1. 将上述代码中的UART_SendString()和BSP_Init()替换为你的平台实际驱动函数。
  2. 编译并烧录到开发板,打开串口调试助手。
  3. 预期输出模式:串口持续输出大量L,但每隔约200ms会插入一个H,形成类似LLLLHLLLLLHLLLLL...的序列。
  4. 判定通过标准:
  • 输出中H的出现间隔约为200ms(与vTaskDelay设定一致);
  • 在H出现之前,L连续输出无中断——证明低优先级任务在无高优先级任务就绪时独占CPU;
  • 每次H输出后,L立即恢复输出——证明高优先级任务延时阻塞后,低优先级任务自动恢复运行。

调度机制说明

FreeRTOS采用优先级抢占式调度:

  • 当高优先级任务进入就绪态(如延时结束),内核立即暂停当前运行的低优先级任务,切换到高优先级任务;
  • 高优先级任务调用vTaskDelay()后进入阻塞态,此时低优先级任务成为最高优先级就绪任务,恢复运行;
  • 两个任务共享CPU时间,但高优先级任务总能“插队”——这正是抢占式调度的核心特征。

常见问题

  • 串口只输出L或只输出H:检查任务优先级是否设置正确(高优先级数值必须大于低优先级);确认vTaskDelay延时是否生效。
  • 输出乱码:检查串口波特率与UART_SendString实现是否匹配。
  • 系统卡死无输出:确认堆栈大小(128字)是否足够,可增大至256;检查vTaskStartScheduler前是否已完成必要外设初始化。