FreeRTOS学习笔记(六)队列
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- 前言
- 一、队列的基本内容
- 1.1 队列的引入
- 1.2 FreeRTOS 队列的功能与作用
- 1.3 队列的结构体
- 1.4 队列的使用流程
- 二、相关API详解
- 2.1 xQueueCreate
- 2.2 xQueueSend
- 2.3 xQueueReceive
- 2.4 xQueueSendFromISR
- 2.5 xQueueReceiveFromISR
- 2.6 uxQueueMessagesWaiting
- 2.7 uxQueueSpacesAvailable
- 2.8 vQueueDelete
前言
队列(Queue) 是一种用于任务间通信和同步的重要机制。它允许不同任务或者中断服务例程之间交换数据,而无需直接共享变量。这种机制不仅确保数据在任务之间传递的安全性,还解决了多任务系统中的并发和同步问题。
一、队列的基本内容
1.1 队列的引入
在以前的代码中,如果我们想让一个变量在不同函数中进行传递操作,下意识可能会想到全局变量,但是这种方式存在一个问题:当我们使用freertos时,低优先级的任务会被高优先级的任务打断,这意味着可能会导致变量的结果不可控。为了解决这个问题,我们引入了队列,他自带临界保护,我们只要进行相关的API操作即可。在队列中可以存储固定大小且有限的数据,其中每一个数据叫“队列项目”,而所能存储的最大“队列项目”的数量称为队列的长度。除了可以被多任务访问之外,队列还有以下的特性:
- FreeRTOS 中的队列是先进先出的结构,即最先插入队列的数据会最先被读取;
- 队列的长度和每个队列项的大小在创建时由用户指定;
- FreeRTOS 提供了阻塞模式和非阻塞模式的队列操作。如果任务需要立即返回,可以使用超时为 0 的非阻塞模式;如果任务愿意等待队列有空位或数据,可以设置阻塞时间(如 0~portMAX_DELAY)让任务进入阻塞状态;
- FreeRTOS 中的队列在数据传递时通常会直接拷贝数据进行实值传输,当然也可以传递指针。
1.2 FreeRTOS 队列的功能与作用
- 任务间通信:FreeRTOS 的队列可以让多个任务之间安全地传递数据。例如,一个任务可以向队列发送数据,另一个任务从队列读取数据。这使得不同任务之间可以高效地共享信息,而不需要频繁访问全局变量。
- 任务与中断间通信:队列不仅适用于任务间通信,还适用于中断和任务之间的通信。FreeRTOS 提供了特定的 ISR(中断服务例程)函数,比如 xQueueSendFromISR() 和 xQueueReceiveFromISR(),可以让中断处理函数安全地与任务交换数据。
- 同步与调度:当一个任务尝试从空队列中读取数据时,任务可以选择进入阻塞状态,直到有数据可读。当另一个任务或中断向队列中发送数据时,等待的任务会被唤醒并立即处理数据。这样,队列不仅传递数据,还能用作同步机制,协调任务间的执行顺序。
- 队列引发的任务切换: 在 FreeRTOS 中,如果一个任务向队列发送数据,并唤醒了一个更高优先级的任务,该任务会立刻抢占当前任务进行执行。这使得队列不仅用于数据交换,还起到了一定的任务调度作用。
1.3 队列的结构体
在 FreeRTOS 中,队列是通过一个结构体来实现的。虽然具体实现可能根据不同平台有所调整,但通常队列的结构体包含了队列长度、队列项大小、存储数据的缓冲区指针、队列的头尾指针、队列的同步机制(如等待队列的任务列表)等信息。在 FreeRTOS 的源码中,定义队列的结构体一般为 QueueDefinition,其在 queue.c 中实现,通常通过类型定义 QueueHandle_t 来间接引用该结构体。
struct QueueDefinition
{int8_t *pcHead; /* 指向队列存储区的指针(队列缓冲区的头部) */int8_t *pcTail; /* 指向队列存储区的尾部 */int8_t *pcWriteTo; /* 指向队列中下一个写入位置 */int8_t *pcReadFrom; /* 指向队列中下一个读取位置 */UBaseType_t uxMessagesWaiting; /* 队列中的消息数 */UBaseType_t uxLength; /* 队列的长度(队列项的最大数量) */UBaseType_t uxItemSize; /* 每个队列项的大小(以字节为单位) */TaskHandle_t xTasksWaitingToSend; /* 等待发送的任务列表 */TaskHandle_t xTasksWaitingToReceive;/* 等待接收的任务列表 *//* 下面的成员用于同步多任务或中断访问队列 */BaseType_t xRxLock; /* 接收锁,用于控制接收操作 */BaseType_t xTxLock; /* 发送锁,用于控制发送操作 *//* Mutexes 和 Semaphores 使用的额外信息 */UBaseType_t uxQueueType; /* 队列的类型(普通队列、互斥量、信号量等) */...
} xQUEQUE;
值得一提的是,这个结构体中还包含了一个联合体,它的作用是允许 QueueDefinition 结构体根据队列类型的不同(普通消息队列、信号量、互斥量)共享不同的结构。具体而言:对于普通的消息队列,队列用 xQueue 这个结构来管理等待发送和等待接收的任务列表;对于互斥量,队列使用 xMutex 这个结构来管理递归计数和互斥量的持有者。通过这个联合体,队列的结构体可以根据不同的队列类型选择不同的字段来使用,从而节省内存,并让队列既能处理消息队列,也能处理信号量和互斥量。
/* 通过联合体实现不同类型队列的支持 */union{/* 用于消息队列和信号量 */struct{UBaseType_t uxRecursiveCallCount; /* 递归互斥量使用时的递归计数 */TaskHandle_t xMutexHolder; /* 持有互斥量的任务句柄 */} xMutex;/* 用于普通队列 */struct{List_t xTasksWaitingToSend; /* 等待发送的任务列表 */List_t xTasksWaitingToReceive; /* 等待接收的任务列表 */} xQueue;} u; /* 联合体名称 */
参数说明:
- uxRecursiveCallCount 用于递归互斥量的递归调用计数,这样持有互斥量的任务可以多次锁定互斥量。
- xMutexHolder 用于保存当前持有互斥量的任务句柄。
1.4 队列的使用流程
- 创建队列:可以指定队列的长度和每个队列项的大小(例如,传递一个整数,结构体,或者更复杂的数据)。
- 向队列发送数据:一个任务可以使用 xQueueSend() 或 xQueueSendToBack() 向队列中发送数据,如果队列已满,任务可以选择进入阻塞状态,直到队列有空位,或者直接返回发送失败。
- 从队列读取数据:任务可以使用 xQueueReceive() 从队列中读取数据,如果队列为空,任务可以选择阻塞,直到有数据可读取。
- 中断安全的队列操作:如果队列操作发生在中断服务例程中,FreeRTOS 提供了 xQueueSendFromISR() 和 xQueueReceiveFromISR() 等函数,以确保队列操作的线程安全。
二、相关API详解
FreeRTOS 提供了丰富的队列相关 API,用于在任务之间或中断和任务之间传递数据,进行任务同步。队列机制是 FreeRTOS 中最常用的 IPC(进程间通信)工具之一。以下是一些常用的队列 API 及其功能介绍:
2.1 xQueueCreate
// 功能:创建一个新的队列,并返回该队列的句柄。
QueueHandle_t xQueueCreate(UBaseType_t uxQueueLength, UBaseType_t uxItemSize);
- 参数:
- uxQueueLength:队列中可以容纳的最大数据项数
- uxItemSize:每个队列项的大小(以字节为单位)
- 返回值:
- 成功:队列句柄
- 失败:NULL
这里简单提一下,xQueueCreate的实现是调用了xQueueGenericCreate这个的底层函数,所有的队列(包括普通队列、信号量、互斥量)都通过这个函数创建。通常我们不会直接调用 xQueueGenericCreate,而是使用更高层的 API,如 xQueueCreate、xSemaphoreCreate 等。
QueueHandle_t xQueueGenericCreate(UBaseType_t uxQueueLength, UBaseType_t uxItemSize, uint8_t ucQueueType);
- 参数说明
- uxQueueLength:队列的长度,即队列中可以容纳的最大数据项数。
- uxItemSize:每个队列项的大小(以字节为单位)。如果创建的是信号量或互斥量,这个值为 0。
- ucQueueType:队列的类型,常见的类型有:
- queueQUEUE_TYPE_BASE:普通队列
- queueQUEUE_TYPE_SET:队列集
- queueQUEUE_TYPE_MUTEX:互斥量
- queueQUEUE_TYPE_BINARY_SEMAPHORE:二元信号量
- queueQUEUE_TYPE_COUNTING_SEMAPHORE:计数信号量
- 返回值
- 成功:创建的队列的句柄
- 失败:返回 NULL
2.2 xQueueSend
// 功能 :将一个项目发送到队列中,如果队列满,任务将阻塞直到有空间可用或超时(不可应用于中断)
BaseType_t xQueueSend(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait);
- 参数:
- xQueue:队列的句柄
- pvItemToQueue:指向要放入队列的数据项的指针
- xTicksToWait:如果队列满,任务等待插入的时间(以 Tick 数表示),portMAX_DELAY 表示无限等待
- 返回值:
- 成功:pdPASS
- 失败:errQUEUE_FULL(队列已满)
2.3 xQueueReceive
// 功能:从队列中接收一个项目,如果队列为空,任务将阻塞直到有数据可用或超时。
BaseType_t xQueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait);
- 参数:
- xQueue:队列的句柄
- pvBuffer:指向接收数据项的缓冲区
- xTicksToWait:如果队列为空,任务等待接收的时间(以 Tick 数表示),portMAX_DELAY 表示无限等待
- 返回值:
- 成功:pdPASS
- 失败:errQUEUE_EMPTY(队列为空)
2.4 xQueueSendFromISR
// 功能:从中断服务例程(ISR)中向队列发送数据,与 xQueueSend 类似,但适用于中断上下文。
BaseType_t xQueueSendFromISR(QueueHandle_t xQueue, const void *pvItemToQueue, BaseType_t *pxHigherPriorityTaskWoken);
- 参数:
- xQueue:队列的句柄
- pvItemToQueue:指向要放入队列的数据项的指针
- pxHigherPriorityTaskWoken:如果发送数据后需要进行任务切换,设置为 pdTRUE
- 返回值:
- 成功:pdPASS
- 失败: errQUEUE_FULL
2.5 xQueueReceiveFromISR
// 功能:从中断服务例程(ISR)中接收队列数据。与 xQueueReceive 类似,但适用于中断上下文。
BaseType_t xQueueReceiveFromISR(QueueHandle_t xQueue, void *pvBuffer, BaseType_t *pxHigherPriorityTaskWoken);
- 参数:
- xQueue:队列的句柄。
- pvBuffer:指向接收数据项的缓冲区。
- pxHigherPriorityTaskWoken:如果接收数据后需要进行任务切换,设置为 pdTRUE。
- 返回值:
- 成功:pdPASS
- 失败:errQUEUE_EMPTY
2.6 uxQueueMessagesWaiting
// 功能:返回队列中当前存储的消息数。
UBaseType_t uxQueueMessagesWaiting(QueueHandle_t xQueue);
- 参数:
- xQueue:队列的句柄
- 返回值:队列中已存储的消息数
2.7 uxQueueSpacesAvailable
// 功能:返回队列中剩余可用的空间数。
UBaseType_t uxQueueSpacesAvailable(QueueHandle_t xQueue);
- 参数:
- xQueue:队列的句柄。
- 返回值:队列中剩余的可用空间数量
2.8 vQueueDelete
// 功能:删除队列并释放其占用的内存。
void vQueueDelete(QueueHandle_t xQueue);
- 参数:
- xQueue:要删除的队列句柄
免责声明:本文参考了网上公开资料,仅用于学习交流,若有错误或侵权请联系笔者。
相关文章:

