【ESP32】嵌入式FreeRtos--队列Queue

基础知识

队列:先入先出(FIFO,first in first out)

使用方法:

  1. 创建队列长度、尺寸(每个信息内存空间的大小)
  2. 发送数据
  3. 取数据
API功能
xQueueCreate()创建一个队列
xQueueSend()往队列里写数据
xQueueReceive从队列里读数据
uxQueueMessagesWaiting(队列句柄)返回值为队列中参数的个数,可用于接收数据时,先判断一下队列里是否有数据
// 创建一个队列
QueueHandle_t xQueueCreate(UBaseType_t uxQueueLength, UBaseType_t uxItemSize);  // API

QueueHandle_t Qhandle = xQueueCreate(5, sizeof(int)); // 创建一个队列,长度为5,每个空间的大小为int
 // 发送队列数据API
BaseType_t xQueueSend(
    QueueHandle_t xQueue,
    const void *pvItemToQueue,
    TickType_t xTicksToWait);

// 示例
void send(void *pt)
{
  QueueHandle_t Qhandle = (QueueHandle_t)pt; // 进行强制类型转换,转换为队列句柄

  BaseType_t xStatus; // 记录数据是否发送成功

  char i = 0; // 要发送的数据
  while (1)
  {
    /*参数1:队列的句柄;参数2:要发送的数据; 参数3:超时等待时间*/
    xStatus = xQueueSend(Qhandle, &i, 0);

    if (xStatus != pdPASS)
    {
      Serial.println("发送失败");
    }
    else
      Serial.println("发送成功");
    i++;
    if (i == 8)
      i = 0;
    vTaskDelay(1000);
  }
}
// 接收队列API
BaseType_t xQueueReceive(
    QueueHandle_t xQueue,
    void *pvBuffer,
    TickType_t xTicksToWait);
    
// 示例
void receive(void *pt)
{
  int j = 0; // 接收数据
  while (1)
  {
    if (xQueueReceive(Qhandle, &j, 0) != pdPASS)
    {
      Serial.println("接收失败");
    }
    else
    {
      Serial.print("接收成功:");
      Serial.println(j);
    }

    vTaskDelay(1000);
  }
}

示例1:队列存储int数据

#include <Arduino.h>

// 创建队列全局变量,全局变量
QueueHandle_t Qhandle = xQueueCreate(5, sizeof(int)); // 创建一个队列,长度为5,每个空间的大小为int

void send(void *pt)
{
 int i = 0; // 要发送的数据
  while (1)
  {
    /*参数1:队列的句柄;参数2:要发送的数据; 参数3:超时等待时间*/
    if (xQueueSend(Qhandle, &i, 0) != pdPASS)
    {
      Serial.println("发送失败");
    }
    else
    {
      Serial.print("发送成功:");
      Serial.println(i);
    }
    i++;
    if (i == 8)
      i = 0;
    vTaskDelay(1000);
  }
}

void receive(void *pt)
{
  int j = 0; // 接收数据
  while (1)
  {
    if (xQueueReceive(Qhandle, &j, 0) != pdPASS)
    {
      Serial.println("接收失败:");
    }
    else
    {
      Serial.print("接收成功:");
      Serial.println(j);
    }

    vTaskDelay(1000);
  }
}

void setup()
{
  Serial.begin(9600);

  if (Qhandle != NULL)
  {
    Serial.println("队列创建成功");
    xTaskCreatePinnedToCore(send, "", 1024 * 5, NULL, 1, NULL, 1);    // 发送数据
    xTaskCreatePinnedToCore(receive, "", 1024 * 5, NULL, 1, NULL, 1); // 接收数据
  }
  else
  {
    Serial.println("队列创建失败");
  }
}

void loop()
{
}

运行结果:

示例2:传递结构体(常用)

