freeRTOS学习 — 消息队列

2023-05-16

1、freeRTOS 的消息队列

freeRTOS中提供了任务之间互相通信的另外的一种手段——消息队列。它的作用主要有:
1)为了在任务与任务之间、任务与中断之间的通信而准备的,可以在任务与任务之间,任务与中断之间传递消息;
2)消息队列可以存储有限的、大小固定的数据项目;

它具有的特点有几个:
1)freeRTOS中的消息队列传递的是一个实际的数据,而不是数据的地址。在RTX、ucos-ii、ucos-iii中的消息队列传递的是消息的地址。
2)消息队列不属于某个特定的任务,任何的任务都可以向队列中发送消息,也可以从队列中提取消息。
3)消息队列所能容纳的最大的数据项目就是队列的长度。

2、freeRTOS的消息队列的管理

2.1、队列的出队方式 & 数据存储

通常的队列都是采取先进先出(FIFO)的存储缓冲机制方式,即往队列中发送消息的时候永远是先发到队列的尾部,而从队列中提取消息的时候是从头部提取的。同时freeRTOS也支持 后进先出(LIFO)的方式。
因为freeRTOS的消息队列传递的是实际的数据,所以数据发送到队列中会导致数据拷贝,会浪费一些时间。但是好处在于一旦消息被拷贝到了消息队列中,那么原始的数据缓冲区或者数据就可以删除或者改变,达到反复利用的效果。

2.2、队列的阻塞

队列阻塞的作用是在当任务从队列中获取消息的时候,所指定的一个等待时间。队列在出队和入队都是可以设置阻塞的。有三种阻塞的时间:
不等待:不等待直接执行之后的内容(为0不等待);

定时等待:任务等待一个固定的时间间隔,可以为 0 ~ portMAX_DELAY
一直等待:设置为 portMAX_DELAY 的时候,会一直等待。

3、freeRTOS的队列的实现示意

按照freeRTOS官方给出的队列的实现,它的链接如下:
http://www.freertos.org/Embedded-RTOS-Queues.html

官方的队列示意图如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.1、消息队列的两种通信方式

在这里插入图片描述
在这里插入图片描述

4、freeRTOS 消息队列实现的API函数:

4.1、创建消息队列

函数原型:

QueueHandle_t xQueueCreate( UBaseType_t uxQueueLength, /* 消息个数 */
    			 UBaseType_t uxItemSize );  /* 每个消息大小,单位字节 */

函数描述:
函数 xQueueCreate 用于创建消息队列。
第 1 个参数是消息队列支持的消息个数。即队列长度。
第 2 个参数是每个消息的大小,单位字节。
返回值:如果创建成功会返回消息队列的句柄,失败会返回 NULL。

使用这个函数要注意以下问题:
1)FreeRTOS 的消息传递是数据的复制,而不是传递的数据地址,这点要特别注意。每一次传递都是
uxItemSize 个字节。
2.)uxItemSize:所要发送/接收的消息队列的总字节数。比如要发送10个消息,每个消息占4个字节,所以
uxItemSize = 4(byte) * 10(个) = 40 Byte

4.2、向消息队列中发送消息

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 方式的存取。

4.3、从消息队列中读取消息

1)任务中读取
函数原型:

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,那么此函数会永久等待直到消息队列有数据。

2)中断中读取

BaseType_t  xQueueReceiveFromISR( QueueHandle_t xQueue,	//消息队列
 				       			   void * const pvBuffer,	//消息的存放位置
 				       			   BaseType_t * const pxHigherPriorityTaskWoken )

5、队列初始化函数

static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, //队列长度
    								const UBaseType_t uxItemSize,    //队列项目长度
        							uint8_t *pucQueueStorage, 	 //队列项目的存储区
            						const uint8_t ucQueueType, 	 //队列类型
               					Queue_t *pxNewQueue )		 //队列结构

6、队列复位

BaseType_t xQueueGenericReset( QueueHandle_t xQueue, BaseType_t xNewQueue )

消息队列举例:
创建两个任务,一个任务发送三个数据给另外一个任务,另一个任务接收并打印,循环发送,每次发送都对发送的数据增加后发送。代码如下:

