Skip to content

由 WangChong 贡献,Ai-Thinker 进行整理

FreeRTOS入门-01- 创建任务以及调度任务 -基于AI-m61-32s-kit

移植

操作步骤

1
AI-m61的sdk内已经集成了FreeRTOS组件,当你从零创建一个项目的时候,只需要在本地项目的**proj.con

AI-m61的sdk内已经集成了FreeRTOS组件,当你从零创建一个项目的时候,只需要在本地项目的proj.conf 中启用FreeRTOS库

set(CONFIG_FREERTOS             1)
2
你还需要拷贝FreeRTOSConfig.h到你的项目文件夹下(不是必须)

你还需要拷贝FreeRTOSConfig.h到你的项目文件夹下(不是必须)

3
在程序中引入 FreeRTOS.h

在程序中引入 FreeRTOS.h

4
修改FreeRTOS.h的第59行,指向你的FreeRTOSConfig.h文件(绝对路径)

修改FreeRTOS.h的第59行,指向你的FreeRTOSConfig.h文件(绝对路径)

恭喜你!你已经成功的完成了小安派M61-32s-kit的FreeRtos配置


API介绍

在介绍API之前,简单的提一下OS, 只需要记住最重要的一句话就是OS是负责任务调度

首先介绍今天的第一个API