FreeRTOS学习笔记(六)队列
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、队列的基本内容1.1 队列的引入1.2 FreeRTOS 队列的功能与作用1.3 队列的结构体1.4 队列的使用流程 二、相关API详解2.1 xQueueCreate2.2 xQueueSend2.3 xQu…...

【Python篇】PyQt5 超详细教程——由入门到精通(中篇一)
文章目录 PyQt5入门级超详细教程前言第4部分:事件处理与信号槽机制4.1 什么是信号与槽?4.2 信号与槽的基本用法4.3 信号与槽的基础示例代码详解: 4.4 处理不同的信号代码详解: 4.5 自定义信号与槽代码详解: 4.6 信号槽…...

LinuxQt下的一些坑之一
我们在使用Qt开发时,经常会遇到Windows上应用正常,但到Linux嵌入式下就会出现莫名奇妙的问题。这篇文章就举例分析下: 1.QPushButton按钮外侧虚线框问题 Windows下QPushButton按钮设置样式正常,但到了Linux下就会有一个虚线边框。…...

Statement batch
我们可以看到 Statement 和 PreparedStatement 为我们提供的批次执行 sql 操作 JDBC 引入上述 batch 功能的主要目的,是加快对客户端SQL的执行和响应速度,并进而提高数据库整体并发度,而 jdbc batch 能够提高对客户端SQL的执行和响应速度,其…...

