FreeRTOS_时间片调度

犀利的毛毛虫 发布于 2025-03-09 258 次阅读


时间片调度简介(熟悉)

在FreeRTOS中,同等优先级的任务会轮流分享相同的CPU时间,这个时间被称为时间片。在这里,一个时间片的长度等同于SysTick中断的周期。

时间片调度实验演示(掌握)实验目标

理解FreeRTOS的时间片调度:

  • start_task:用来创建其他的2个任务。
  • task1:通过串口打印task1的运行次数,设置任务优先级为2。
  • task2:通过串口打印task2的运行次数,设置任务优先级为2。

为了更好观察现象,滴答定时器的中断频率设置为50ms中断一次(一个时间片)。

  • FreeRTOSConfig.h代码清单
#define configUSE_TIME_SLICING                          1
#define configUSE_PREEMPTION                            1
#define configTICK_RATE_HZ          ( ( TickType_t ) 20 )
  • freertos_demo.c代码清单任务配置
#include "freertos_demo.h"
/* freertos相关的头文件,必须的 */
#include "FreeRTOS.h"
#include "task.h"
/* 需要用到的其他头文件 */
#include "LED.h"
#include "Key.h"

/* 启动任务的配置 */
#define START_TASK_STACK 128
#define START_TASK_PRIORITY 1
TaskHandle_t start_task_handle;
void start_task(void *pvParameters);

/* 任务1的配置 */
#define TASK1_STACK 128
#define TASK1_PRIORITY 2
TaskHandle_t task1_handle;
void task1(void *pvParameters);

/* 任务2的配置 */
#define TASK2_STACK 128
#define TASK2_PRIORITY 2
TaskHandle_t task2_handle;
void task2(void *pvParameters);

/**
 * @description: 启动FreeRTOS
 * @return {*}
 */
void freertos_start(void)
{
    /* 1.创建一个启动任务 */
    xTaskCreate((TaskFunction_t)start_task,               // 任务函数的地址
                (char *)"start_task",                     // 任务名字符串
                (configSTACK_DEPTH_TYPE)START_TASK_STACK, // 任务栈大小,默认最小128,单位4字节
                (void *)NULL,                             // 传递给任务的参数
                (UBaseType_t)START_TASK_PRIORITY,         // 任务的优先级
                (TaskHandle_t *)&start_task_handle);      // 任务句柄的地址

    /* 2.启动调度器:会自动创建空闲任务 */
    vTaskStartScheduler();
}

/**
 * @description: 启动任务:用来创建其他Task
 * @param {void} *pvParameters
 * @return {*}
 */
void start_task(void *pvParameters)
{
    /* 进入临界区:保护临界区里的代码不会被打断 */
    taskENTER_CRITICAL();

    /* 创建3个任务 */
    xTaskCreate((TaskFunction_t)task1,
                (char *)"task1",
                (configSTACK_DEPTH_TYPE)TASK1_STACK,
                (void *)NULL,
                (UBaseType_t)TASK1_PRIORITY,
                (TaskHandle_t *)&task1_handle);
    xTaskCreate((TaskFunction_t)task2,
                (char *)"task2",
                (configSTACK_DEPTH_TYPE)TASK2_STACK,
                (void *)NULL,
                (UBaseType_t)TASK2_PRIORITY,
                (TaskHandle_t *)&task2_handle);

    /* 启动任务只需要执行一次即可,用完就删除自己 */
    vTaskDelete(NULL);

    /* 退出临界区 */
    taskEXIT_CRITICAL();
}

/**
 * @description: 任务一:实现LED1每500ms闪烁一次
 * @param {void} *pvParameters
 * @return {*}
 */
void task1(void *pvParameters)
{
    uint16_t task1_count = 0;
    while (1)
    {
        taskENTER_CRITICAL();
        printf("task1运行[%d]次...\r\n", ++task1_count);
        // vTaskDelay(500); //为了观察时间片调度,不使用freertos的延时函数
        HAL_Delay(10); // 使用该延时的前提:HAL时钟修改成其他定时器,并且中断优先级较高
        taskEXIT_CRITICAL();
    }
}

/**
 * @description: 任务二:实现LED2每500ms闪烁一次
 * @param {void} *pvParameters
 * @return {*}
 */
void task2(void *pvParameters)
{
    uint16_t task2_count = 0;
    while (1)
    {
        taskENTER_CRITICAL();
        printf("task2运行[%d]次...\r\n", ++task2_count);
        // vTaskDelay(500); //为了观察时间片调度,不使用freertos的延时函数
        HAL_Delay(10); // 使用该延时的前提:HAL时钟修改成其他定时器,并且中断优先级较高
        taskEXIT_CRITICAL();
    }
}