3. 时间片轮转调度
任务定义
在RTOS中,当多个任务具有相同优先级时,需要一种机制让它们公平共享CPU。本案例基于FreeRTOS,创建两个同优先级任务,通过配置时间片轮转调度(Round-Robin),使两个任务按固定时间片交替执行。最终通过串口输出的任务执行序列,验证时间片轮转是否生效。
实现原理
FreeRTOS的调度器在以下两个条件同时满足时启用时间片轮转:① 宏configUSE_TIME_SLICING定义为1;② 多个任务处于同一优先级且均为就绪态。此时,每个任务运行一个时间片(由configTICK_RATE_HZ决定,默认1ms)后,调度器强制切换到同优先级的另一个就绪任务。若只有一个同优先级任务就绪,则时间片轮转不产生实际切换。
代码实现
// main.c
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
// 串口发送字符串(硬件相关,需根据平台实现)
extern void UART_SendString(const char *str);
// 两个同优先级任务:打印任务名后延时
void vTaskA(void *pvParameters) {
for (;;) {
UART_SendString("A\r\n");
vTaskDelay(2); // 主动让出CPU,但时间片轮转仍会生效
}
}
void vTaskB(void *pvParameters) {
for (;;) {
UART_SendString("B\r\n");
vTaskDelay(2);
}
}
int main(void) {
// 硬件初始化(时钟、UART等,略)
// 创建两个同优先级任务(优先级均为1)
xTaskCreate(vTaskA, "TaskA", 128, NULL, 1, NULL);
xTaskCreate(vTaskB, "TaskB", 128, NULL, 1, NULL);
// 启动调度器
vTaskStartScheduler();
// 正常不会执行到这里
for (;;);
return 0;
}
FreeRTOSConfig.h关键配置:
#define configUSE_PREEMPTION 1 // 抢占式调度
#define configUSE_TIME_SLICING 1 // 启用时间片轮转
#define configTICK_RATE_HZ 1000 // 时钟节拍1kHz,时间片=1ms
#define configMAX_PRIORITIES 5
时间片轮转执行时序
落地与验证
运行方式:将代码编译后烧录至目标板(如STM32F407),打开串口调试助手,波特率与UART_SendString实现一致(通常115200)。
观察现象:串口持续交替输出A和B,且输出序列呈现周期性交替,例如:
A
B
A
B
A
B
...
判定标准:
- 若串口输出为连续的
A或B(长时间无交替),说明时间片轮转未生效——检查configUSE_TIME_SLICING是否为1,以及两个任务优先级是否确实相同。 - 若输出呈现
A、B交替,但间隔不规律,可能原因是任务中vTaskDelay(2)导致任务主动阻塞,掩盖了时间片切换。可去掉vTaskDelay,改为空循环(如for(;;);),此时时间片轮转效果更明显——两个任务会严格按1ms时间片交替。 - 若将其中一个任务优先级改为2(高于另一个),则高优先级任务独占CPU,串口只输出高优先级任务内容,这反向验证了同优先级是时间片轮转的前提。
验证要点:本案例核心是验证configUSE_TIME_SLICING=1时,同优先级任务按时间片自动切换。若需更精确观测,可在任务切换点翻转GPIO并用逻辑分析仪测量,但串口输出已足以定性判断轮转是否生效。