// 声明一个结构体
struct Struct
{
  int id;
  int a;
};
  • QueueHandle_t Qhandle = xQueueCreate(5, sizeof(xStruct)); 在上个程序的基础上进行创建的队列每个空间的大小
  • 修改队列的地址
#include <Arduino.h>

struct Struct
{
  int id;
  int a;
};

// 创建队列全局变量,全局变量
QueueHandle_t Qhandle = xQueueCreate(5, sizeof(Struct)); // 创建一个队列,长度为5,每个空间的大小为int

void send(void *pt)
{
  Struct xUSB = {1, 55}; // 要发送的数据
  while (1)
  {
    /*参数1:队列的句柄;参数2:要发送的数据; 参数3:超时等待时间*/
    if (xQueueSend(Qhandle, &xUSB, 0) != pdPASS)
    {
      Serial.println("发送失败");
    }
    else
    {
      Serial.println("发送成功");
      xUSB.id++;
    }

    vTaskDelay(1000);
  }
}

void receive(void *pt)
{
  Struct yUSB; // 定义一个接收结构体
  while (1)
  {
    if (xQueueReceive(Qhandle, &yUSB, 0) != pdPASS)
    {
      Serial.println("接收失败");
    }
    else
    {
      Serial.print("接收成功:");
      Serial.println(yUSB.id);
      Serial.println(yUSB.a);
    }

    vTaskDelay(1000);
  }
}

void setup()
{
  Serial.begin(9600);

  if (Qhandle != NULL)
  {
    Serial.println("队列创建成功");
    xTaskCreatePinnedToCore(send, "", 1024 * 5, NULL, 1, NULL, 1);    // 发送数据
    xTaskCreatePinnedToCore(receive, "", 1024 * 5, NULL, 1, NULL, 1); // 接收数据
  }
  else
  {
    Serial.println("队列创建失败");
  }
}

void loop()
{
}

运行结果:

发送成功
接收成功:1
55
发送成功
接收成功:2
55

示例3:传递大数据时,把指针对应的数据进行传递

  • malloc()函数使用:在使用malloc开辟空间时,使用完一定要释放空间,如果不释放会造成内存泄漏。malloc()函数返回的实际是一个无类型指针,必须在其前面加上指针类型强制转换才可以使用。指针自身 = (指针类型*)malloc(sizeof(指针类型)*数据数量)
	int *p = NULL;
	int n = 10;
	p = (int *)malloc(sizeof(int)*n);
  • free()释放malloc()函数给指针变量分配的内存空间。注意:使用后该指针变量一定要重新指向NULL,防止野指针(悬空指针、失效指针)出现。
int *p = (int *)malloc(sizeof(int));
	*p = 100;
	free(p);
	p = NULL;

队列的多进单出:多个任务写,一个任务读


多个任务输入一个队列,一个任务读队列中的数据,此时注意设置任务的优先级别,设置写入的任务级别为1(各任务之间轮流发送数据),读任务的优先级别为2。

  • portMAX_DELAY一直等待,直到队列中有数据就开始读
#include <Arduino.h>

QueueHandle_t Qhandle = xQueueCreate(5, sizeof(int)); // 创建一个队列,长度为5,每个空间的大小为int

void send1(void *pt)
{
  int i = 1; // 任务1要发送的数据
  while (1)
  {

    if (xQueueSend(Qhandle, &i, 0) != pdPASS)
    {
      Serial.println("发送失败");
    }
    else
    {
      Serial.println("发送成功");
    }
    vTaskDelay(1000);
  }
}

void send2(void *pt)
{
  int i = 2; // 任务2要发送的数据
  while (1)
  {
    if (xQueueSend(Qhandle, &i, 0) != pdPASS)
    {
      Serial.println("发送失败");
    }
    else
    {
      Serial.println("发送成功");
    }
    vTaskDelay(1000);
  }
}

