FreeRTOS消息队列

1、消息队列的基本概念

1、1 消息队列的概念及特点

        消息队列简称队列,是一种常用于任务间通信的数据结构

如下图:消息队列可以在任务与任务间,中断与任务间传递消息,实现任务接收来自其他任务或中断的不固定长度的消息

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

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

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

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

> 消息队列具有FIFO(先存先读)与LIFO(后进先读  )存储机制,方便处理数据

1、2 消息队列的通信机制

        消息队列是一种异步的通信方式

        任务能够从队列里读取消息,当队列中的消息为空时,读取消息的任务将被阻塞,用户可以指定阻塞的任务时间 xTicksToWait 在这段时间内,如果队列为空,该任务将保持阻塞状态以及等待队列数据有效,当队列中有新消息时,被阻塞的任务会被唤醒并处理新信息,当等待的时候超过指定阻塞时间,即使队列中没有有效数据,任务也有自动从阻塞态转为就绪态

        通过消息队列服务,任务或中断服务可以将一条或多条数据放入消息队列中,同样一个或多个任务可以从消息队列中获得消息,当有多个消息发送到消息队列时,通常是先进入消息队列的消息先传给任务,也就是说,任务先得到的是最先进入消息队列的消息,既先进先出原则(FIFO),FreeRTOS的队列也支持后进先出原则(LIFO)

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

1、3 消息队列常用的API函数

使用消息队列的典型流程如下:

> 创建消息队列

> 发送消息队列

> 读取消息队列

> 删除消息队列

常用API函数如下:

> xQueueCreate()

> xQueueSend() 和 xQueueSendFromISR()

> xQueueReceive()

> xQueueDelete() 

2、消息队列的创建与删除

2、1 消息队列的创建

函数描述:

函数 xQueueCreate 用于创建消息队列

> 第一个参数是消息队列支持的消息个数

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

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

2、2 消息队列创建的应用举例
static QueueHandle_t xQueue1 = NULL;
static QueueHandle_t xQueue2 = NULL;

xQueue1 = xQueueCreate(1,sizeof(uint32_t))

if(xQueue == Null)
  printf("创建消息队列1失败\r\n");
else 
  printf("创建消息队列1成功\r\n");

xQueue2 = xQueueCreate(2,16);
if(xQueue2 == NULL)
  printf("创建消息队列2失败\r\n");
else 
  printf("创建消息队列2成功\r\n");
 2、3 消息队列的删除

函数描述:

> 函数 xQueueDelete 用于删除消息队列

> 它只有一个参数,就是要被删除队列的句柄

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

3、任务中消息队列的发送

函数描述:

函数 xQueueSend 用于任务中消息发送

> 第一个参数是消息队列的句柄

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

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

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

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

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

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

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

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

5、消息队列还有两个函数 xQueueSendToBack 和 xQueueSendToFront 前一个是实现FIFO方式存取的,而后一个是实现LIFO方式的,我们这里说的函数 xQueueSend 等效于 xQueueSendToBack,也是实现的FIFO方式的存取

应用举例

if(xQueueSend(xQueue1,&ucSedn_Data,ulSendBlockTime) == pdPASS)
  printf("成功向消息队列1发送数据:%u\r\n",ucSend_Data);
else
  printf("向消息队列1发送数据时出现超时\r\n");

if(xQueueSend(xQueue2,"MCU168\r\n",0) == pdPASS)
  printf("成功向消息队列2发送字符串:%s\r\n","MCU168");
else
  printf("向消息队列2发送字符串出现超时\r\n");

4、中断中消息队列的发送 

函数描述:

函数 xQueueSendFromISR 用于中断服务程序中消息发送

> 第一个参数是消息队列句柄
> 第二个参数要传递数据地址,每次发送都是将消息队列创建函数 xQueueCreate 所指定的大小复制到消息队列空间中
> 第三个参数用于保存是否有高优先级任务准备就绪,如果函数执行完毕后,此参数的数值是 pdTRUE 说明有高优先级任务要执行,否则没有
> 返回值,如果消息成功发送返回 pdTRUE 否则返回 errQUEUE_FULL

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

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

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

3、消息队列还有两个函数 xQueueSendToBackFromISR 和 xQueueSendToFrontFromISR,函数xQueueSendToBack

5、消息队列任务中接收 

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

> 第一个参数是消息队列句柄

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

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

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

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

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

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

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

  

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值