FreeRTOS消息队列

消息队列简介

队列是为了任务与任务、 任务与中断之间的通信而准备的, 可以在任务与任务、 任务与中断之间传递消息, 队列中可以存储有限的、 大小固定的数据项目。任务与任务、 任务与中断之间要交流的数据保存在队列中, 叫做队列项目。 队列所能保存的最大数据项目数量叫做队列的长度, 创建队列的时候会指定数据项目的大小和队列的长度。 由于队列用来传递消息的, 所以也称为消息队列。

消息队列数据存储

通常队列采用先进先出(FIFO)的存储缓冲机制, 也就是往队列发送数据的时候(也叫入队)永远都是发送到队列的尾部, 而从队列提取数据的时候(也叫出队)是从队列的头部提取的。 但是也可以使用 后进先出(LIFO) 的存储缓冲,FreeRTOS 中的队列也提供了 LIFO 的存储缓冲机制。

数据发送到队列中会导致数据拷贝, 也就是将要发送的数据拷贝到队列中,这就意味着在队列中存储的是数据的原始值, 而不是原数据的引用(即只传递数据的指针), 这个也叫做值传递。

采用值传递的话虽然会导致数据拷贝, 会浪费一点时间, 但是一旦将消息发送到队列中原始的数据缓冲区就可以删除掉或者覆写, 这样的话这些缓冲区就可以被重复的使用。 FreeRTOS 中使用队列传递消息的话虽然使用的是数据拷贝,但是也可以使用引用来传递消息, 直接往队列中发送指向这个消息的地址指针就可以了

消息队列阻塞机制

出队阻塞

当任务尝试从一个队列中读取消息的时候可以指定一个阻塞时间, 这个阻塞时间就是当任务从队列中读取消息无效的时候任务阻塞的时间。 出队就是从队列中读取消息, 出队阻塞是针对从队列中读取消息的任务而言的。

任务 A 用于处理串口接收到的数据, 串口接收到数据以后就会放到队列 Q 中, 任务 A 从队列 Q 中读取数据。 但是如果此时队列 Q 是空的, 说明还没有数据, 任务 A 这时候来读取的话肯定是获取不到任何东西, 那该怎么办呢?

三种选择

一: 二话不说扭头就走

阻塞时间为 0 的话就是不阻塞, 没有数据的话就马上返回任务继续执行接下来的代码

二: 要不我在等等吧, 等一会看看, 说不定一会就有数据了

如果阻塞时间为 0~ portMAX_DELAY 之间, 当任务没有从队列中获取到消息的话就进入阻塞态, 阻塞时间指定了任务进入阻塞态的时间, 当阻塞时间到了以后还没有接收到数据的话就退出阻塞态, 返回任务接着运行下面的代码, 如果在阻塞时间内接收到了数据就立即返回, 执行任务中下面的代码

三: 死等, 死也要等到你有数据

当阻塞时间设置为 portMAX_DELAY 的话, 任务就会一直进入阻塞态等待, 直到接收到数据为止

入队阻塞

入队说的是向队列中发送消息, 将消息加入到队列中。 和出队阻塞一样, 当一个任务向队列发送消息的话也可以设置阻塞时间。

消息队列操作示图

(1) 创建队列

图中任务 A 要向任务 B 发送消息, 这个消息是 x 变量的值。 首先创建一个队列, 并且指定队列的长度和每条消息的长度。 这里我们创建了一个长度为 4的队列, 因为要传递的是 x 值, 而 x 是个 int 类型的变量, 所以每条消息的长度就是 int 类型的长度, 在 STM32 中是 4 字节, 即每条消息是 4 个字节的。

(2) 向队列发送第一个消息

图中任务 A 的变量 x 值为 10, 将这个值发送到消息队列中。 此时队列剩余长度就是 3 了。 前面说了向队列中发送消息是采用拷贝的方式, 所以一旦消息发送完成变量 x 就可以再次被使用, 赋其他的值。

(3) 向队列发送第二个消息

图中任务 A 又向队列发送了一个消息, 即新的 x 的值, 这里是 20。 此时队列剩余长度为 2。

(4) 从队列中读取消息

图中任务 B 从队列中读取消息, 并将读取到的消息值赋值给 y, 这样 y 就等于 10 了。 任务 B 从队列中读取消息完成以后可以选择清除掉这个消息或者不清除。 当选择清除这个消息的话其他任务或中断就不能获取这个消息了, 而且队列剩余大小就会加一, 变成 3。 如果不清除的话其他任务或中断也可以获取这个消息, 而队列剩余大小依旧是 2。

消息队列控制块