void receive(void *pt)
{
  int i; // 存储接收数据
  while (1)
  {
    if (xQueueReceive(Qhandle, &i, portMAX_DELAY) != pdPASS) // portMAX_DELAY,一直等待,直到队列中有数据。等待时间设置为0,表示队列中如果没有数据,立即返回
    {
      Serial.println("接收失败");
    }
    else
    {
      Serial.print("接收成功:");
      Serial.println(i);
    }
    // vTaskDelay(1000); // 采用了portMAX_DELAY,这里就不需要delay了
  }
}

void setup()
{
  Serial.begin(9600);

  if (Qhandle != NULL)
  {
    Serial.println("队列创建成功");
    xTaskCreatePinnedToCore(send1, "", 1024 * 5, NULL, 1, NULL, 1); // 两个相同的优先级别,轮流发送数据
    xTaskCreatePinnedToCore(send2, "", 1024 * 5, NULL, 1, NULL, 1);
    xTaskCreatePinnedToCore(receive, "", 1024 * 5, NULL, 2, NULL, 1); // 优先级别2,只要队列中有数据,就读
  }
  else
  {
    Serial.println("队列创建失败");
  }
}

void loop()
{
}

运行结果:

发送成功
接收成功:2
发送成功
接收成功:1

队列集合:一个任务读不同的队列

  • xQueueCreateSet( const UBaseType_t uxEventQueueLength ) 参数为队列集合的总长度
/*把队列加入到集合中
参数1:需要加入的队列句柄;参数2:队列集合的句柄*/
BaseType_t xQueueAddToSet( QueueSetMemberHandle_t xQueueOrSemaphore,
QueueSetHandle_t xQueueSet );
// 从队列集合中选择有数据的队列
QueueSetMemberHandle_t xQueueSelectFromSet( QueueSetHandle_t xQueueSet,
const TickType_t xTicksToWait );
#include <Arduino.h>

QueueHandle_t Qhandle1 = xQueueCreate(5, sizeof(int)); // 队列1
QueueHandle_t Qhandle2 = xQueueCreate(5, sizeof(int)); // 队列2

QueueSetHandle_t QueueSet = xQueueCreateSet(10); // 队列集合句柄

xQueueAddToSet(Qhandle1, QueueSet); // 把队列1加入到队列集合中
xQueueAddToSet(Qhandle2, QueueSet); // 把队列2加入到队列集合中

QueueSetMemberHandle_t QueueData = xQueueSelectFromSet(QueueSet, portMAX_DELAY); // 从队列集合中获取有数据的队列

void send1(void *pt)
{
  int i = 1; // 任务1要发送的数据
  while (1)
  {

    if (xQueueSend(Qhandle1, &i, 0) != pdPASS)
    {
      Serial.println("发送失败");
    }
    else
    {
      Serial.println("发送成功");
    }
    vTaskDelay(1000);
  }
}

void send2(void *pt)
{
  int i = 2; // 任务2要发送的数据
  while (1)
  {
    if (xQueueSend(Qhandle2, &i, 0) != pdPASS)
    {
      Serial.println("发送失败");
    }
    else
    {
      Serial.println("发送成功");
    }
    vTaskDelay(1000);
  }
}

void receive(void *pt)
{

  int i; // 存储接收数据
  while (1)
  {
    if (xQueueReceive(QueueData, &i, portMAX_DELAY) != pdPASS) // portMAX_DELAY,一直等待,直到队列中有数据
    {
      Serial.println("接收失败");
    }
    else
    {
      Serial.print("接收成功:");
      Serial.println(i);
    }
    // vTaskDelay(1000); // 采用了portMAX_DELAY,这里就不需要delay了
  }
}

void setup()
{
  Serial.begin(9600);

  Serial.println("队列创建成功");
  xTaskCreatePinnedToCore(send1, "", 1024 * 5, NULL, 1, NULL, 1); // 两个相同的优先级别,轮流发送数据
  xTaskCreatePinnedToCore(send2, "", 1024 * 5, NULL, 1, NULL, 1);
  xTaskCreatePinnedToCore(receive, "", 1024 * 5, NULL, 2, NULL, 1); // 优先级别2,只要队列中有数据,就读
}

