FreeRTOS 从入门到精通--FreeRTOS 高级编程

[复制链接]
查看671 | 回复5 | 2023-9-27 16:20:22 | 显示全部楼层 |阅读模式

本帖最后由 CHENQIGUANG1998 于 2023-9-27 16:41 编辑

在 FreeRTOS 中,有许多高级特性和编程技巧,这些特性可以帮助您更好地管理系统资源,提高系统性能,并避免一些常见的编程错误。在本文中,我们将深入探讨以下几个主题:动态任务创建和删除、优先级继承和避免死锁、时间片轮转调度(Round-Robin Scheduling)、软件定时器(Software Timer)以及 FreeRTOS 的内存管理。

动态任务创建和删除

在 FreeRTOS 中,任务的创建和删除可以在运行时进行。这是一个强大的功能,因为它允许我们在系统运行时动态地调整任务的数量和优先级。

创建任务

要动态地创建一个任务,我们可以使用 xTaskCreate() 函数。这个函数的原型如下:

BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
                         const char * const pcName,
                         const uint16_t usStackDepth,
                         void * const pvParameters,
                         UBaseType_t uxPriority,
                         TaskHandle_t * const pxCreatedTask );

删除任务

要删除一个任务,我们可以使用 vTaskDelete() 函数。这个函数的原型如下:

void vTaskDelete( TaskHandle_t xTaskToDelete );

优先级继承和避免死锁

在 FreeRTOS 中,有一种叫做优先级继承的机制,这种机制可以避免死锁的发生。当一个任务持有多个互斥量(mutex)时,如果另一个任务尝试获取这些互斥量,那么它的优先级将被提高到当前持有互斥量的任务的优先级。这就是优先级继承。

时间片轮转调度(Round-Robin Scheduling)

FreeRTOS 提供了时间片轮转调度(Round-Robin Scheduling)的功能。每个任务都被分配一个固定长度的时间片(time slice),在这个时间片内,任务可以执行。当时间片用完时,调度器会切换到下一个任务。这种调度策略可以防止一个任务长时间占用 CPU 时间,从而使得其他任务得不到执行。要实现这个功能,可以使用 configUSE_TIME_SLICING 宏。

软件定时器(Software Timer)

FreeRTOS 提供了软件定时器的功能。软件定时器可以在指定的时间间隔后触发一个回调函数。这对于需要定时触发某些操作的应用非常有用。要使用软件定时器,需要使用 xTimerCreate() 函数创建一个定时器,然后使用 xTimerStart() 函数启动它。当定时器到期时,会调用一个回调函数。这个回调函数的原型如下:

void vTimerCallbackFunction( TimerHandle_t xTimer );

FreeRTOS 的内存管理

FreeRTOS 提供了一套内存管理机制,可以帮助开发者更有效地管理系统内存。FreeRTOS 的内存管理基于分区(partition)的概念。内存被分成若干个分区,每个分区可以包含一个或多个块(block)。每个块的大小固定,而分区的大小可以动态调整。要使用 FreeRTOS 的内存管理功能,需要使用 pvPortMalloc() 和 vPortFree() 函数来分配和释放内存。

以下准备了一些代码示例:

动态任务创建和删除

在FreeRTOS中,可以在运行时动态地创建和删除任务。以下是一个示例代码,展示了如何动态地创建和删除任务:

// 包含FreeRTOS头文件
#include "FreeRTOS.h"
#include "task.h"

// 定义一个任务函数,该函数将在新创建的任务中执行
void vTaskFunction(void *pvParameters)
{
    // 任务代码
}

int main(void)
{
    // 创建一个任务句柄变量
    TaskHandle_t xCreatedTask;

    // 创建一个任务,并将其句柄存储在xCreatedTask中
    if (xTaskCreate(vTaskFunction, "TaskName", configMINIMAL_STACK_SIZE, NULL, tkIDLE_PRIORITY, &xCreatedTask) == pdPASS)
    {
        // 任务创建成功,可以启动任务调度器
        vTaskStartScheduler();
    }
    else
    {
        // 任务创建失败,处理错误
    }

    // 删除任务
    vTaskDelete(xCreatedTask);

    return 0;
}

优先级继承和避免死锁

FreeRTOS提供了优先级继承机制来避免死锁。以下是一个示例代码,展示了如何使用优先级继承来避免死锁:

// 包含FreeRTOS头文件
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"

// 定义一个任务函数,该函数将在新创建的任务中执行
void vTaskFunction1(void *pvParameters)
{
    // 任务代码
}

void vTaskFunction2(void *pvParameters)
{
    // 任务代码
}