1、创建消息队列
QueueHandle_t     NewQueue;	//消息队列
NewQueue  = xQueueCreate(3,sizeof(int)*3); //这一步非常重要,所需字节数 = 每个消息的字节数*队列长度

2、发送消息队列 && 接收消息队列
//task1任务函数 
void task1_task(void *pvParameters) //prio = 2
{

    u32 recStr[3] = {0};
    while(1)
    {
  
        xQueueReceive(NewQueue, recStr, 0);	//接收消息队列
        printf("Tx0 = %d Tx1 = %d Tx2 = %d\r\n",recStr[0],recStr[1],recStr[2]);
        LED1 ^= 1;
        vTaskDelay(200);   //延时n个时钟节拍	
    }
}

//task2任务函数  
void task2_task(void *pvParameters) //prio = 3
{

    u32 TxStr[3] = {0};
	while(1)
	{
        xQueueSend(NewQueue, TxStr, portMAX_DELAY);	//发送消息队列
        TxStr[0] ++;
        TxStr[1] += 5;
        TxStr[2] += 10;
        LED0 ^= 1;

        vTaskDelay(500);       //延时n个时钟节拍	
	}
}

对嵌入式技术感兴趣的欢迎关注微信公众号“嵌入式之入坑笔记”,一起学习讨论啊!
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