void loop()
{
}

队列邮箱:一个任务写,多个任务读

  • BaseType_t xQueueOverwrite( QueueHandle_t xQueue, const void *pvItemToQueue );往队列邮箱中写入数据
// 从队列邮箱中读数据
BaseType_t xQueuePeek( QueueHandle_t xQueue,
void *pvBuffer, TickType_t
xTicksToWait );
#include <Arduino.h>

QueueHandle_t Mailbox = xQueueCreate(1, sizeof(int));

void send(void *pt)
{
  int i = 1; // 任务1要发送的数据
  while (1)
  {
    if (xQueueOverwrite(Mailbox, &i) != pdPASS)
    {
      Serial.println("发送失败");
    }
    else
    {
      Serial.println("发送成功");
      i++;
    }
    vTaskDelay(1000);
  }
}

void receive1(void *pt)
{

  int i; // 存储接收数据
  while (1)
  {
    if (xQueuePeek(Mailbox, &i, 0) != pdPASS) // portMAX_DELAY,一直等待,直到队列中有数据
    {
      Serial.println("接收失败");
    }
    else
    {
      Serial.print("接收成功:");
      Serial.println(i);
    }
  }
}
void receive2(void *pt)
{

  int i; // 存储接收数据
  while (1)
  {
    if (xQueuePeek(Mailbox, &i, 0) != pdPASS) // portMAX_DELAY,一直等待,直到队列中有数据
    {
      Serial.println("接收失败");
    }
    else
    {
      Serial.print("接收成功:");
      Serial.println(i);
    }
  }
}

void setup()
{
  Serial.begin(9600);

  Serial.println("队列创建成功");
  xTaskCreatePinnedToCore(send, "", 1024 * 5, NULL, 1, NULL, 1);
  xTaskCreatePinnedToCore(receive1, "", 1024 * 5, NULL, 2, NULL, 1);
  xTaskCreatePinnedToCore(receive2, "", 1024 * 5, NULL, 2, NULL, 1);
}

void loop()
{
}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FreeRTOS是一个开源的实时操作系统内核,被广泛应用于嵌入系统中。ESP32是一款具有双核处理器和Wi-Fi功能的芯片,通过使用ESP-IDF开发框架可以进行软件开发。在ESP32-IDF开发中,使用FreeRTOS的消息队列可以实现不同任务之间的通信。 在ESP32开发中,可以通过中断服务程序(Interrupt Service Routine,ISR)来发送消息到消息队列,并在任务中通过接收方法响应。 首先,我们需要创建一个全局的消息队列句柄,可以使用xQueueCreate函数来创建一个消息队列。例如,可以使用以下代码创建一个大小为10的消息队列: xQueueHandle messageQueue = xQueueCreate(10, sizeof(int)); 然后,在中断服务程序中,可以使用xQueueSendFromISR方法将消息发送到消息队列中。例如,可以使用以下代码将一个整数值发送到消息队列中: int value = 100; xQueueSendFromISR(messageQueue, &value, NULL); 在任务中,可以使用xQueueReceive方法从消息队列中接收消息并进行响应。例如,可以使用以下代码从消息队列中接收一个整数值并打印出来: int receivedValue; xQueueReceive(messageQueue, &receivedValue, portMAX_DELAY); printf("Received value: %d\n", receivedValue); 需要注意的是,在接收消息时,可以通过指定第三个参数来设置等待时间。例如,使用portMAX_DELAY表示无限等待,即直到接收到消息为止。 通过以上步骤,我们可以实现在ESP32开发中使用FreeRTOS消息队列进行中断服务消息发送与响应。这种方可以实现不同任务之间的通信和同步,提高系统的并发性和实时性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值