当前位置: 首页 > 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.lryc.cn/news/601891.html

相关文章:

  • 使用低级上位画图法理解在对磁盘空间进行容量分配时【低级单位上位至高级单位的换算】
  • Mybatis Plus 多数据源
  • AI时代,我们更需要自己的开发方式与平台
  • Coze Studio概览(一)
  • 链表算法常用技巧与操作
  • 通过硬编码函数地址并转换为函数指针来调用函数
  • 【Agentic】通过LangGrah实现RAG评分和重写
  • 清华大学具身智能多传感器融合感知综述:背景、方法、挑战与展望
  • Flutter开发实战之CI/CD与发布流程
  • 网易大模型算法岗面经80道
  • JSON格式化与结构对比
  • 移植pbrt中的并行化到ray trace in weeks中
  • LangGraph底层API入门总结
  • OpenLayers 综合案例-地图绘制
  • 十字链表以及实现
  • SpringAI入门及浅实践,实战 Spring‎ AI 调用大模型、提示词工程、对话记忆、Adv‎isor 的使用
  • 第五章 中央处理器(CPU)知识体系与考法总结
  • 【第六节】方法与事件处理器
  • Gradle#Plugin
  • Windows---动态链接库Dynamic Link Library(.dll)
  • 2025.7.27总结—新励成
  • Kubernetes 核心组件解析
  • HCIE学习之路:MSTP实现负载均衡实验
  • 【INT范围提取字符串数字为正数】2022-8-29
  • Leetcode 3628. Maximum Number of Subsequences After One Inserting
  • rust- 定义模块以控制作用域和隐私
  • 握手未来,PostgreSQL认证专家
  • 【I】题目解析
  • Spring AI 学习笔记
  • 小架构step系列27:Hibernate提供的validator