UCOS学习笔记——消息队列

消息队列

消息队列的基本概念

队列又称消息队列,是一种常用于任务间通信的数据结构,队列可以在任务与任务间、中断和任务间传递信息
μC/OS中使用队列数据结构实现任务异步通信工作,具有如下特性:
●消息支持先进先出方式排队,支持异步读写工作方式。
●消息支持后进先出方式排队,往队首发送消息(LIFO) 。
●读消息队列支持超时机制。
●可以允许不同长度的任意类型消息
●一个任务能够从任意一个消息队列接收和发送消息。.
●多个任务能够从同一个消息队列接收和发送消息。
●当队列使用结束后,可以通过删除队列函数进行删除。

消息变量组成:

指向下一条消息的指针、用于表明该消息所指向数据的大小的变量、存放消息最后一次被提交的时间戳的变量、消息中包含一个指向实际数据的指针 ,如下图所示:
消息发送者和接收者都不知道消息中数据的结构因为这些都通过uC/OS-III 的 API 隐藏起来了
在这里插入图片描述
uC/OS-III 维护一个消息池。消息池的大小通过 OS_CFG_APP.H中的
OS_CFG_MSG_POOL_SIZE 设置。
当 uC/OS-III 被初始化时, 消息就会以单向列表的形式链接起来如下图。注意的是这个列表由结构体 OS_MSG_POOL 管理, 它包含 3 个部分: .NextPtr 指向该消息列表、 .NbrFree 包含了该队列的空闲消息数、 .NbrUsed 包含了该队列中已被使用的消息数。
在这里插入图片描述
消息的排列由结构体 OS_MSG_Q 控制,如图
Alt

  • InPtr
  • OutPtr 指向下一个将要被插入到队列的消息。指向下一个将要被释放的消息。
  • NbrEntriesSize 包含了该队列所能接受的最大消息数。队列满后再往其中发送消息,消息将不会被插入。
  • NbrEntries 当前队列中的消息数
  • NbrEntriesMax 记录了到目前为止队列中存放的最大消息数。

消息队列的工作过程

在UCOS-III中定义了一个数组0SCfg MsgPool[OS_CFG_MSG_ POOL_ SIZE],在系统初始化的时候就将这个大数组的各个元素串成单向链表,组成我们说的消息池,而这些元素我们称之为消息。
消息队列是内核对象。事实上,可以分配任意个消息队列(只要处理器的 RAM 足够的话)。通过消息队列用户可以做很多事情,如下图所示。然而, ISR 中只能
调用 OSQPost()。
在这里插入图片描述
消息队列是先入先出模式(FIFO)。然而, uC/OS-III 也可以将其设置为后入先出模式(LIFO)。 若任务或 ISR 发送紧急消息给另一个任务时, 后入先出模式是非常有用的, 在这种情况下, 该紧急消息绕过消息队列中的其他消息。消息队列的长度可以在运行时设置。如上图,接收任务旁的沙漏表示该任务可以设置等待期限。如果任务没有在规定时间内接收到该消息, uC/OS-III 会返回一个错误代
号表示任务被就绪不是因为接收到消息,而是等待超时。
消息队列中存放了等待该消息的任务。多个任务可以在消息队列中等待消息,如图 下图所示。当一个消息被发送到消息队列时,等待该消息的高优先级任务接收这个消息。 消息发送者可以广播这个消息给消息队列中的所有任务。 在这种情况下, 如果接收到消息中有优先级高于消息发送者优先级的任务, uC/OS-III 就会切换到这个高优先级的任务。 注意: 不是每个任务都需要设置等待期限, 有些任务可能需要永远等待这个消息
在这里插入图片描述

消息队列的常用函数

消息队列函数总结在这里插入图片描述

任务中消息队列总结在这里插入图片描述

消息队列发送函数OSQPost()
任务或者中断服务程序都可以给消息队列发送消息,当发送消息时,如果队列未满,就说明运行信息入队。μC/OS 会从消息池中取出一个消息,挂载到消息队列
的末尾(FIFO发送方式),如果是LIFO发送方式,则将消息挂载到消息队列的头部,然后将消息中MsgPtr成员变量指向要发送的消息(此处可以理解为添加要发送的信息到消息(块)中),如果系统有任务阻塞在消息队列中,那么在发送了消息队列的时候,会将任务解除阻塞。
消息队列获取函数OSQPend()
当任务试图从队列中的获取消息时,用户可以指定一个阻塞超时时间,当且仅
当消息队列中有消息的时候,任务才能获取到消息。在这段时间中,如果队列
为空,该任务将保持阻塞状态以等待队列消息有效。当其他任务或中断服务程
序往其等待的队列中写入了数据,该任务将自动由阻塞态转为就绪态。当任务
等待的时间超过了用户指定的阻塞时间,即使队列中尚无有效消息,任务也会
自动从阻塞态转为就绪态。

消息队列使用注意事项及总结

注意事项

1、使用OSQPend()、OSQPost()等 这些函数之前应先创建需消息队列队列读取采用的是先进先出(FIFO、 LIFO) 模式
2、无论是发送或者是接收消息都是以数据引用的方式进行。
3、队列是具有自己独立权限的内核对象,并不属于任何任务。所有任务都可以向
同一队列写入和读出。
4、消息的传递实际,上只是传递传送内容的指针和传送内容的字节大小,在获取消息之前不能释放存储在消息中的指针内容

总结

  • 当任务或 ISR 发送消息给另一个任务时,通过消息队列是很有效的方法。 被发送的消息中的数据必须被存储, 因为传送的是数据地址而不是实际的数据。
  • 任务在等待消息的时候不会占用 CPU。
  • 使用任务内部的消息堆栈更为简单和高效。 当设置 OS_CFG.H 中的 OS_CFG_TASK_Q_EN 为 1 时使能任务内部消息队列
  • 如果多个任务等待同一个消息队列中的消息,分配一个 OS_Q 并让任务所等待的消息发送到 OS_Q 中。 特别的, 可以广播消息给所有在消息队列中等待的任务。设置 OS_CFG.H 中的 OS_CFG_Q_EN 为1 开启消息队列服务。
    -消息通过结构体 OS_MSG(从 uC/OS-III 的消息池中获得)被发送。设置消息队列的大小,和消息池的大小。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章