当前位置: 首页 > ops >正文

基于ESP-IDF的ESP32开发记录——如何建立一个队列

ESP-IDF版本:v5.2.1

基于上一篇文章,现在已经学会了怎么在ESP32上运行一个任务,这篇就是介绍怎么建立一个队列。

先说下个人对队列的理解,队列其实就是一种高级的数组,写freertos系统的人已经帮用户在数组上封装了几层,并提供了相应的API给用户直接调用。实线的功能就是相比数组而言,多了任务间通信和同步时的一些重要的功能特性。
比如在多任务同时访问数据内容时,数组会出现竞争问题,如果不使用临界区保护,程序就会有数据错误的风险。但如果使用队列,多任务同时访问队列,freertos本身就会对数据进行保护,则不再需要人为的写保护代码。
有比如队列自带先进先出的特性,如果使用数组要实现先进先出,则还需要额外写逻辑才能实现。

所以用队列其实跟用数组没多大区别,核心的一点就是如果数据只需要在一个任务里面反复用,那就可以直接用数组。如果数据需要在多任务或中断里面改变,那就用队列,而且还能实现任务同步、阻塞等效果。

首先要创建队列,只要与队列有关,就需要引入两个头文件:

#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
创建队列 xQueueCreate( uxQueueLength, uxItemSize )

这个函数其实是一个宏:

#define xQueueCreate( uxQueueLength, uxItemSize )    xQueueGenericCreate( ( uxQueueLength ), ( uxItemSize ), ( queueQUEUE_TYPE_BASE ) )

不过我们不去管宏的实现,因为这是乐鑫底层的设定。这个多出来的参数queueQUEUE_TYPE_BASE 乐鑫已经设定成了
( ( uint8_t ) 0U )。

第一个参数 uxQueueLength:队列长度。

第二个参数 uxItemSize:队列里面每个成员的大小(以字节为单位)。

我的用法:

QueueHandle_t queue_handle = NULL;typedef struct
{int i;unsigned char j;
}queue_data_t;queue_data_t queue_data1 = {100,200};
queue_data_t queue_data2 = {0,0};void app_main(void)
{queue_handle = xQueueCreate(10,sizeof(queue_data_t));xQueueSend(queue_handle,&queue_data1,100);xQueueReceive(queue_handle,&queue_data2,portMAX_DELAY);vTaskDelay(pdMS_TO_TICKS(20));
}

这样就新建了一个长度为10,每个成员为queue_data_t类型的队列了。

写队列 xQueueSend( xQueue, pvItemToQueue, xTicksToWait )

同样这个函数也是个宏定义,底层实际上调用的是另外一个函数,但这个不需要用户管,是乐鑫底层的事情。

第一个参数 xQueue:队列的句柄,意思就是要往那个队列写数据。按照上方的代码,这个地方的句柄就写成 queue_handle。

第二个参数 pvItemToQueue:写什么内容到队列。这个参数是一个指针,需要用户传入数据的地址。按照上方的代码,这个位置的参数写成&queue_data1。

第三个参数 xTicksToWait:写入等待多少个系统节拍。假如队列已满,我们还想要往队列里面写入内容,系统调度会自动把写入阻塞,并等待队列有空间了再写入数据。用户可以设定这个等待时间,假如这个设置的参数写100。说明假如写入阻塞了,系统会在阻塞后100个系统节拍内一直等待队列空闲,当时间超过100个节拍了,那这次写入就被丢弃了。

写数据到队列头部 xQueueSendToFront(xQueue,pvItemToQueue,xTicksToWait)

因为队列是先入先出的,所以正常调用的写队列,会把数据写到队列尾部,如果想要先入后出,可以调用这个写数据到队列头,这样就能实现先入后出了。

读队列数据 xQueueReceive(QueueHandle_t xQueue, void *const pvBuffer, TickType_t xTicksToWait)

第一个参数 xQueue:要读的队列的句柄。填queue_handle。

第二个参数 pvBuffer:指向缓冲区的指针,用来存放读出来的数据。可以定义一个跟队列成员数据类型一样的变量来存放。

第三个参数 xTicksToWait:等待多少个系统节拍。因为如果队列为空,这个函数读不到数据的,就会发生阻塞。如果设置为
portMAX_DELAY,则会一直在这里阻塞,直到有数据能读出来。如果设置为0,则读不到数据就会直接返回。如果设置为100,则阻塞100个节拍,之后就往下继续执行。

拿上面的代码为例子xQueueReceive(queue_handle,&queue_data2,portMAX_DELAY);这行代码已经把阻塞时间设置为了最大,也就意味着如果队列里面没有数据,这个app_main()函数就会一直卡在这一行,是没有机会运行到下一行vTaskDelay(pdMS_TO_TICKS(20));的。如果把portMAX_DELAY改为100,那当队列没有数据,运行到读队列这行代码时,系统等待100个节拍之后就继续往下执行,执行vTaskDelay这个函数。

http://www.xdnf.cn/news/9436.html

相关文章:

  • 使用Spring AI集成Perplexity AI实现智能对话(详细配置指南)
  • 【PhysUnits】13 改进减法(sub.rs)
  • Vue开发系列——Vue 生命周期钩子 及常见知识点
  • STP(生成树协议)原理与配置
  • XCTF-web-easyphp
  • BugKu Web渗透之source
  • 虚幻GamePlay框架
  • 《函数栈帧的创建和销毁》
  • AI--知识库RAG实战
  • @Transactional高级用法之传播机制
  • 基于对比学习的推荐系统开发方案,使用Python在PyCharm中实现
  • CSS3实现的账号密码输入框提示效果
  • 【25-cv-05894】Keith律所代理Jennifer Le Feuvre版权画
  • 大数据-273 Spark MLib - 基础介绍 机器学习算法 决策树 分类原则 分类原理 基尼系数 熵
  • pikachu靶场通关笔记06 XSS关卡02-反射型POST
  • 私有化部署DeepSeek后行业数据模型的训练步骤
  • 数字孪生赋能智能制造:某汽车发动机产线优化实践
  • Function calling和mcp区别
  • HTML5基础
  • 人工智能100问☞第35问:什么是Transformer模型?
  • 数据库-算法学习C++(入门)
  • Android-kotlin协程学习总结
  • 如何通过创新科技手段打造美术馆展厅互动体验,提升观众沉浸感?
  • 《P5507 机关》
  • java操作服务器文件(把解析过的文件迁移到历史文件夹地下)
  • VM改MAC电脑密码(截图)
  • 佰力博科技与您探讨DEAI介电阻抗分析仪的特点
  • day023-网络基础与OSI七层模型
  • 变色龙Ultra编译指南:从零开始
  • Python爬虫实战:抓取百度15天天气预报数据