RTOS系统 -- FreeRTOS之任务调度

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(;;);
}

上一篇:Revit 2025:建筑设计师的得力助手


下一篇:物联网数据解析实战:掌握CJSON库核心函数,精准处理JSON数据