FreeRTOS(消息队列)

 资料来源于硬件家园:资料汇总 - FreeRTOS实时操作系统课程(多任务管理)

目录

一、消息队列的基本概念

1、消息队列的基本概念

2、消息队列的通信机制

3、FreeRTOS中消息队列特性

4、消息队列应用场景

二、消息队列常用API

1、使用消息队列的典型流程

三、消息队列创建与删除

1、消息队列控制块(句柄)

2、队列创建

3、队列删除

四、任务与中断中消息队列发送与接收

1、任务中消息队列发送

2、中断中消息队列发送

3、任务中消息队列接收


一、消息队列的基本概念

1、消息队列的基本概念

消息队列简称队列,是一种常用于任务间通信的数据结构。消息队列可以在任务与任务间、中断与任务间传递消息,实现任务接收来自其它任务或中断的不固定长度的消息。 

相比于裸机的全局数组,使用消息队列有如下优势

①消息队列具有超时机制,可以让 FreeRTOS 内核有效地管理任务

② 使用消息队列可以防止多任务的访问冲突

③ 使用消息队列可以有效地解决中断服务程序与任务之间消息传递的问题,使用全局数组的话,任务得不断去监测标志位以获取数据

④消息队列具有FIFO与LIFO储存机制,方便处理数据

2、消息队列的通信机制

消息队列是一种异步的通信方式。任务能够从队列中读取消息,当队列中的消息为空时,读取消息的任务将被阻塞。用户可以指定阻塞的任务时间 xTicksToWait,在这段时间中,如果队列为空,该任务将保持阻塞状态以等待队列数据有效。当队列中有新消息时,被阻塞的任务会被唤醒并处理新消息;当等待的时间超过指定的阻塞时间,即使队列中没有有效数据,任务也会自动从阻塞态转为就绪态。通过消息队列服务,任务或中断服务可以将一条或多条消息放入消息队列中。同样,一个或多个任务可以从消息队列中获得消息。当有多个消息发送到消息队列时,通常是将先进入消息队列的消息先传给任务,也就是说,任务先得到的是最先进入消息队列的消息,即先进先出原则(FIFO),FreeRTOS的队列也支持后进先出原则(LIFO)。

3、FreeRTOS中消息队列特性

①消息支持先进先出方式排队,支持异步读写工作方式

②读写队列均支持超时机制

③消息支持后进先出方式排队,向队首发送消息(LIFO)

④可以允许不同长度(不超过队列节点最大值)的任意类型消息

⑤一个任务能够从任意一个消息队列接收和发送消息

⑥多个任务能够从同一个消息队列接收和发送消息

⑦当队列使用结束后,可以通过删除队列函数进行删除

4、消息队列应用场景

消息队列可用于发送不定长消息的场合。队列是FreeRTOS 主要的任务间通信方式,可以在任务与任务间、中断和任务间传送信息,发送到队列的消息是通过复制方式实现的,这意味着队列存储的数据是原始数据,而不是原始数据的引用。

二、消息队列常用API

1、使用消息队列的典型流程

①创建消息队列 :xQueueCreate() 

②发送消息队列 :xQueueSend() 与 xQueueSendFromISR()

③读取消息队列 :xQueueReceive()

④删除消息队列:vQueueDelete()

三、消息队列创建与删除

1、消息队列控制块(句柄)

2、队列创建

函数原型:

QueueHandle_t xQueueCreate( UBaseType_t uxQueueLength, //队列长度消息个数 

                                UBaseType_t uxItemSize ); //类目大小,即消息大小,单位字节

函数描述:函数 xQueueCreate 用于创建消息队列

①第 1 个参数是消息队列支持的消息个数

②第 2 个参数是每个消息的大小,单位字节

③返回值,如果创建成功会返回消息队列的句柄,如果由于 FreeRTOSConfig.h 文件中 heap 大小不足,无法为此消息队列提供所需的空间会返回 NULL

应用:

/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */
osThreadId KEY1Handle;//定义队列变量
static QueueHandle_t xQueue=NULL;
static QueueHandle_t xQueue1=NULL;/* USER CODE END Variables */
  /* USER CODE BEGIN RTOS_QUEUES *//* add queues, ... */xQueue=xQueueCreate(1,4);if(xQueue==NULL)HAL_UART_Transmit(&huart2,(uint8_t*)"Create xQueue error... \r\n", 27, HAL_MAX_DELAY);elseHAL_UART_Transmit(&huart2,(uint8_t*)"Create xQueue success... \r\n", 29, HAL_MAX_DELAY);xQueue1=xQueueCreate(2,16);if(xQueue1==NULL)HAL_UART_Transmit(&huart2,(uint8_t*)"Create xQueue1 error... \r\n", 28, HAL_MAX_DELAY);elseHAL_UART_Transmit(&huart2,(uint8_t*)"Create xQueue1 success... \r\n", 30, HAL_MAX_DELAY);/* USER CODE END RTOS_QUEUES */