FreeRTOS 的消息队列控制块由多个元素组成, 当消息队列被创建时, 系统会为控制块分配对应的内存空间, 用于保存消息队列的一些信息如消息的存储位置, 头指针pcHead、 尾指针 pcTail、 消息大小 uxItemSize 以及队列长度uxLength, 以及当前队列消息个数uxMessagesWaiting 等

typedef struct QueueDefinition
{
    int8_t *pcHead; (1)

    int8_t *pcTail; (2)

    int8_t *pcWriteTo; (3)

union
{
    int8_t *pcReadFrom; (4)

    UBaseType_t uxRecursiveCallCount; (5)

} u;
    List_t xTasksWaitingToSend; (6)

    List_t xTasksWaitingToReceive; (7)

    volatile UBaseType_t uxMessagesWaiting; (8)

    UBaseType_t uxLength; (9)

    UBaseType_t uxItemSize; (10)

    volatile int8_t cRxLock; (11)

    volatile int8_t cTxLock; (12)

#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) &&
    ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
    uint8_t ucStaticallyAllocated;
#endif

#if ( configUSE_QUEUE_SETS == 1 )
    struct QueueDefinition *pxQueueSetContainer;
#endif

#if ( configUSE_TRACE_FACILITY == 1 )
UBaseType_t uxQueueNumber;
uint8_t ucQueueType;
#endif
} xQUEUE;

typedef xQUEUE Queue_t;

代码(1): pcHead 指向队列消息存储区起始位置, 即第一个消息空间。
代码(2): pcTail 指向队列消息存储区结束位置地址。
代码(3): pcWriteTo 指向队列消息存储区下一个可用消息空间。
代码(4): pcReadFrom 与 uxRecursiveCallCount 是一对互斥变量, 使用联合体用来确保两个互斥的结构体成员不会同时出现。 当结构体用于队列时,pcReadFrom 指向出队消息空间的最后一个, 见文知义, 就是读取消息时候是从pcReadFrom 指向的空间读取消息内容。
代码(5): 当结构体用于互斥量时, uxRecursiveCallCount 用于计数, 记录递归互斥量被“调用” 的次数。
代码(6): xTasksWaitingToSend 是一个发送消息阻塞列表, 用于保存阻塞在此队列的任务, 任务按照优先级进行排序, 由于队列已满, 想要发送消息的任务无法发送消息。
代码(7): xTasksWaitingToReceive 是一个获取消息阻塞列表, 用于保存阻塞在此队列的任务, 任务按照优先级进行排序, 由于队列是空的, 想要获取消息的任务无法获取到消息。
代码(8): uxMessagesWaiting 用于记录当前消息队列的消息个数, 如果消息队列被用于信号量的时候, 这个值就表示有效信号量个数。
代码(9): uxLength 表示队列的长度, 也就是能存放多少消息。
代码(10): uxItemSize 表示单个消息的大小。
代码(11): 队列上锁后, 储存从队列收到的列表项数目, 也就是出队的数量,如果队列没有上锁, 设置为 queueUNLOCKED。

常用消息队列 API 函数

消息队列创建函数 

xQueueCreate()用于创建一个新的队列并返回可用于访问这个队列的队列句柄。 队列句柄其实就是一个指向队列数据结构类型的指针。

动态创建(常用)

静态创建

复位 

队列刚被创建时,里面没有数据;使用过程中可以调用 xQueueReset()把队列恢复为初始状态

删除

删除队列的函数为 vQueueDelete(),只能删除使用动态方法创建的队列,它会释放内存。

向消息队列发送消息函数

xQueueSend()用于向队列尾部发送一个队列消息。 消息以拷贝的形式入队,而不是以引用的形式。 该函数绝对不能在中断服务程序里面被调用, 中断中必须使用带有中断保护功能的QueueSendFrxomISR()来代替。

xQueueSendFromISR()是一个宏, 宏展开是调用函数xQueueGenericSendFromISR()。 该宏是 xQueueSend()的中断保护版本, 用于在中断服务程序中向队列尾部发送一个队列消息, 等价于
xQueueSendToBackFromISR()。


 

xQueueSendToFront()用于向队列队首发送一个消息。 消息以拷贝的形式入队,而不是以引用的形式。 该函数绝不能在中断服务程序里面被调用, 而是必须使用带有中断保护功能的 xQueueSendToFrontFromISR ()来代替。

xQueueSendToFrontFromISR()是一个宏, 宏展开是调用函数xQueueGenericSendFromISR()。 该宏是 xQueueSendToFront()的中断保护版本,用于在中断服务程序中向消息队列队首发送一个消息。

