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

news2025/1/24 14:28:52

基础知识

队列:先入先出(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()
{
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/413685.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

静态时序分析Static Timing Analysis4——多时钟域和多时钟时序检查

文章目录前言一、多时钟域时序分析1、慢时钟域到快时钟域1.1 建立时间检查1.2 保持时间检查1.3 多周期检查2、快时钟域到慢时钟域2.1 建立时间检查2.2 保持时间检查2.3 合理的约束3、总结二、多时钟1、整数倍关系2、非整数倍关系三、相位移动前言 2023.4.12 这里讲的多时钟域和…

干货满满!MES生产制造管理全流程分析

阅读本文您将了解&#xff1a;1.什么是MES生产管理流程&#xff1b;2.MES生产管理流程具体步骤&#xff1b;3.实施MES生产管理流程优势&#xff1b;4.MES生产管理流程中可能会遇见的问题。 一、什么是MES生产管理流程 MES生产管理系统&#xff08;又称制造执行系统&#xff0…

Java开发 - 公共字段的自动填充

前言 如果说Java开发中有什么是让人很烦的一件事&#xff0c;那一定是无尽的填充字段&#xff0c;本篇作为观众瑰宝系列第二篇&#xff0c;将带来公共字段填充相关的知识点&#xff0c;学完此篇&#xff0c;让你摆脱公共字段填充带来的麻烦&#xff0c;节省代码&#xff0c;降…

定时任务:从Timer、STPE、Quartz 到 XXL-JOB

java.util.Timerjava.util.concurrent.ScheduledThreadPoolExecutor 简称STPEQuartzXXL-JOB 基本套路 定时任务基本上都是在一个while(true)或for(;;)死循环中&#xff08;每次循环判断定时程序是否终止或暂停&#xff09;&#xff0c;从任务存放的地&#xff08;可以是内存的…

电脑重装系统后会怎样?

​有小伙伴的电脑系统运行缓慢卡顿&#xff0c;现在想通过重装系统来解决问题。咨询电脑重装系统会怎么样对系统有影响吗&#xff0c;现在小编就带大家看看电脑重装系统后会怎样。 方法/步骤&#xff1a; 一、电脑重装系统会怎么样 1、我们的电脑重装系统后&#xff0c;电脑…

Java面试题总结 | Java基础部分(持续更新)

Java基础 文章目录Java基础一个Java文件里可以有多个类吗&#xff08;不含内部类&#xff09;&#xff1f;创建对象的方法面向对象和面向过程简述自动装箱拆箱Java代码块执行顺序java中的基本数据类型对应的字节数包装类型和基本数据类型的场景java中的关键字分类final关键字st…

【微信小程序】小程序基础入门01

&#x1f609;博主&#xff1a;初映CY的前说(前端领域) ,&#x1f4d2;本文核心&#xff1a;微信小程序的入门介绍 【前言】小程序是一种不需要下载、安装即可使用的应用&#xff0c;它实现了应用触手可及的梦想&#xff0c;用户扫一扫或者搜一下就能打开应用&#xff0c;也实现…

Flink 优化 (三) --------- 反压处理

目录一、概述1. 反压的理解2. 反压的危害二、定位反压节点1. 利用 Flink Web UI 定位2. 利用 Metrics 定位三、反压的原因及处理1. 查看是否数据倾斜2. 使用火焰图分析3. 分析 GC 情况4. 外部组件交互一、概述 Flink 网络流控及反压的介绍&#xff1a;https://flink-learning.…

threejs-后期通道效果汇总

文章目录前言后期处理通道汇总简单通道效果FilmPassDotScreenPassBloomPassUnrealBloomPassOutlinePassGlitchPassHalftonePass高级通道效果掩码效果MaskPass景深效果 BokehPass景自定义效果 ShaderPass总结前言 Threejs提供了很多后期处理通道&#xff0c;配合 THREE.EffectC…

【并发编程Python】一文了解Python并发编程,协程、线程、进程

并发编程简介和一些前缀知识 并发编程是使得程序大幅度提速的。在并发编程中&#xff0c;程序可以同一时间执行多个任务&#xff0c;这有助于提高程序的吞吐量和响应时间。并发编程设计的主要概念包括线程、锁、同步、信号量、进程间通信等。 前缀知识&#xff1a; IO&#x…

信息系统项目管理师第四版知识摘编:第22章 组织通用治理​

第22章 组织通用治理​ 组织治理是协调组织利益相关者之间关系的一种制度安排&#xff0c;目标是为了确保组织的高效决策&#xff0c;实现利益相关者之间的利益均衡&#xff0c;提高组织的绩效&#xff0c;确保组织运行的可持续发展。​ 22.1组织战略​ 组织战略是组织高质量…

一文读懂:低代码开发平台对企业效益有什么作用?

一文读懂&#xff1a;低代码开发平台对企业效益有什么作用&#xff1f; 近年来&#xff0c;企业数字化转型的需求越来越迫切&#xff0c;但面临着IT人才不足、成本高昂等痛点问题&#xff0c;于是零代码平台应运而生&#xff0c;成为企业数字化转型的重要工具。 市面上的零代…

基于支持向量机SVM的脑部肿瘤识别,脑电波样本熵提取

目录 支持向量机SVM的详细原理 SVM的定义 SVM理论 Libsvm工具箱详解 简介 参数说明 易错及常见问题 SVM应用实例,基于SVM的的脑部肿瘤识别分类预测 代码 结果分析 展望 支持向量机SVM的详细原理 SVM的定义 支持向量机(support vector machines, SVM)是一种二分类模型,它…

Spring boot+Vue博客平台:文章列表展示、文章分类与标签管理模块实现

本文将详细介绍如何实现博客平台中的文章列表展示、文章分类与标签管理功能&#xff0c;包括前端的Vue组件设计和后端的Spring Boot接口实现。在阅读本文后&#xff0c;您将了解如何设计和实现高效、易用的文章列表展示、文章分类与标签管理功能。 一、文章列表展示 1.设计思…

电脑蓝屏错误MACHINE-CHECK-EXCEPTION重装系统教程

电脑蓝屏错误MACHINE-CHECK-EXCEPTION重装系统教程分享。最近有用户电脑遇到了蓝屏问题&#xff0c;正常使用电脑的时候常常会出现了蓝屏错误代码“MACHINE-CHECK-EXCEPTION”。那么遇到这个问题要怎么去进行系统的重装呢&#xff1f;来看看以下的具体操作方法教学吧。 准备工作…

JVM/GC/CMS

CMS (Concurrent Mark Sweep) jdk1.4后期版本开始引入的新gc算法ParNew(新生代) CMS(老年代)组合使用使用标记-清除算法目标&#xff1a;适合于B/S等对响应时间要求高的场景缺点&#xff1a;运行结束产生大量空间碎片缺点&#xff1a;由于分配给用户使用的老年代空间不足造成…

一文快速回顾 Servlet、Filter、Listener

什么是Servlet&#xff1f; 前置知识&#xff1a; Web 服务器&#xff1a;可以指硬件上的&#xff0c;也可以指软件上的。从硬件的角度来说&#xff0c; Web 服务器指的就是一台存储了网络服务软件的计算机&#xff1b;从软件的角度来说&#xff0c; Web 服务器指的是一种软件…

使用codon加速你的python程序

使用codon加速你的python程序 作为高性能 Python 编译器&#xff0c;Codon 可将 Python 代码编译为本机机器代码&#xff0c;而无需任何运行时开销。在单线程上&#xff0c;Python 的典型加速大约为 10-100 倍或更多。Codon 的性能通常与 C/C 的性能相当。与 Python 不同&#…

Three.js教程:第一个3D场景

推荐&#xff1a;将NSDT场景编辑器加入你3D工具链其他工具系列&#xff1a;NSDT简石数字孪生下面的代码完整展示了通过three.js引擎创建的一个三维场景&#xff0c;在场景中绘制并渲染了一个立方体的效果&#xff0c;为了大家更好的宏观了解three.js引擎&#xff0c; 尽量使用了…

【linux】进程和线程的几种状态及状态切换

文章目录一、进程的状态1.1 进程的三种状态1.2 三种状态转换图1.3 三种状态之间的转换1.4 linux下的进程进程状态二、线程的状态三、总结一、进程的状态 1.1 进程的三种状态 进程状态&#xff1a;一个进程的生命周期可以划分为一组状态&#xff0c;这些状态刻画了整个进程。进…