freeRTOS学习 — 消息队列 的相关文章

  • FreeRTOS临界区

    FreeRTOS临界区是指那些必须完整运行 不能被打断的代码段 比如有的外设的初始化需要严格的时序 初始化过程中不能被打断 FreeRTOS 在进入临界区代码的时候需要关闭中断 当处理完临界区代码以后再打开中断 FreeRTOS 系统本身就
  • FreeRTOS基础五:软件定时器

    软件定时器简介 软件定时器的作用 在指定的时间到来时执行指定的函数 或者以某个频率周期性地执行某个函数 被执行的函数叫做软件定时器回调函数 软件定时器由FreeRTOS内核实现 不需要硬件支持 软件定时器只有在软件定时器回调函数被调用时才需
  • freertos————互斥锁

    线程安全 多线程程序处于一个多变的环境 可访问的全局变量和堆数据随时可能被其他的线程改变 多个线程同时访问一个共享数据 可能造成严重的后果 出现问题的是之前移植了一个freemodbus的从站 多个任务访问全局变量保持寄存器区 导致最后读出
  • 7 SpringBoot整合RocketMQ发送单向消息

    发送单向消息是指producer向 broker 发送消息 执行 API 时直接返回 不等待broker 服务器的结果 这种方式主要用在不特别关心发送结果的场景 举例 日志发送 RocketMQTemplate给我们提供了sendOneWa
  • RabbitMQ理论+实战

    1 引出 1 1 中间件应用场景 1 跨系统数据传输 2 高并发的流量削峰 3 数据的分发与异步处理 4 大数据分析与传递 5 分布式事务 1 2 中间件常用协议 01 什么是协议 所谓协议是指 1 计算机底层操作系统和应用程序通讯时共同遵
  • STM32F103移植FreeRTOS必须搞明白的系列知识---2(FreeRTOS任务优先级)

    STM32F103移植FreeRTOS必须搞明白的系列知识 1 Cortex CM3中断优先级 STM32F103移植FreeRTOS必须搞明白的系列知识 2 FreeRTOS任务优先级 STM32F103移植FreeRTOS必须搞明白的系
  • RocketMQ 简介

    本文根据阿里云 RocketMQ产品文档整理 地址 https help aliyun com document detail 29532 html userCode qtldtin2 简介 RocketMQ是由阿里捐赠给Apache的一款
  • FreeRTOS死机原因

    1 中断回调函数中没有使用中断级API xxFromISR 函数 xSemaphoreGiveFromISR uart busy HighterTask 正确 xSemaphoreGive uart busy 错误 2 比configMAX
  • 消息队列:Ubuntu16.04安装和Web页面管理RabbitMQ(楼主亲测、真实有效)

    RabbitMQ 总来来说 RabbitMQ的安装还是有一些难度的 不同的方式 安装的方法也是完全不一样 还要解决蛮多依赖 加上现在有些网站 极其不负责 很多博文都没有经过测试检验就直接发出来的 楼主来亲测一下 希望能对大家有好的帮助 一
  • freeRTOS出现任务卡死的情况。

    最近在做一个产品二代升级的项目 代码是上一任工程师留下的 很多BUG 而且融合了HAL库和LL库 以及github上下载的GSM源码 很不好用 我这边是将2G模块换成了4G 且添加了单独的BLE模块 因此只在源码的基础上 去除2G和BLE代
  • FreeRTOS轻量级同步--任务通知

    1 简介 在FreeRTOS的配置参数中的configUSE TASK NOTIFICATIONS宏打开 一般RTOS会默认打开 如图1所示 图1 notify宏开关 RTOS在创建任务时 会创建一个32位的通知值ulNotifiedVal
  • RocketMQ系列之架构浅谈

    RMQ的架构设计 下面我从GitHub上截取了一张RMQ的源码结构图 图中我框框出来的9大模块 基本就构成了整个RMQ的内部结构 上面9大模块的依赖层次主要如下 依赖越强的越处于底层 下面介绍下最上层的4个模块 这4个模块中工具命令行就不讲
  • 单片机通信数据延迟问题排查

    1 问题说明 笔者在最近的项目中 发现系统的响应延迟较高 经过排查 排除了单片机运行卡死的问题 2 原因分析 具体排查过程这里就不细致说明了 直接给出排查后原因 任务执行周期规划不合理 导致freertos队列发送接收到的命令有延迟 为了便
  • 5分钟学会RocketMQ

    RocketMQ 简介 RocketMQ 是一个队列模型的消息中间件 具有高性能 高可用 高实时等特性 它并不支持JMS java消息服务 规范 但参考了JMS规范和kafak等的思想 Producer Consumer 队列都可以分布式
  • RT-Thread记录(七、IPC机制之邮箱、消息队列)

    讲完了线程同步的机制 我们要开始线程通讯的学习 线程通讯中的邮箱消息队列也属于 RT Thread 的IPC机制 目录 前言 一 邮箱 1 1 邮箱控制块 1 2 邮箱操作 1 2 1 创建和删除 1 2 2 初始化和脱离 1 2 3 发送
  • FreeRTOS 配置TICK_RATE_HZ

    我使用的是带有 5 4 版 FreeRTOS 的 MSP430f5438 我有一个有趣的问题 我无法弄清楚 基本上 当我将 configTICK RATE HZ 设置为不同的值时 LED 闪烁得更快或更慢 它应该保持相同的速率 我将 con
  • 如何更改 FreeRTOS 中任务的最大可用堆大小?

    我通过以下方式在任务中创建元素列表 l dllist pvPortMalloc sizeof dllist dlllist 有 32 字节大 我的嵌入式系统有 60kB SRAM 所以我希望系统可以轻松处理我的 200 个元素列表 我发现在
  • 腾讯技术工程总结-主流消息队列你了解哪些?

    文章参考 腾讯技术工程 关于消息队列的知识总结 主流消息队列你了解哪些 消息队列的发展历程 2003 年至今有很多优秀的消息队列诞生 如 kafka 阿里自研的 rocketmq 以及后起之秀 pulsar 消息队列在刚出现所需要解决的问题
  • 防止GCC LTO删除函数

    我使用 GCC ARM Embedded 和 FreeRTOS FreeRTOS具有的功能vTaskSwitchContext 仅在某些情况下使用 内联汇编代码 问题是 当我使用LTO时 GCC不考虑内联汇编代码并认为该函数没有被使用 因此
  • FreeRTOS 匈牙利表示法 [重复]

    这个问题在这里已经有答案了 我是 RTOS 和 C 编程的新手 而且我仍在习惯 C 的良好实践 因此 我打开了一个使用 FreeRTOS 的项目 我注意到操作系统文件使用匈牙利表示法 我知道一点符号 但面临一些新的 标准 FreeRTOS

随机推荐