【FreeRTOS基础入门】队列集

时间:2024-02-21 21:44:00

文章目录

  • 前言
  • 一、为什么需要队列集
  • 二、队列集的基本操作顺序
  • 三、使用方法
    • 3.1 创建队列集
    • 3.2 与队列集建立联系
    • 3.3 读取队列集得到有数据的队列
    • 3.4 示例代码
  • 总结


前言

FreeRTOS是一个开源的实时操作系统内核,广泛应用于嵌入式系统中。它提供了一套丰富的功能,其中队列是一个重要的组件,用于实现任务之间的通信和数据传递。本文将重点介绍FreeRTOS中的队列集(Queue Set)的基础知识,以帮助初学者更好地理解和应用这一功能。

在嵌入式系统中,多个任务可能需要共享数据或进行协同工作。队列集是FreeRTOS中用于处理这种情况的一种高效机制。通过使用队列集,任务可以等待多个队列中的任何一个,从而更灵活地响应事件和共享信息。在本文中,我们将深入探讨队列集的概念、使用方法以及在实际应用中的一些典型场景。


一、为什么需要队列集

比如说,你的系统有鼠标,键盘,触摸屏等等等等,这些输入设备都需要往app里面发送数据,那么发送数据肯定就是使用队列了,他们每一个都需要一个独一无二的队列进行存储对应的数据,但是我们之前学的队列,他每次等待都只能等待某一个队列,但是现在有几个了,所以这样就不行。所以freertos引入了队列集。队列集其实就是保存了一堆队列的队列而已。队列集里面任意一个有数据,就会唤醒等待队列的任务,任务来取出相应的数据即可。

二、队列集的基本操作顺序

首先我们的队列集也是一个队列,他存着比如触摸,鼠标等等的队列。

  1. 首先我们要使用队列集需要先创建一个队列集,如果要检测3个队列A、B、C,这个队列集的长度为A+B+C队列的长度
  2. 与你需要检测的队列建立联系。在queue中里面有个handle指向队列集
  3. 当比如触摸屏有数据,他把数据放到他的队列里面去,然后需要把触摸屏队列handle放到队列集中
  4. 我们可以去读queue set,他会返回某一个队列(一次)
  5. 读返回的队列数据即可(一次)

三、使用方法

如果我们想使用队列集,需要把这个宏设置为1:configUSE_QUEUE_SETS
我们这边以一个示例来讲解,这个示例为task1和task2填数据到各自的队列,然后task3来读队列集

3.1 创建队列集

我们可以使用下面这个函数来创建一个队列集

QueueSetHandle_t xQueueCreateSet( const UBaseType_t uxEventQueueLength );

参数为队列集的长度。如果要检测3个队列A、B、C,这个队列集的长度为A+B+C队列的长度
返回值为队列集的handle

3.2 与队列集建立联系

我们可以使用下面这个函数用来队列和队列集建立联系

BaseType_t xQueueAddToSet( QueueSetMemberHandle_t xQueueOrSemaphore, QueueSetHandle_t xQueueSet );

参数1为Queue的handle,参数2为与哪个队列集联系

3.3 读取队列集得到有数据的队列

我们可以使用下面这个函数进行队列集的读取:

QueueSetMemberHandle_t xQueueSelectFromSet( QueueSetHandle_t xQueueSet, TickType_t const xTicksToWait );

参数1为哪个队列集,参数2为等待时间
返回值为有数据的队列.
然后我们就可以使用队列的读函数直接去读了,可以不需要等待时间,因为前面都判断了一定有数据,所以不需要等待。

3.4 示例代码

#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"

#define QUEUE_LENGTH 5
#define ITEM_SIZE    sizeof(int)

// 声明队列句柄
QueueHandle_t queue1, queue2;

// Task1,向队列1发送数据
void Task1(void *pvParameters) {
    int data = 1;
    
    while (1) {
        // 向队列1发送数据
        xQueueSend(queue1, &data, portMAX_DELAY);
        data++; // 更新数据
        
        vTaskDelay(pdMS_TO_TICKS(1000)); // 1秒延迟
    }
}

// Task2,向队列2发送数据
void Task2(void *pvParameters) {
    int data = 100;
    
    while (1) {
        // 向队列2发送数据
        xQueueSend(queue2, &data, portMAX_DELAY);
        data += 100; // 更新数据
        
        vTaskDelay(pdMS_TO_TICKS(2000)); // 2秒延迟
    }
}

// Task3,从队列集中读取数据
void Task3(void *pvParameters) {
    QueueSetHandle_t queueSet;
    QueueHandle_t member;
    BaseType_t xResult;
    int received_data;
    
    // 创建队列集
    queueSet = xQueueCreateSet(QUEUE_LENGTH * 2);
    
    // 将队列1和队列2添加到队列集中
    xQueueAddToSet(queue1, queueSet);
    xQueueAddToSet(queue2, queueSet);
    
    while (1) {
        // 等待从队列集中读取数据
        member = xQueueSelectFromSet(queueSet, portMAX_DELAY);
        
        // 判断是哪个队列有可读数据
        if (member == queue1) {
            // 从队列1中接收数据
            xQueueReceive(queue1, &received_data, 0);
            printf("Task3 received data from queue1: %d\n", received_data);
        } else if (member == queue2) {
            // 从队列2中接收数据
            xQueueReceive(queue2, &received_data, 0);
            printf("Task3 received data from queue2: %d\n", received_data);
        }
    }
}

int main(void) {
    // 创建队列
    queue1 = xQueueCreate(QUEUE_LENGTH, ITEM_SIZE);
    queue2 = xQueueCreate(QUEUE_LENGTH, ITEM_SIZE);
    
    // 创建任务
    xTaskCreate(Task1, "Task1", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
    xTaskCreate(Task2, "Task2", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
    xTaskCreate(Task3, "Task3", configMINIMAL_STACK_SIZE, NULL, 2, NULL);
    
    // 启动调度器
    vTaskStartScheduler();
    
    return 0;
}


总结

队列集作为FreeRTOS的一个重要特性,在嵌入式系统的开发中发挥着关键作用。通过学习队列集的基础知识,开发者可以更好地设计和实现任务之间的通信机制,提高系统的灵活性和效率。在实际应用中,合理使用队列集可以简化任务之间的同步与通信,使系统更加可靠和稳定。希望本文能够为初学者提供一个清晰的入门指南,让大家更好地利用FreeRTOS的队列集功能进行嵌入式