从消息队列读取消息函数

xQueueReceive()用于从一个队列中接收消息并把消息从队列中删除。 接收的消息是以拷贝的形式进行的, 所以我们必须提供一个足够大空间的缓冲区。 具体能够拷贝多少数据到缓冲区, 这个在队列创建的时候已经设定。 该函数绝不能在中断服务程序里面被调用, 而是必须使用带有中断保护功能的xQueueReceiveFromISR ()来代替。

如果不想删除消息的话, 就调用 xQueuePeek()函数

xQueueReceiveFromISR()是 xQueueReceive ()的中断版本, 用于在中断服务程序中接收一个队列消息并把消息从队列中删除;

xQueuePeekFromISR()是xQueuePeek()的中断版本, 用于在中断中从一个队列中接收消息, 但并不会把消息从队列中移除。


说白了这两个函数只能用于中断, 是不带有阻塞机制的, 并且是在中断中可以安全调用

消息队列使用注意事项

1.使用 xQueueSend()、 xQueueSendFromISR()、 xQueueReceive()等这些函数之前应先创建需消息队列, 并根据队列句柄进行操作。

2.队列读取采用的是先进先出(FIFO) 模式, 会先读取先存储在队列中的数据。 当然也 FreeRTOS 也支持后进先出(LIFO) 模式, 那么读取的时候就会读取到后进队列的数据。

3.在获取队列中的消息时候, 我们必须要定义一个存储读取数据的地方, 并且该数据区域大小不小于消息大小, 否则, 很可能引发地址非法的错误。

4.无论是发送或者是接收消息都是以拷贝的方式进行, 如果消息过于庞大,可以将消息的地址作为消息进行发送、 接收。

5.队列是具有自己独立权限的内核对象, 并不属于任何任务。 所有任务都可以向同一队列写入和读出。 一个队列由多任务或中断写入是经常的事, 但由多个任务读出倒是用的比较少。


 


 





 

 


 


 



 


 


 


 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【博士每天一篇文献-综述】Modularity in Deep Learning A Survey

阅读时间:2023-12-8 1 介绍 年份:2023 作者:孙浩哲,布朗克斯医疗卫生系统 会议: Science and Information Conference 引用量:4 论文主要探讨了深度学习中的模块化(modularity)概念…

ROS学习记录:C++节点发布自定义地图

前言 ROS栅格地图格式 在了解了ROS地图消息包的数据结构后(链接在上),本文将编写一个节点,发布地图消息包,看看在RViz中显示是什么效果。 一、准备 1、为了简单起见,发布一个两行四列的地图 2、为了便于观测,只对地…

沐风老师3DMAX一键多孔结构建模插件Porous使用方法

​3DMAX一键多孔结构建模插件Porous使用教程 3dMax是大家熟知的3D建模软件之一,其功能非常的强大,在科研绘图领域有着非常广泛的应用,但是由于科研绘图的图形(模型)一般都属于异形结构,手工绘制建模&#x…

Seq2seq、编码器解码器神经网络

目录 一、Seq2seq 简介二、编码器三、解码器四、编码器-解码器的训练 遇到看不明白的地方,欢迎在评论中留言呐,一起讨论,一起进步! 需掌握的前提知识: LSTM、词嵌入 本文参考:【官方双语】编码、解码神经网…

人类记忆优化算法:针对全局优化问题的记忆启发优化器

Human memory optimization algorithm: A memory-inspired optimizer for global optimization problems 24年 Expert Systems With Applications sci一区 原文链接: https://doi.org/10.1016/j.eswa.2023.121597 Zhu D, Wang S, Zhou C, et al. Human memory optimization alg…

【机器学习】GPT-4中的机器学习如何塑造人类与AI的新对话

🚀时空传送门 🔍引言📕GPT-4概述🌹机器学习在GPT-4中的应用🚆文本生成与摘要🎈文献综述与知识图谱构建🚲情感分析与文本分类🚀搜索引擎优化💴智能客服与虚拟助手&#x1…

Web--CSS基础

文章目录 定义方式选择器文本字体背景边框元素展示格式内边距与外边距盒子模型位置浮动flex布局响应式布局 定义方式 行内样式表 直接定义在style属性中&#xff0c;作用于当前标签 <img src "/imges/logo.jpg" alt "" style "width 400"…

时钟影响ADC性能不仅仅是抖动

时钟影响ADC性能除了抖动&#xff0c;还有占空比。 在高速AD采样中&#xff0c;时钟占空比是非常重要的一个参数。时钟信号的上升沿控制ADC的采样&#xff0c;而下降沿控制着信号的保持&#xff0c;在一个周期内才可以完成量化输出&#xff0c;所以必须保持时钟的占空比为50%&…

