HI3861学习笔记(10)——LiteOS(CMSIS-RTOS2)消息队列

一、简介

1.1 消息队列

消息队列,是一种常用于任务间通信的数据结构,实现了接收来自任务或中断的不固定长度的消息,并根据不同的接口选择传递消息是否存放在自己空间。任务能够从队列里面读取消息,当队列中的消息是空时,挂起读取任务;当队列中有新消息,挂起的读取任务被唤醒并处理新消息。

用户在处理业务时,消息队列提供了异步处理机制,允许将一个消息放入队列,但并不立即处理它,同时队列还能起到缓冲消息作用。

LiteOS中使用队列数据结构实现任务异步通信工作,具有如下特性:

  • 消息以先进先出方式排队,支持异步读写工作方式。
  • 读队列和写队列都支持超时机制。
  • 发送消息类型由通信双方约定,可以允许不同长度(不超过队列节点最大值)消息。
  • 一个任务能够从任意一个消息队列接收和发送消息。
  • 多个任务能够从同一消息队列接收和发送消息。
  • 当队列使用结束后,如果是动态申请的内存,需要通过释放内存函数回收。

1.2 消息队列的运作机制

创建队列时,根据用户传入队列长度和消息节点大小来开辟相应的内存空间以供该队列使用,返回队列ID。

在队列控制块中维护一个消息头节点位置Head和一个消息尾节点位置Tail来表示当前队列中消息存储情况。Head表示队列中被占用消息的起始位置。Tail表示队列中被空闲消息的起始位置。刚创建时Head和Tail均指向队列起始位置。

写队列时,根据Tail找到被占用消息节点末尾的空闲节点作为数据写入对象。

读队列时,根据Head找到最先写入队列中的消息节点进行读取。

删除队列时,根据传入的队列ID寻找到对应的队列,把队列状态置为未使用,释放原队列所占的空间,对应的队列控制头置为初始状态。

二、API说明

以下任务管理接口位于 kernel/liteos_m/components/cmsis/2.0/cmsis_os2.h

业务BUILD.gn中包含路径

include_dirs = [
        "//utils/native/lite/include",
        "//kernel/liteos_m/components/cmsis/2.0",
    ]

2.1 osMessageQueueNew

功能创建消息队列,不能在中断服务调用该函数
函数定义osMessageQueueId_t osMessageQueueNew (uint32_t msg_count,uint32_t msg_size,const osMessageQueueAttr_t *attr)
参数msg_count:队列中的最大消息数
msg_size:最大消息大小(以字节为单位)
attr:消息队列属性;空:默认值
返回消息队列ID

2.2 osMessageQueuePut

功能发送消息,如果参数timeout设置为0,可以从中断服务例程调用
函数定义osStatus_t osMessageQueuePut (osMessageQueueId_t mq_id,const void *msg_ptr,uint8_t msg_prio,uint32_t timeout)
参数mq_id:由osMessageQueueNew获得的消息队列ID
msg_ptr:要发送的消息
msg_prio:指优先级
timeout:超时值
返回0 - 成功,非0 - 失败

2.3 osMessageQueueGet

功能获取消息,如果参数timeout设置为0,可以从中断服务例程调用
函数定义osStatus_t osMessageQueueGet (osMessageQueueId_t mq_id,void *msg_ptr,uint8_t *msg_prio,uint32_t timeout)
参数mq_id:由osMessageQueueNew获得的消息队列ID
msg_ptr:指针指向队列中获取消息的缓冲区指针
msg_prio:指优先级
timeout:超时值
返回0 - 成功,非0 - 失败

2.4 osMessageQueueDelete

功能删除消息队列
函数定义osStatus_t osMessageQueueDelete (osMessageQueueId_t mq_id)
参数mq_id:消息队列ID
返回0 - 成功,非0 - 失败

三、通过消息队列进行线程之间交换消息

编译时在业务BUILD.gn中包含路径

include_dirs = [
        "//utils/native/lite/include",
        "//kernel/liteos_m/components/cmsis/2.0",
    ]

在Message_example函数中,通过osMessageQueueNew()函数创建了消息队列ID,Thread_MsgQueue1()函数中通过osMessageQueuePut()函数向消息队列中发送消息。在Thread_MsgQueue2()函数中通过osMessageQueueGet()函数读取消息队列中的消息比打印出来。

void Thread_MsgQueue1 (void *argument) 
{
  (void)argument; 

  msg.Buf = "Hello BearPi-HM_Nano!";                                         // do some work...
  msg.Idx    = 0U;
  while (1)
  {
    osMessageQueuePut(mid_MsgQueue, &msg, 0U, 0U);
    osThreadYield();                                            // suspend thread   
    osDelay(100);
  }
}
 
void Thread_MsgQueue2 (void *argument) 
{
  (void)argument;
  osStatus_t status;

  while (1) {
    // Insert thread code here...
    status = osMessageQueueGet(mid_MsgQueue, &msg, NULL, 0U);   // wait for message
    if (status == osOK) {
      printf("Message Queue Get msg:%s\n",msg.Buf);
    }
  }
}

static void Message_example (void) {
 
  mid_MsgQueue = osMessageQueueNew(MSGQUEUE_OBJECTS, 100, NULL);
  if (mid_MsgQueue == NULL) {
    printf("Falied to create Message Queue!\n");
  } 
  osThreadAttr_t attr;
  
  attr.attr_bits = 0U;
  attr.cb_mem = NULL;
  attr.cb_size = 0U;
  attr.stack_mem = NULL;
  attr.stack_size = 1024*10;
  attr.priority = 25;

  attr.name = "Thread_MsgQueue1";
  if (osThreadNew(Thread_MsgQueue1, NULL, &attr) == NULL) {
      printf("Falied to create Thread_MsgQueue1!\n");
  }
  attr.name = "Thread_MsgQueue2";
  if (osThreadNew(Thread_MsgQueue2, NULL, &attr) == NULL) {
      printf("Falied to create Thread_MsgQueue2!\n");
  }
}

示例代码编译烧录代码后,按下开发板的RESET按键,通过串口助手查看日志,会打印从消息队列中获取的消息。

Message Queue Get msg:Hello BearPi-HM_Nano!
Message Queue Get msg:Hello BearPi-HM_Nano!
Message Queue Get msg:Hello BearPi-HM_Nano!
Message Queue Get msg:Hello BearPi-HM_Nano!
Message Queue Get msg:Hello BearPi-HM_Nano!

• 由 Leung 写于 2021 年 7 月 18 日

• 参考:【鸿蒙2.0设备开发教程】小熊派HarmonyOS 鸿蒙·季 开发教程

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Leung_ManWah

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值