int main(void)
{
    // 创建两个任务句柄变量
    TaskHandle_t xTask1, xTask2;

    // 创建一个互斥量句柄变量
    SemaphoreHandle_t xMutex;

    // 创建两个任务
    xTaskCreate(vTaskFunction1, "Task1", configMINIMAL_STACK_SIZE, NULL, tkIDLE_PRIORITY, &xTask1);
    xTaskCreate(vTaskFunction2, "Task2", configMINIMAL_STACK_SIZE, NULL, tkIDLE_PRIORITY, &xTask2);

    // 创建一个互斥量,用于保护共享资源
    xMutex = xSemaphoreCreateMutex();

    // 在任务1中使用互斥量访问共享资源
    xSemaphoreTake(xMutex, portMAX_DELAY); // 获取互斥量,如果获取成功则继续执行,否则阻塞当前任务直到获取成功或超时
    // 访问共享资源的代码
    xSemaphoreGive(xMutex); // 释放互斥量,允许其他任务获取互斥量访问共享资源
}

时间片轮转调度

FreeRTOS 提供了时间片轮转调度(Round-Robin Scheduling)的机制,用于均衡地分配 CPU 时间给各个任务。以下是一个示例代码,展示了如何使用时间片轮转调度:

// 包含FreeRTOS头文件
#include "FreeRTOS.h"
#include "task.h"

// 定义两个任务函数,分别在不同的时间片内执行
void vTaskFunction1(void *pvParameters)
{
    // 任务代码
    for( ;; )
    {
        // 在这里执行任务1的代码
        // ...
    }
}

void vTaskFunction2(void *pvParameters)
{
    // 任务代码
    for( ;; )
    {
        // 在这里执行任务2的代码
        // ...
    }
}

int main(void)
{
    // 创建两个任务句柄变量
    TaskHandle_t xTask1, xTask2;

    // 创建两个任务,并指定时间片长度
    xTaskCreate(vTaskFunction1, "Task1", configMINIMAL_STACK_SIZE, NULL, tkHIGHEST_PRIORITY, &xTask1);
    xTaskCreate(vTaskFunction2, "Task2", configMINIMAL_STACK_SIZE, NULL, tkHIGHEST_PRIORITY - 1, &xTask2);

    // 设置时间片轮转调度器的时间片长度
    vTaskSetTimeOutState(&xTimeOutState);
    xTimeOutState.pxTaskToSwitchTo = &xTask2; // 切换到任务2的时间片结束时,将切换回任务1的时间片
    xTimeOutState.ulTimeOutDelta = pdMS_TO_TICKS(5000); // 设置时间片长度为 5 秒

    // 启动时间片轮转调度器
    vTaskStartScheduler();

    return 0;
}

软件定时器

FreeRTOS 提供了软件定时器的功能,可以在指定的时间间隔后触发一个回调函数。以下是一个示例代码,展示了如何使用软件定时器:

// 包含FreeRTOS头文件
#include "FreeRTOS.h"
#include "timer.h"
#include "task.h"

// 定义一个定时器回调函数,该函数将在定时器到期时被调用
void vTimerCallbackFunction( TimerHandle_t xTimer )
{
    // 定时器回调函数的代码
    // ...
}

int main(void)
{
    // 创建定时器句柄变量
    TimerHandle_t xTimer;

    // 创建定时器,并指定回调函数、定时器时长和参数
    xTimer = xTimerCreate(NULL, pdMS_TO_TICKS(1000), pdFALSE, NULL, vTimerCallbackFunction);
    if (xTimer != NULL)
    {
        // 启动定时器
        xTimerStart(xTimer, portMAX_DELAY);
    }
    else
    {
        // 定时器创建失败,处理错误
    }

    // 其他代码...

    return 0;
}
回复

使用道具 举报

CHENQIGUANG1998 | 2023-9-27 16:34:30 | 显示全部楼层
沙发
回复

使用道具 举报

jkernet | 2023-9-27 21:14:04 | 显示全部楼层
vTaskDelete(NULL)和优雅安全的结束任务应该讲一讲
回复 支持 反对

使用道具 举报

WangChong | 2023-9-27 21:29:35 | 显示全部楼层
好文章学习了
回复 支持 反对

使用道具 举报

ifwz1729 | 2023-9-29 17:46:29 | 显示全部楼层
这都是啥!啥!
知足常乐
回复 支持 反对

使用道具 举报

bzhou830 | 2023-10-19 11:28:59 | 显示全部楼层
好文章学习了
选择去发光,而不是被照亮
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则