3、队列删除

函数原型:void vQueueDelete( QueueHandle_t xQueue); //队列句柄 

函数描述:

①函数 vQueueDelete 用于删除消息队列

②第 1 个参数是需要删除的消息队列句柄

注意:消息队列删除后,系统会清空此队列的全部消息,且不能再次使用此队列。  

四、任务与中断中消息队列发送与接收

1、任务中消息队列发送

函数原型:BaseType_t xQueueSend( QueueHandle_t xQueue, /* 消息队列句柄 */ 

                    const void * pvItemToQueue, /* 要传递数据地址 */ 

                    TickType_t xTicksToWait /* 等待消息队列有空间的最大等待时间 */ );

函数描述:函数 xQueueSend 用于任务中消息发送。 

① 第 1 个参数是消息队列句柄

② 第 2 个参数要传递数据地址,每次发送都是将消息队列创建函数 xQueueCreate 所指定的单个消息大 小复制到消息队列空间中

③ 第 3 个参数是当消息队列已经满时,等待消息队列有空间时的最大等待时间,单位系统时钟节拍

④ 返回值,如果消息成功发送返回 pdTRUE,否则返回 errQUEUE_FULL

使用这个函数要注意以下问题:

1. FreeRTOS 的消息传递是数据的复制,而不是传递的数据地址。

2. 此函数是用于任务代码中调用的,故不可以在中断服务程序中调用此函数,中断服务程序中使用的是xQueueSendFromISR。

3. 如果消息队列已经满且第三个参数为 0,那么此函数会立即返回。

4. 如果用户将 FreeRTOSConfig.h 文件中的宏定义 INCLUDE_vTaskSuspend 配置为 1 且第三个参数配置为 portMAX_DELAY,那么此发送函数会永久等待直到消息队列有空间可以使用。

5. 消息队列还有两个函数 xQueueSendToBack 和 xQueueSendToFront,函数 xQueueSendToBack实现的是 FIFO 方式的存取,函数 xQueueSendToFront 实现的是 LIFO 方式的读写。我们这里说的函数 xQueueSend 等效于 xQueueSendToBack,即实现的是 FIFO 方式的存取。

2、中断中消息队列发送

函数原型:BaseType_t xQueueSendFromISR ( QueueHandle_t xQueue, /* 消息队列句柄 */ 

           const void *pvItemToQueue, /* 要传递数据地址 */ 

           BaseType_t *pxHigherPriorityTaskWoken /* 高优先级任务是否被唤醒的状态保存 */ );

函数描述:函数 xQueueSendFromISR 用于中断服务程序中消息发送。 

① 第 1 个参数是消息队列句柄。 

② 第 2 个参数要传递数据地址,每次发送都是将消息队列创建函数 xQueueCreate 所指定的单个消息大 小复制到消息队列空间中。

③ 第 3 个参数用于保存是否有高优先级任务准备就绪。如果函数执行完毕后,此参数的数值是 pdTRUE,说明有高优先级任务要执行,否则没有。

④ 返回值,如果消息成功发送返回 pdTRUE,否则返回 errQUEUE_FULL。

使用这个函数要注意以下问题:

1. FreeRTOS 的消息传递是数据的复制,而不是传递的数据地址。正因为这个原因,用户在创建消息队列时单个消息大小不可太大,因为一定程度上面会增加中断服务程序的执行时间。

2. 此函数是用于中断服务程序中调用的,故不可以在任务代码中调用此函数,任务代码中使用的是xQueueSend。

3. 消息队列还有两个函数 xQueueSendToBackFromISR 和 xQueueSendToFrontFromISR,函数xQueueSendToBackFromISR 实现的是 FIFO 方式的存取,函数 xQueueSendToFrontFromISR 实现的是 LIFO 方式的读写。我们这里说的函数 xQueueSendFromISR 等效于xQueueSendToBackFromISR,即实现的是 FIFO 方式的存取。

3、任务中消息队列接收

函数原型:BaseType_t xQueueReceive( QueueHandle_t xQueue, /* 消息队列句柄 */ 

                   void *pvBuffer, /* 接收消息队列数据的缓冲地址 */ 

                   TickType_t xTicksToWait /* 等待消息队列有数据的最大等待时间 */ );

函数描述:函数 xQueueReceive 用于接收消息队列中的数据。 

① 第 1 个参数是消息队列句柄。 

② 第 2 个参数是从消息队列中复制出数据后所储存的缓冲地址,缓冲区空间要大于等于消息队列创建函数 xQueueCreate 所指定的单个消息大小,否则取出的数据无法全部存储到缓冲区,从而造成内存溢出。

③ 第 3 个参数是消息队列为空时,等待消息队列有数据的最大等待时间,单位系统时钟节拍。 

④ 返回值,如果接到到消息返回 pdTRUE,否则返回 pdFALSE。

使用这个函数要注意以下问题:

1. 此函数是用于任务代码中调用的,故不可以在中断服务程序中调用此函数,中断服务程序使用的是xQueueReceiveFromISR。

