FreeRTOS中的任务调度
背景介绍
FreeRTOS是一种轻量级的实时操作系统,被广泛应用于嵌入式系统中。它提供了多任务管理功能,包括任务创建、任务调度和任务切换。FreeRTOS的调度器根据任务的优先级和状态自动调度任务,确保系统资源的有效利用和实时性。
在M4处理器上,FreeRTOS能够实现任务间的自动调度。调度器采用基于优先级的抢占式调度算法,确保系统总是运行最高优先级且处于就绪状态的任务。如果有多个任务具有相同的优先级,调度器会采用时间片轮转的方法在这些任务之间切换。
主动调度
尽管FreeRTOS的调度器通常会自动管理任务的调度,但有时我们需要手动干预任务调度。这可以通过以下几种方式实现:
1. 任务切换
通过调用任务切换函数,可以强制调度器立即进行任务切换。
taskYIELD(); // 手动触发任务切换
2. 优先级调整
通过调整任务的优先级,可以影响调度器的行为,立即切换到新的最高优先级任务。
vTaskPrioritySet(xTaskHandle, uxNewPriority); // 改变任务优先级
3. 任务通知
通过任务通知机制,可以实现任务之间的同步和通信,从而影响调度器的行为。
xTaskNotifyGive(xTaskHandle); // 通知任务
4. 中断服务例程(ISR)中的调度
在中断服务例程中,可以通过设置上下文切换请求标志来强制任务调度。
portYIELD_FROM_ISR(xHigherPriorityTaskWoken); // 在ISR中触发任务调度
示例代码
以下是一些示例代码,展示如何通过上述方法主动调度任务。
任务切换
void vTask1(void *pvParameters) {
for(;;) {
// 任务代码
taskYIELD(); // 主动触发任务切换
}
}
void vTask2(void *pvParameters) {
for(;;) {
// 任务代码
}
}
优先级调整
void vTask1(void *pvParameters) {
for(;;) {
// 任务代码
vTaskPrioritySet(NULL, uxNewPriority); // 改变自身优先级
}
}
void vTask2(void *pvParameters) {
for(;;) {
// 任务代码
}
}
任务通知
void vTask1(void *pvParameters) {
for(;;) {
// 等待通知
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
// 被通知后继续执行
}
}
void vTask2(void *pvParameters) {
for(;;) {
// 任务代码
xTaskNotifyGive(xTask1Handle); // 通知任务1
}
}
中断服务例程中的调度
void vISRHandler(void) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
// 处理中断
// ...
// 触发任务调度
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
优先级说明
在FreeRTOS中,优先级的值越大,优先级越高。FreeRTOS使用整数值来表示任务的优先级,值越大表示优先级越高。任务的优先级决定了调度器选择哪个任务来运行。当有多个任务处于就绪状态时,调度器会选择优先级最高的任务来运行。
示例说明
例如,如果你创建了三个任务,并设置它们的优先级如下:
- 任务A:优先级为1
- 任务B:优先级为2
- 任务C:优先级为3
在这种情况下,任务C的优先级最高,因此调度器会首先运行任务C。如果任务C阻塞或进入等待状态,调度器会选择下一个优先级最高的任务,即任务B来运行。
创建任务时设置优先级
在创建任务时,你可以通过uxPriority参数来设置任务的优先级。以下是一个示例代码:
#include "FreeRTOS.h"
#include "task.h"
void vTaskA(void *pvParameters) {
for(;;) {
// 任务A的代码
}
}
void vTaskB(void *pvParameters) {
for(;;) {
// 任务B的代码
}
}
void vTaskC(void *pvParameters) {
for(;;) {
// 任务C的代码
}
}
int main(void) {
// 创建任务A,优先级为1
xTaskCreate(vTaskA, "Task A", 1000, NULL, 1, NULL);
// 创建任务B,优先级为2
xTaskCreate(vTaskB, "Task B", 1000, NULL, 2, NULL);
// 创建任务C,优先级为3
xTaskCreate(vTaskC, "Task C", 1000, NULL, 3, NULL);
// 启动调度器
vTaskStartScheduler();
// 由于调度器已经启动,通常不会运行到这里
for(;;);
}