PPP 、PPPoE 浅析和配置示例
一、名词: PPP: Point to Point Protocol 点到点协议 LCP:Link Control Protocol 链路控制协议 NCP:Network Control Protocol 网络控制协议,对于上层协议的支持,N 可以为IPv4、IPv6…...

【Python机器学习】词向量推理——词向量
目录 面向向量的推理 使用词向量的更多原因 如何计算Word2vec表示 skip-gram方法 什么是softmax 神经网络如何学习向量表示 用线性代数检索词向量 连续词袋方法 skip-gram和CBOW:什么时候用哪种方法 word2vec计算技巧 高频2-gram 高频词条降采样 负采样…...

Python 语法糖:让编程更简单(续二)
Python 语法糖:让编程更简单(续) 10. Type hints Type hints 是 Python 中的一种语法糖,用于指定函数或变量的类型。例如: def greet(name: str) -> None:print(f"Hello, {name}!")这段代码将定义一个…...

6 - Shell编程之sed与awk编辑器
目录 一、sed 1.概述 2.sed命令格式 3.常用操作的语法演示 3.1 输出符合条件的文本 3.2 删除符合条件的文本 3.3 替换符合条件的文本 3.4 插入新行 二、awk 1.概述 2. awk命令格式 3.awk工作过程 4.awk内置变量 5.awk用法示例 5.1 按行输出文本 5.2 按字段输出文…...

