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

ESP32学习-FreeRTOS队列使用指南与实战

FreeRTOS 缓存队列关键概念

FreeRTOS 的缓存队列(Queue)是一种用于任务间通信的机制,允许任务或中断服务例程(ISR)以 FIFO(先进先出)的方式发送和接收数据。缓存队列可以传输固定大小的数据块,支持多任务并发操作,并通过阻塞机制实现同步。

关键特性:

  • 线程安全:队列操作是原子的,无需额外保护。
  • 阻塞与非阻塞:任务可以阻塞等待队列空间或数据,或立即返回。
  • 多任务支持:多个任务可以同时读写队列。
  • 中断安全:提供带 FromISR 后缀的 API 供中断上下文使用。

缓存队列使用模板

创建队列

使用 xQueueCreate()xQueueCreateStatic() 创建队列。动态创建示例:

QueueHandle_t xQueue = xQueueCreate(uxQueueLength,     // 队列长度(最大可存数据项数)uxItemSize         // 每个数据项的大小(字节)
);

参数说明:

  • uxQueueLength:队列容量,即队列可存储的最大数据项数量。
  • uxItemSize:每个数据项的大小(如传输 int 则设为 sizeof(int))。
发送数据到队列

使用 xQueueSend()xQueueSendFromISR()(中断中发送):

BaseType_t xStatus = xQueueSend(xQueue,           // 队列句柄pvItemToQueue,    // 指向待发送数据的指针xTicksToWait      // 阻塞超时时间(portMAX_DELAY 表示无限等待)
);

参数说明:

  • pvItemToQueue:指向待发送数据的指针(数据会被复制到队列)。
  • xTicksToWait:若队列满时,任务阻塞的 tick 数。0 表示不阻塞,立即返回。
从队列接收数据

使用 xQueueReceive()xQueueReceiveFromISR()(中断中接收):

BaseType_t xStatus = xQueueReceive(xQueue,           // 队列句柄pvBuffer,         // 接收数据的缓冲区指针xTicksToWait      // 阻塞超时时间
);

参数说明:

  • pvBuffer:指向接收缓冲区的指针(队列数据会被复制到此)。
  • xTicksToWait:若队列为空时,任务阻塞的 tick 数。
其他常用函数
  • uxQueueMessagesWaiting():获取队列中当前数据项数量。
  • xQueueReset():重置队列为空状态。
  • vQueueDelete():删除动态创建的队列。

完整示例代码

#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include <stdio.h>// 定义队列参数
#define QUEUE_LENGTH 5             // 队列最多容纳 5 个元素
#define ITEM_SIZE sizeof(int)      // 每个元素大小为一个 int// 发送任务:每秒向队列发送一个整数
void vSenderTask(void *pvParameters) {QueueHandle_t xQueue = (QueueHandle_t)pvParameters; // 获取队列句柄int valueToSend = 42;while (1) {// 向队列发送数据,如果队列已满则阻塞等待xQueueSend(xQueue, &valueToSend, portMAX_DELAY);printf("Sent: %d\n", valueToSend);// 延时 1 秒(1000 毫秒)vTaskDelay(pdMS_TO_TICKS(1000));}
}// 接收任务:阻塞等待从队列接收数据
void vReceiverTask(void *pvParameters) {QueueHandle_t xQueue = (QueueHandle_t)pvParameters; // 获取队列句柄int receivedValue;while (1) {// 从队列接收数据(如果队列为空,则阻塞等待)if (xQueueReceive(xQueue, &receivedValue, portMAX_DELAY) == pdPASS) {// 成功接收到数据,打印处理printf("Received: %d\n", receivedValue);}}
}// 系统主入口函数
void main() {// 创建队列:最大容纳 QUEUE_LENGTH 个 int 类型数据QueueHandle_t xQueue = xQueueCreate(QUEUE_LENGTH, ITEM_SIZE);// 创建发送任务,优先级为 1,传入队列句柄xTaskCreate(vSenderTask, "Sender", configMINIMAL_STACK_SIZE, xQueue, 1, NULL);// 创建接收任务,优先级也为 1,传入队列句柄xTaskCreate(vReceiverTask, "Receiver", configMINIMAL_STACK_SIZE, xQueue, 1, NULL);// 启动 FreeRTOS 调度器(之后永不返回)vTaskStartScheduler();
}

关键注意事项

  • 数据复制:队列通过内存拷贝传输数据,需确保发送的数据指针有效。
  • 中断上下文:在中断中必须使用 FromISR 函数,且不可阻塞。
  • 优先级反转:高优先级任务长时间阻塞可能导致低优先级任务无法释放队列资源。

问题

1.为什么main函数不会直接退出吗?
vTaskStartScheduler()这个函数会启动 FreeRTOS 的调度器,从此进入多任务运行状态:

  • 控制权会交由调度器管理;
  • main() 不会继续执行;
  • 实际上 vTaskStartScheduler() 永不返回(除非发生错误);
    所以,只要调度器启动成功,main() 的最后一行之后的代码永远不会执行
http://www.xdnf.cn/news/1199971.html

相关文章:

  • 回归预测 | MATLAB实现BiTCN双向时间卷积神经网络多输入单输出回归预测
  • 如何在 Ubuntu 24.04 或 22.04 中更改 SSH 端口
  • 个人笔记HTML5
  • 【ee类保研面试】通信类---信息论
  • [2025CVPR-图象超分辨方向]DORNet:面向退化的正则化网络,用于盲深度超分辨率
  • 标签驱动的可信金融大模型训练全流程-Agentar-Fin-R1工程思路浅尝
  • Unity Catalog与Apache Iceberg如何重塑Data+AI时代的企业数据架构
  • JavaEE初阶第十二期:解锁多线程,从 “单车道” 到 “高速公路” 的编程升级(十)
  • LeetCode 239:滑动窗口最大值
  • 模拟实现python的sklearn库中的Bunch类以及 load_iris 功能
  • RocksDB 高效采样算法:水塘抽样和随机寻址
  • WAIC 2025 热点解读:如何构建 AI 时代的“视频神经中枢”?
  • [N1盒子] 斐讯盒子N1 T1通用刷机包(可救砖)
  • SpringBoot 整合 Langchain4j AIService 深度使用详解
  • Valgrind Helgrind 工具全解:线程同步的守门人
  • 编程语言Java——核心技术篇(五)IO流:数据洪流中的航道设计
  • JavaWeb(苍穹外卖)--学习笔记13(微信小程序开发,缓存菜品,Spring Cache)
  • Java中get()与set()方法深度解析:从封装原理到实战应用
  • 8. 状态模式
  • 零基础 “入坑” Java--- 十五、字符串String
  • 一场关于电商零售增长破局的深圳探索
  • 金融科技中的跨境支付、Open API、数字产品服务开发、变革管理
  • 【Ollama】大模型本地部署与 Java 项目调用指南
  • 字符串是数据结构还是数据类型?
  • 基于Prometheus+Grafana的分布式爬虫监控体系:构建企业级可观测性平台
  • Git Commit 生成与合入 Patch 指南
  • java--WebSocket简单介绍
  • 多模态视觉语言模型FILA-细粒度分辨率融合策略
  • [10月考试] B
  • Flutter 生命周期介绍