2. 如果消息队列为空且第三个参数为 0,那么此函数会立即返回。

3. 如果用户将 FreeRTOSConfig.h 文件中的宏定义 INCLUDE_vTaskSuspend 配置为 1 且第三个参数配置为 portMAX_DELAY,那么此函数会永久等待直到消息队列有数据。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

tensorflow-gpu cuda cudNN tensorRT 安装

tensorflow-gpu cuda cudNN tensorRT 安装 tensorflow-gpu 版本对应关系 tensorflow-gpu 版本对应关系 https://tensorflow.google.cn/install/source#gpu 安装方式 方式1 ,直接安装在系统上 这种方式只能安装一个版本 方式2,安装在虚拟环境中 …

JDK19 - synchronized关键字导致的虚拟线程PINNED

JDK19 - synchronized关键字导致的虚拟线程PINNED 前言一. PINNED是什么意思1.1 synchronized 绑定测试1.2 synchronized 关键字的替代 二. -Djdk.tracePinnedThreads的作用和坑2.1 死锁案例测试2.2 发生原因的推测2.3 总结 前言 在 虚拟线程详解 这篇文章里面,我们…

树莓派安装Ubuntu系统(无屏幕)

树莓派安装ubuntu系统 前言 软件需要: 1.方案一 win32diskimager-1.0.0-install.exe SDFormatterha Ubuntu镜像(可以官网下载也可以清华源) 方案二: 树莓派镜像烧录器 树莓派镜像烧录器直达下载 硬件需要: 64GB内存卡(推荐Sanddisk Ultra&am…

Java多线程(3)---锁策略、CAS和JUC

目录 前言 一.锁策略 1.1乐观锁和悲观锁 ⭐ 两者的概念 ⭐实现方法 1.2读写锁 ⭐概念 ⭐实现方法 1.3重量级锁和轻量级锁 1.4自旋锁和挂起等待锁 ⭐概念 ⭐代码实现 1.5公平锁和非公平锁 1.6可重入锁和不可重入锁 二.CAS 2.1为什么需要CAS 2.2CAS是什么 ⭐CAS…

c基础扫雷

和三子棋一样,主函数先设计游戏菜单界面,这里就不做展示了。 初始化棋盘 初级扫雷大小为9*9的棋盘,但排雷是周围一圈进行排雷(8格),而边界可能会越界。数组扩大了一圈,行和列都加了2,所以我们用一个11*11的数组来初始化…

leetcode 343. 整数拆分

2023.8.10 本题用dp算法来做,dp[i]代表的含义是:当前数字i 在拆分之后所能获得的最大乘积。然后由于n>2,所以dp[0]和dp[1]没有意义,不用初始化,直接初始化dp[2] 1。 然后再遍历给dp数组赋值:dp[i]的来源…

Untiy Json和Xml的序列化和反序列化

Json的序列化和反序列化 1.定义数据类 [Serializable] public class ZoomPoint {// 点名称, 将作为Key被字典存储public string name;// 轴心X坐标public Vector2 pivot Vector2.one / 2;// 放大倍率,小于1是为缩小倍率,小于0是取绝对值,不…

竞赛项目 酒店评价的情感倾向分析

前言 🔥 优质竞赛项目系列,今天要分享的是 酒店评价的情感倾向分析 该项目较为新颖,适合作为竞赛课题方向,学长非常推荐! 🧿 更多资料, 项目分享: https://gitee.com/dancheng-senior/post…

推荐两本书《JavaRoadmap》、《JustCC》

《JavaRoadmap》 前言 本书的受众 如果你是一名有开发经验的程序员,对 Java 语言语法也有所了解,但是却一直觉得自己没有入门,那么希望这本书能帮你打通 Java 语言的任督二脉。 本书的定位 它不是一本大而全的书,而是一本打通、…

嵌入式:C高级 Day4

一、整理思维导图 二、写一个函数&#xff0c;获取用户的uid和gid并使用变量接收 三、整理冒泡排序、简单选择排序和快速排序的代码 冒泡排序 #include <myhead.h>void output(int arr[], int len); void bubble_sort(int arr[], int len);int main(int argc, const ch…

数字化时代,如何做好用户体验与应用性能管理

引言 随着数字化时代的到来&#xff0c;各个行业的应用系统从传统私有化部署逐渐转向公有云、行业云、微服务&#xff0c;这种变迁给运维部门和应用部门均带来了较大的挑战。基于当前企业 IT 运维均为多部门负责&#xff0c;且使用多种运维工具&#xff0c;因此&#xff0c;当…

Linux命名管道进程通信

文章目录 前言一、什么是命名管道通信二、创建方式三、代码示例四、文件进程通信总结 前言 命名管道 是实现进程间通信的强大工具&#xff0c;它提供了一种简单而有效的方式&#xff0c;允许不同进程之间进行可靠的数据交换。不仅可以在同一主机上的不相关进程间进行通信&…