什么是XML文件,以及如何打开和转换为其他文件格式
本文描述了什么是XML文件以及它们在哪里使用,哪些程序可以打开XML文件,以及如何将XML文件转换为另一种基于文本的格式,如JSON、PDF或CSV。 什么是XML文件 XML文件是一种可扩展标记语言文件。它们是纯文本文件,除了描述数据的传输、结构和存储外,本身什么也不做。 RSS提…...

海外直播对网速、带宽、安全的要求
要满足海外直播的要求,需要拥有合适的网络配置。在全球化的浪潮下,海外直播正逐渐成为企业、个人和各类组织的重要工具。不论是用于市场推广、品牌宣传,还是与观众互动,海外直播都为参与者带来了丰富的机会。然而,确保…...

UWB定位室外基站
定位基站,型号SW,是一款基于无线脉冲技术开发的UWB定位基站,基站可用于人员、车辆、物资的精确定位, 该基站专为恶劣环境使用而设计,防尘、防水等级IP67,工业级标准支持365天连续运行,本安防爆可…...

高斯平面直角坐标讲解,以及地理坐标转换高斯平面直角坐标
高斯平面直角坐标系(Gauss-Krger 坐标系)是基于 高斯-克吕格投影 的一种常见的平面坐标系统,主要用于地理信息系统 (GIS)、测绘和工程等领域。该坐标系将地球表面的经纬度(地理坐标)通过一种投影方式转换为平面直角坐标,以便在二维平面中进行距离、面积和角度的计算。 一…...

C++入门(06)安装QT并快速测试体验一个简单的C++GUI项目
文章目录 1. 清华镜像源下载2. 安装3. 开始菜单上的 QT 工具4. 打开 Qt Creator5. 简单的 GUI C 项目5.1 打开 Qt Creator 并创建新项目5.2 设计界面5.3 添加按钮的点击事件5.4 编译并运行项目 6. 信号和槽(Signals and Slots) 这里用到了C类与对象的很多…...

一篇文章告诉你小程序为什么最近这么火?
微信小程序之所以最近这么火,主要得益于其低成本获取高流量、线上线下流量互换、社交裂变引爆流量以及封闭商业生态闭环等优势。下面将详细探讨小程序火爆的多个原因: 一篇文章告诉你小程序为什么这么火爆? 低成本获取高流量 无需安装注册&…...

Qt-常用控件(3)-多元素控件、容器类控件和布局管理器
1. 多元素控件 Qt 中提供的多元素控件有: QListWidgetQListViewQTableWidgetQTableViewQTreeWidgetQTreeView xxWidget 和 xxView 之间的区别,以 QTableWidget 和 QTableView 为例. QTableView 是基于 MVC 设计的控件.QTableView 自身不持有数据,使用 QTableView 的…...

【系统设计】主动查询与主动推送:如何选择合适的数据传输策略
基本描述总结 主动查询机制:系统A主动向系统B请求数据,采用严格的权限控制和身份认证,防止未授权的数据访问。数据在传输过程中使用TLS加密,并通过动态脱敏处理隐藏敏感信息。 推送机制:系统B在数据更新时主动向系统…...

mac 安装brew并配置国内源
前置条件 - Xcode 命令行工具 一行代码安装Homebrew 添加到路径(PATH) - zsh shell为例 背景介绍 最近重装了我的MAC mini (m1 芯片), 很多软件都需要重新安装,因为后续还需要安装一些软件,所以想着安装个包管理软件 什么…...

