LOADING...

加载过慢请开启缓存(浏览器默认开启)

loading

ESP-IDF与freeRTOS(二) 队列

ESP-IDF与freeRTOS(二) 队列

书接上回

队列传递数据

RTOS队列需要添加头文件freertos/queue.h

常用函数:

//Creates a new queue and returns a handle by which the queue can be referenced.
//创建队列
QueueHandle_t xQueueCreate( UBaseType_t uxQueueLength,UBaseType_t uxItemSize );

//创建队列集合
QueueSetHandle_t xQueueCreateSet( const UBaseType_t uxEventQueueLength );

//创建静态队列
QueueHandle_t xQueueCreateStatic(UBaseType_t uxQueueLength,
                                 UBaseType_t uxItemSize,
                                 uint8_t *pucQueueStorageBuffer,
                                 StaticQueue_t *pxQueueBuffer);

//删除队列
void vQueueDelete( TaskHandle_t pxQueueToDelete );

更多请查阅FreeRTOS参考手册。

整型队列示例

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"

#include "freertos/queue.h"

// 输入参数定义为void类型指针,可强转其他任何类型参数传入,在函数内再转换回去
void sendTask1(void *pvParam)
{
    //创建队列句柄,将传入void类型队列指针转为队列句柄类型指针
    QueueHandle_t QHandle;
    QHandle = (QueueHandle_t)pvParam;

    BaseType_t xStatus;

    int i = 0;
    while (1)
    {
        //发送i的值到队列QHandle,超时等待设置为0
        xStatus = xQueueSend(QHandle, &i, 0);
        if (xStatus != pdPASS)
        {
            // 发送失败
            printf("send fail!\n");
        }
        else
        {
            printf("send done!\n");
        }
        i++;
        if (i == 8)
        {
            i = 0;
        }
        //设置延时1s发送一次
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}

void recTask(void *pvParam)
{
    QueueHandle_t QHandle;
    QHandle = (QueueHandle_t)pvParam;

    BaseType_t xStatus;
    int x = 0;
    while (1)
    {
        //判断队列是否为空
        if (uxQueueMessagesWaiting(QHandle) != 0)
        {
            // 队列非空
            //从QHandle接收数据到x,超时等待为0
            xStatus = xQueueReceive(QHandle, &x, 0);
            if (xStatus != pdPASS)
            {
                // 发送失败
                printf("rec fail!\n");
            }
            else
            {
                printf("rec x = %d!\n", x);
            }
        }
        else
        {
            printf("No data!\n");
        }
        //设置延时200ms读取一次
        vTaskDelay(200 / portTICK_PERIOD_MS);
    }
}

void app_main(void)
{

    TaskHandle_t pxTask1 = NULL;
    TaskHandle_t pxTask2 = NULL;

    // 创建队列句柄
    QueueHandle_t QHandle;
    // 创建队列,参数为队列长度、Item大小
    // 此处设置队列存储int型变量,用sizeof取得大小
    QHandle = xQueueCreate(5, sizeof(int));
    // 判断是否创建成功
    if (QHandle != NULL)
    {
        printf("Creat queue successfully!\n");
        xTaskCreatePinnedToCore(sendTask1, "sendTask1", 1024 * 5, (void *)QHandle, 1, NULL, 0);
        xTaskCreatePinnedToCore(recTask, "recTask", 1024 * 5, (void *)QHandle, 1, NULL, 0);
    }
    else
    {
        printf("Can't creat queue successfully!\n");
    }
}

示例输出

...
No data!
No data!
No data!
No data!
send done!
rec x = 0!
No data!
No data!
No data!
No data!
send done!
rec x = 1!
No data!
No data!
No data!
No data!
send done!
rec x = 2!
No data!
No data!
No data!
No data!
send done!
rec x = 3!
No data!
No data!
No data!
No data!
send done!
rec x = 4!
No data!
No data!
No data!
...

结构体队列

示例:

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"

#include "freertos/queue.h"

typedef struct A_STRUCT
{
    char id;
    char data;
}xStruct;

// 输入参数定义为void类型指针,可强转其他任何类型参数传入,在函数内再转换回去
void sendTask1(void *pvParam)
{
    QueueHandle_t QHandle;
    QHandle = (QueueHandle_t)pvParam;

    BaseType_t xStatus;

    //定义结构体并赋初值
    xStruct xUSB = {1,55};
    while (1)
    {
        xStatus = xQueueSend(QHandle, &xUSB, 0);
        if (xStatus != pdPASS)
        {
            // 发送失败
            printf("send fail!\n");
        }
        else
        {
            printf("send done!\n");
        }
        xUSB.id++;
        if (xUSB.id == 8)
        {
            xUSB.id = 0;
        }
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}

void recTask(void *pvParam)
{
    QueueHandle_t QHandle;
    QHandle = (QueueHandle_t)pvParam;

    BaseType_t xStatus;
    
    xStruct xUSB;
    while (1)
    {
        // 判断队列是否为空
        if (uxQueueMessagesWaiting(QHandle) != 0)
        {
            // 队列非空
            xStatus = xQueueReceive(QHandle, &xUSB, 0);
            if (xStatus != pdPASS)
            {
                // 发送失败
                printf("rec fail!\n");
            }
            else
            {
                printf("rec id = %d, data = %d!\n", xUSB.id,xUSB.data);
            }
        }
        else
        {
            printf("No data!\n");
        }

        vTaskDelay(500 / portTICK_PERIOD_MS);
    }
}

void app_main(void)
{
    xTaskCreatePinnedToCore(ledTask, "ledTask", 1024, NULL, 1, NULL, 1);
    // 创建队列句柄
    QueueHandle_t QHandle;
    // 创建队列,参数为队列长度、Item大小
    // 此处设置队列存储结构体变量,用sizeof取得大小
    QHandle = xQueueCreate(5, sizeof(xStruct));
    // 判断是否创建成功
    if (QHandle != NULL)
    {
        printf("Creat queue successfully!\n");
        xTaskCreatePinnedToCore(sendTask1, "sendTask1", 1024 * 5, (void *)QHandle, 1, NULL, 0);
        xTaskCreatePinnedToCore(recTask, "recTask", 1024 * 5, (void *)QHandle, 1, NULL, 0);
    }
    else
    {
        printf("Can't creat queue successfully!\n");
    }
}

运行结果:

...
No data!
send done!
rec id = 0, data = 55!
No data!
send done!
rec id = 1, data = 55!
No data!
send done!
rec id = 2, data = 55!
No data!
send done!
rec id = 3, data = 55!
No data!
send done!
rec id = 4, data = 55!
No data!
send done!
rec id = 5, data = 55!
...

指针传递(需要特别小心)

注意创建与释放,指针越界

需要注意,示例中队列传递为指针类型,代码中创建了指针来储存字符串,即为字符串数组,在传递时对数组名取地址,即为字符串的指针。

示例

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"

#include "freertos/queue.h"

#include "myled.h"

typedef struct A_STRUCT
{
    char id;
    char data;
} xStruct;

// 输入参数定义为void类型指针,可强转其他任何类型参数传入,在函数内再转换回去
void sendTask1(void *pvParam)
{
    char *pStrToSend;
    // char型可不用sizeof,直接填50,此处保持好习惯,避免写其他类型时分配错误
    // pStrToSend = (char *)malloc(sizeof(char) * 50);
    int i = 0;

    QueueHandle_t QHandle;
    QHandle = (QueueHandle_t)pvParam;

    BaseType_t xStatus;

    while (1)
    {
        //循环里分配内存,每一个数一个内存空间,需要在使用完后及时释放
        // char型可不用sizeof,直接填50,此处保持好习惯,避免写其他类型时分配错误
        pStrToSend = (char *)malloc(sizeof(char) * 50);
        // sprintf不会限制长度,可能会导致越界
        // snprintf格式化输出到buf,并限制长度
        // 如此处限制长度50,则最多输出49个,最后一个会置为'\0'
        snprintf(pStrToSend, 50, "Today is a good %d day!\r\n", i);
        i++;
        // 此处传递为字符串名的地址,字符串指针的地址
        xStatus = xQueueSend(QHandle, &pStrToSend, 0);
        if (xStatus != pdPASS)
        {
            // 发送失败
            printf("send fail!\n");
        }
        else
        {
            printf("send done!\n");
        }
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}

void recTask(void *pvParam)
{
    QueueHandle_t QHandle;
    QHandle = (QueueHandle_t)pvParam;

    char *pStrToRec;
    // pStrToRec = (char *)malloc(sizeof(char)*50);

    BaseType_t xStatus;

    while (1)
    {
        // 判断队列是否为空
        if (uxQueueMessagesWaiting(QHandle) != 0)
        {
            // 队列非空
            // 此处传递为字符串名的地址,字符串指针的地址
            xStatus = xQueueReceive(QHandle, &pStrToRec, 0);
            if (xStatus != pdPASS)
            {
                // 发送失败
                printf("rec fail!\n");
            }
            else
            {
                printf("rec: %s\r\n", pStrToRec);
            }
            //使用完传递的数据,将内存及时释放
            //由于传递数据为指针
            //实际上发送函数和接收函数指针指向为同一个内存空间
            //释放接收函数指向内存即可
            free(pStrToRec);
        }
        else
        {
            printf("No data!\n");
        }

        vTaskDelay(500 / portTICK_PERIOD_MS);
    }
}

void app_main(void)
{
    led_init();

    xTaskCreatePinnedToCore(ledTask, "ledTask", 1024, NULL, 1, NULL, 1);

    // 创建队列句柄
    QueueHandle_t QHandle;
    // 创建队列,参数为队列长度、Item大小
    // 此处设置队列存储指针类型变量,用sizeof取得指针宽度大小
    QHandle = xQueueCreate(5, sizeof(char *));
    // 判断是否创建成功
    if (QHandle != NULL)
    {
        printf("Creat queue successfully!\n");
        xTaskCreatePinnedToCore(sendTask1, "sendTask1", 1024 * 5, (void *)QHandle, 1, NULL, 0);
        xTaskCreatePinnedToCore(recTask, "recTask", 1024 * 5, (void *)QHandle, 1, NULL, 0);
    }
    else
    {
        printf("Can't creat queue successfully!\n");
    }
}

运行结果

...
Creat queue successfully!
send done!
rec: Today is a good 0 day!

No data!
send done!
rec: Today is a good 1 day!

No data!
send done!
rec: Today is a good 2 day!

No data!
send done!
rec: Today is a good 3 day!

No data!
send done!
rec: Today is a good 4 day!

No data!
send done!
rec: Today is a good 5 day!
...
showimg