自动化决策和业务流程类控制的系统前端UI设计开发

自动化决策和业务流程类控制的系统前端UI设计开发

NLP——电影评论情感分析

python-tensorflow2.0 numpy 1.19.1 tensorflow 2.0.0 导入库 数据加载 数据处理 构建模型 训练 评估 预测 1.基于2层dropout神经网络 2.基于LSTM的网络 #导入需要用到的库 import os import tarfile import urllib. request import tensorflow as tf import numpy a…

使用Python批量处理Excel的内容

正文共&#xff1a;1500 字 10 图&#xff0c;预估阅读时间&#xff1a;1 分钟 在前面的文章中&#xff08;如何使用Python提取Excel中固定单元格的内容&#xff09;&#xff0c;我们介绍了如何安装Python环境和PyCharm工具&#xff0c;还利用搭好的环境简单测试了一下ChatGPT提…

小程序名片怎么生成?AI名片生成器源码系统 为企业店铺创建自己的数字名片

在数字化时代&#xff0c;小程序名片已经成为企业店铺展示自身形象、推广产品和服务的重要工具。分享一个AI名片生成器源码系统春哥AI雷达智能名片小程序系统企业商业运营版&#xff0c;含完整代码包和详细的图文安装部署搭建教程&#xff0c;新手也能轻松使用&#xff0c;源码…

MySQL: 索引与事务

文章目录 1. 索引 (Index)1.1 概念1.2 作用1.3 使用场景1.4 索引的使用1.5 索引的使用案例 (不要轻易尝试)1.6 索引背后的数据结构1.7 重点总结 2.事务2.1 为什么要使用事务2.2 事务的概念2.3 事务的使用2.4 对事务的理解2.5 事务的基本特性 1. 索引 (Index) 1.1 概念 索引是…

Python Requests库详解

大家好&#xff0c;在现代网络开发中&#xff0c;与Web服务器进行通信是一项至关重要的任务。Python作为一种多才多艺的编程语言&#xff0c;提供了各种工具和库来简化这一过程。其中&#xff0c;Requests库作为Python中最受欢迎的HTTP库之一&#xff0c;为开发人员提供了简单而…

12-Gateway网关-网关作用介绍

12-Gateway网关-网关作用介绍 1.为什么需要网关&#xff1a; 网关功能&#xff1a; ​ 1.身份认证和权限校验 ​ 2.服务路由、负载均衡 ​ 3.请求限流 2.网关的技术实现&#xff1a; 在SpringCloud中网关的实现包括两种“ ​ gateway ​ zuul Zuul是基于Servlet的实…

node-mysql的批量插入

此前我批量插入都是用类似这样的命令&#xff1a; sqlcmdinsert into table(field1,field2,...) values ? indata[["f1v1","f2v1"],["f1v2","f2v2"],...] mysqlconn.query(sqlcmd,[indata],(err,res)>{...})但是感觉不太舒服&…

VueRouter3学习笔记

文章目录 1&#xff0c;入门案例2&#xff0c;一些细节高亮效果非当前路由会被销毁 3&#xff0c;嵌套路由4&#xff0c; 传递查询参数5&#xff0c;命名路由6&#xff0c;传递路径参数7&#xff0c;路径参数转props8&#xff0c;查询参数转props9&#xff0c;replace模式10&am…

Vue--》从零开始打造交互体验一流的电商平台(二)

今天开始使用 vue3 + ts 搭建一个电商项目平台,因为文章会将项目的每处代码的书写都会讲解到,所以本项目会分成好几篇文章进行讲解,我会在最后一篇文章中会将项目代码开源到我的github上,大家可以自行去进行下载运行,希望本文章对有帮助的朋友们能多多关注本专栏,学习更多…

SAP Build 1-工作流表单开发

1. BTP SAP Build环境配置 1.1 启用试用账号 访问BTP trial&#xff0c;启用试用账号&#xff0c;没有的话注册一个即可 https://account.hanatrial.ondemand.com/trial/#/home/trial 注册完之后就会让选择区域&#xff0c;要选US的区域才有自动化相关的功能 然后就开始生成…

什么是Java?

什么是Java&#xff1f;java是什么&#xff1f;下面我们来总结一下。 java是什么&#xff1f; java是一个静态编程语言&#xff0c;具有强大的多线程特征&#xff0c;目前java不仅采用c语言的优点&#xff0c;还去掉了一些多继承指针&#xff0c;等复杂的概念&#xff0c;我们…