Temu官方宣导务必将所有的点位材料进行检测-RSL资质检测
关于饰品类产品合规问题宣导: 产品法规RSL要求 RSL测试是根据REACH法规及附录17的要求进行测试。REACH法规是欧洲一项重要的法规,其中包含许多对化学物质进行限制的规定和高度关注物质。 为了确保珠宝首饰的安全性,欧盟REACH法规规定&#…...

mysql高级sql
文章目录 一,查询1.按关键字排序1.1按关键字排序操作(1)按分数排序查询(不加asc默认为升序)(2)按分数降序查询(DESC)(3)使用where进行条件查询(4)使用ORDER BY语句对多个字段排序 1.2使用区间判断查询(and/…...

Linux CentOS 7.9 安装mysql8
1、新建mysql文件夹 数据比较大,所以我在服务器另外挂了一个盘装mysql,和默认安装一个道理,换路径即可 cd ../ //创建文件夹 mkdir mysql //进入mysql文件夹 cd mysql 2、下载mysql8.0安装包并解压、重命名 //下载安装包 wget https://dev…...

替代 Django 默认 User 模型并使用 `django-mysql` 添加数据库备注20240904
替代 Django 默认 User 模型并使用 django-mysql 添加数据库备注 前言 在 Django 项目开发中,默认的 User 模型虽然能够满足许多基础需求,但在实际项目中我们常常需要对用户模型进行定制化。通过覆盖默认的 User 模型,我们可以根据具体的业…...

三维激光扫描点云配准外业棋盘的布设与棋盘坐标测量
文章目录 一、棋盘标定板准备二、棋盘标定板布设三、棋盘标定板坐标测量一、棋盘标定板准备 三维激光扫描棋盘是用来校准和校正激光扫描仪的重要工具,主要用于提高扫描精度。棋盘标定板通常具有以下特点: 高对比度图案:通常是黑白相间的棋盘格,便于识别。已知尺寸:每个格…...

【Python知识宝库】文件操作:读写文件的最佳实践
🎬 鸽芷咕:个人主页 🔥 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想,就是为了理想的生活! 文章目录 前言一、文件读取1. 使用open函数2. 逐行读取3. 使用readlines和readline 二、文件写入1. 写入文本2. 追加内容3. 写入…...

Chapter 13 普通组件的注册使用
欢迎大家订阅【Vue2Vue3】入门到实践 专栏,开启你的 Vue 学习之旅! 文章目录 前言一、组件创建二、局部注册三、全局注册 前言 在 Vue.js 中,组件是构建应用程序的基本单元。本章详细讲解了注册和使用 Vue 的普通组件的两种方式:…...

u盘显示需要格式化才能用预警下的数据拯救恢复指南
U盘困境:需要格式化的紧急应对 在数字信息爆炸的时代,U盘作为便携的数据存储介质,承载着我们工作、学习乃至生活中的大量重要资料。然而,当U盘突然弹出“需要格式化才能用”的提示时,这份便捷瞬间转化为焦虑与不安。这…...

还不懂BIO,NIO,AIO吗
BIO(Blocking I/O)、NIO(Non-blocking I/O)和 AIO(Asynchronous I/O)是 Java 中三种不同的 I/O 模型,主要用于处理输入 / 输出操作。 一、BIO(Blocking I/O) 定义与工作原…...

物联网——DMA+AD多通道
DMA简介 存储器映像 某些数据在运行时不会发生变化,则设置为常量,存在Flash存储器中,节省运行内存的空间 DMA结构图 DMA访问权限高于cpu 结构要素 软件触发源:存储器到存储器传输完成后,计数器清零 硬件触发源&…...

Vue 中 watch 和 watchEffect 的区别
watch 和 watcheffect 都是 vue 中用于监视响应式数据的 api,它们的区别在于:watch 用于监视特定响应式属性并执行回调函数。watcheffect 用于更通用的响应式数据监视,但回调函数中不能更新响应式数据。Vue 中 watch 和 watchEffect 的区别 …...

pip install pyaudio sounddevice error: externally-managed-environment
shgbitaishgbitai-C9X299-PGF:~/pythonworkspace/ai-accompany$ pip install pyaudio sounddevice error: externally-managed-environment This environment is externally managed ╰─> To install Python packages system-wide, try apt installpython3-xyz, where xyz …...

HTML 转 PDF API 接口
HTML 转 PDF API 接口 网络工具 / 文件处理 支持网页转 PDF 高效生成 PDF / 提供永久链接。 1. 产品功能 超高性能转换效率;支持将传递的 HTML 转换为 PDF,支持转换 HTML 中的 CSS 格式;支持传递网站 URL,直接转换页面成对应的 …...