c
BaseType_t xTaskCreate(
    TaskFunction_t pvTaskCode,
    const char * const pcName,
    configSTACK_DEPTH_TYPE usStackDepth,
    void *pvParameters,
    UBaseType_t uxPriority,
    TaskHandle_t *pxCreatedTask
);
pvTaskCode指向任务入口函数的指针(即 实现任务的函数名称,请参阅如下示例)。任务通常 以 无限循环的形式实现 ;实现任务的函数决不能试图返回 或退出。 但是,任务可以 自我删除 。
pcName任务的描述性名称。主要是为了方便 调试,但也可用于 获取任务句柄 。任务名称的最大长度由 FreeRTOSConfig.h 中的 configMAX_TASK_NAME_LEN 定义。
usStackDepth要 分配 用于 任务堆栈的 字数(不是字节)。例如,如果堆栈的宽度为 16 位,usStackDepth 为 100,则将分配 200 字节用作该任务的堆栈。 再举一例,如果堆栈的宽度为 32 位,usStackDepth 为 400,则将分配 1600 字节用作该任务的堆栈。堆栈深度与堆栈宽度的乘积不得超过 size_t 类型变量所能包含的最大值。请参阅常见问题: 堆栈应有多大?
pvParameters作为参数传递给创建的任务的一个值。如果 pvParameters 设置为变量的地址, 则在执行创建的任务时该变量必须仍然存在——因此 传递堆栈变量的地址是无效的。
uxPriority创建任务执行的 优先级 。包含 MPU 支持的系统可在特权(系统)模式下选择性地创建任务, 方法是在 uxPriority 中设置 portPRIVILEGE_BIT 位。 例如,要创建一个优先级为 2 的特权任务,可将 uxPriority 设置为 ( 2 \
pxCreatedTask用于将句柄传递至由 xTaskCreate() 函数创建的任务 。 pxCreatedTask 是可选的,可设置为 NULL。

上述的这个方法用于创建一个任务并且分配给FreeRtos进行调度,其中需要注意的是uxPriority参数,这个参数是任务的优先级,优先级越高,任务将可能最先被CPU调度,并不是优先级越高就一定会被第一个调度!。


创建Task

下面是一个调用示例:

c
void turnGreenLed()
{
    while (1)
    {
        bflb_gpio_set(gpio, GPIO_PIN_14);
        bflb_mtimer_delay_ms(1000);
        bflb_gpio_reset(gpio, GPIO_PIN_14);
        vTaskDelay(pdMS_TO_TICKS(1000));
        // 等待1秒
    }
}

在上述代码中,我创建了一个blink 绿色LED的任务,主要这个任务中是一个死循环即While(1)然后在循环体内使LED间隔1秒进行闪烁。

c
void turnRedLed()
{
    while (1)
    {
        bflb_gpio_set(gpio, GPIO_PIN_12);
        bflb_mtimer_delay_ms(1000);
        bflb_gpio_reset(gpio, GPIO_PIN_12);
        vTaskDelay(pdMS_TO_TICKS(1000));
        // 等待1秒
    }
}

void turnBlueLed()
{
    while (1)
    {
        bflb_gpio_set(gpio, GPIO_PIN_15);
        bflb_mtimer_delay_ms(1000);
        bflb_gpio_reset(gpio, GPIO_PIN_15);
        vTaskDelay(pdMS_TO_TICKS(1000));
        // 等待1秒
    }
}

上面我又创建了两个点亮蓝色LED和红色LED的方法。如果这里不使用OS进行调度,并且程序处于单线程的情况下,一旦其中某一个方法已经执行的话,程序使不可能执行到其他的位置的(因为是死循环)。

将任务交给RTOS,由RTOS进行调度

c
    xTaskCreate(turnRedLed,   // 任务函数
                "Task1",      // 任务名称,用于调试
                128,          // 任务栈大小(以字为单位)
                NULL,         // 传递给任务函数的参数
                1,            // 任务优先级,数值越高优先级越高
                NULL);        // 任务句柄,可以用于后续操作
    xTaskCreate(turnBlueLed,  // 任务函数
                "Task2",      // 任务名称,用于调试
                128,          // 任务栈大小(以字为单位)
                NULL,         // 传递给任务函数的参数
                2,            // 任务优先级,数值越高优先级越高
                NULL);        // 任务句柄,可以用于后续操作
    xTaskCreate(turnGreenLed, // 任务函数
                "Task3",      // 任务名称,用于调试
                128,          // 任务栈大小(以字为单位)
                NULL,         // 传递给任务函数的参数
                3,            // 任务优先级,数值越高优先级越高
                NULL);        // 任务句柄,可以用于后续操作

上述方法中,使用xTaskCreate 把任务交给了OS进行调度。


今天的第二个API

void vTaskStartScheduler( void );

  • 描述: 启动 RTOS 调度器。调用后,RTOS 内核可以控制在何时执行哪些任务。(由RTOS负责任务调度)

调用示例:

c
vTaskStartScheduler();

完整代码如下:

c
#include "bflb_mtimer.h"
#include "board.h"
#include "FreeRTOS.h"
#define DBG_TAG "MAIN"
#include "bflb_gpio.h"
#include "log.h"

struct bflb_device_s *gpio;

void turnRedLed()
{
    while (1)
    {
        bflb_gpio_set(gpio, GPIO_PIN_12);
        bflb_mtimer_delay_ms(1000);
        bflb_gpio_reset(gpio, GPIO_PIN_12);
        vTaskDelay(pdMS_TO_TICKS(1000));
        // 等待1秒
    }
}

void turnBlueLed()
{
    while (1)
    {
        bflb_gpio_set(gpio, GPIO_PIN_15);
        bflb_mtimer_delay_ms(1000);
        bflb_gpio_reset(gpio, GPIO_PIN_15);
        vTaskDelay(pdMS_TO_TICKS(1000));
        // 等待1秒
    }
}

void turnGreenLed()
{
    while (1)
    {
        bflb_gpio_set(gpio, GPIO_PIN_14);
        bflb_mtimer_delay_ms(1000);
        bflb_gpio_reset(gpio, GPIO_PIN_14);
        vTaskDelay(pdMS_TO_TICKS(1000));
        // 等待1秒
    }
}

int main(void)
{
    board_init();
    gpio = bflb_device_get_by_name("gpio");

    // Red
    bflb_gpio_init(gpio, GPIO_PIN_12, GPIO_OUTPUT | GPIO_PULLUP | GPIO_DRV_3);
    // Blue
    bflb_gpio_init(gpio, GPIO_PIN_15, GPIO_OUTPUT | GPIO_PULLUP | GPIO_DRV_3);
    // Green
    bflb_gpio_init(gpio, GPIO_PIN_14, GPIO_OUTPUT | GPIO_PULLUP | GPIO_DRV_3);

    xTaskCreate(turnRedLed,   // 任务函数
                "Task1",      // 任务名称,用于调试
                128,          // 任务栈大小(以字为单位)
                NULL,         // 传递给任务函数的参数
                1,            // 任务优先级,数值越高优先级越高
                NULL);        // 任务句柄,可以用于后续操作
    xTaskCreate(turnBlueLed,  // 任务函数
                "Task2",      // 任务名称,用于调试
                128,          // 任务栈大小(以字为单位)
                NULL,         // 传递给任务函数的参数
                2,            // 任务优先级,数值越高优先级越高
                NULL);        // 任务句柄,可以用于后续操作
    xTaskCreate(turnGreenLed, // 任务函数
                "Task3",      // 任务名称,用于调试
                128,          // 任务栈大小(以字为单位)
                NULL,         // 传递给任务函数的参数
                3,            // 任务优先级,数值越高优先级越高
                NULL);        // 任务句柄,可以用于后续操作

    // 启动调度器
    vTaskStartScheduler();

    while (1)
    {
    }
}

实验现象

RGBLED灯闪烁

  • 注意,千万不要在Task内使用非RTOS提供的延时函数,如果使用的话RTOS将可能出现调度错误。请使用**vTaskDelay(pdMS_TO_TICKS(1000))**替换

遇到问题?

如有其他问题,请到统一的提问与讨论区:Ai-Thinker Discussions

Released under the MIT License. Build Time 2026-09-11 14:52:23