UCOSIII操作系统
UCOSIII其他内容导航不迷路
UCOSIII操作系统-简介
【UCOSIII操作系统】任务篇(1)创建任务
【UCOSIII操作系统】任务篇(2)相关API函数
【UCOSIII操作系统】系统初始化篇(1)系统初始化
【UCOSIII操作系统】系统初始化篇(2)CPU,SysTick,内存初始化
【UCOSIII操作系统】硬件初始化篇(1)硬件初始化以及开始运行系统
【UCOSIII操作系统】消息队列篇(2)任务消息队列
【UCOSIII操作系统】信号量与互斥量篇(1)信号量
【UCOSIII操作系统】信号量与互斥量篇(2)互斥量
【UCOSIII操作系统】信号量与互斥量篇(3)任务信号量
【UCOSIII操作系统】事件篇
【UCOSIII操作系统】中断管理篇
【UCOSIII操作系统】临界段篇
【UCOSIII操作系统】软件定时器篇
【UCOSIII操作系统】内存管理篇
已完结
说在前面:
这个内容不适合0基础的人,因为这里只讲了应用层面的东西,并没有深入内核讲解,所以要从零开始学UCOSIII的朋友,可以先去学完入门内容,再来观看这个笔记加深印象。
这篇文章是个人学习整理,如有错误请指正
UCOSIII操作系统——消息队列篇(1)消息队列
消息队列常用函数
函数 | 描述 |
---|---|
OSQCreate() | 创建消息队列 |
OSQDel() | 消息队列删除 |
OSQPost() | 消息队列发送 |
OSQPend() | 消息队列获取 |
消息队列概念简介
队列又称消息队列,是一种常用于任务间通信的数据结构,队列可以在任务与任务间、中断和任务间传递信息,实现了任务接收来自其他任务或中断的不固定长度的消息,任务能够从队列里面读取消息。
创建消息队列->OSQCreate()
- 函数原型
void OSQCreate (OS_Q *p_q, //消息队列指针
CPU_CHAR *p_name, //消息队列名称
OS_MSG_QTY max_qty, //消息队列大小(不能为0)
OS_ERR *p_err) //返回错误类型
- 在调用创建消息队列函数之前要定义一个消息队列结构体
OS_Q queue; //声明消息队列
- 创建实例
/* 创建消息队列 queue */
OSQCreate ((OS_Q *)&queue, //指向消息队列的指针
(CPU_CHAR *)"Queue For Test", //队列的名字
(OS_MSG_QTY )20, //最多可存放消息的数目
(OS_ERR *)&err); //返回错误类型
消息队列删除->OSQDel()
队列删除函数是根据队列结构体(队列句柄)直接删除的,删除之后这个消息队列的所有信息都会被系统清空,而且不能再次使用这个消息队列了,但是需要注意的是,如果某个消息队列没有被定义,那也是无法被删除的。想要使用消息队列删除函数就必须将OS_CFGQ_DEL_EN宏定义配置为1
- 函数原型
#if OS_CFG_Q_DEL_EN > 0u //如果使能了 OSQDel() 函数
OS_OBJ_QTY OSQDel (OS_Q *p_q, //消息队列指针
OS_OPT opt, //选项
OS_ERR *p_err) //返回错误类型
- 选项
OS_OPT_DEL_NO_PEND: //如果只在没有任务等待的情况下删除队列
OS_OPT_DEL_ALWAYS: //无论如何必须删除消息队列 - 应用实例
/* 删除消息队列 queue */
OSQDel ((OS_Q *)&queue, //指向消息队列的指针
OS_OPT_DEL_NO_PEND,
(OS_ERR *)&err); //返回错误类型
消息队列发送->OSQPost()
- 函数原型
void OSQPost (OS_Q *p_q, //消息队列指针
void *p_void, //消息指针(看解释)
OS_MSG_SIZE msg_size, //消息大小(单位:字节)
OS_OPT opt, //选项
OS_ERR *p_err) //返回错误类型
- 消息指针
要发送的数据的指针,将内存块首地址通过队列“发送出去”,可以是"字符串"也可以是数组,在接受消息队列的时候可以通过指针取出具体消息。 - 选项
#define OS_OPT_POST_FIFO (OS_OPT) (0x0000u) /* 默认采用FIFO 方式发送 */
#define OS_OPT_POST_LIFO (OS_OPT) (0x0010u) /*采用LIFO 方式发送消息*/
#define OS_OPT_POST_1 (OS_OPT) (0x0000u) /*将消息发布到最高优先级的等待任务*/
#define OS_OPT_POST_ALL (OS_OPT) (0x0200u) /*向所有等待的任务广播消息*/
#define OS_OPT_POST_NO_SCHED (OS_OPT) (0x8000u) /*发送消息但是不进行任务调度*/
我们可以使用,上面基本类型来组合出其他几种类型,如下:
OS_OPT_POST_FIFO+ OS_OPT_POST_ALL
OS_OPT_POST_LIFO +OS_OPT_POST_ALL
OS_OPT_POST_FIFO+ OS_OPT_POST_NO_SCHED
OS_OPT_POST_LIFO + OS_OPT_POST_NO_SCHED
OS_OPT_POST_FIFO + OS_OPT_POST_ALL + OS_OPT_POST_NO_SCHED
OS_OPT_POST_LIFO + OS_OPT_POST_ALL+ OS_OPT_POST_NO_SCHED
- 应用实例1
/* 发布消息到消息队列 queue */
OSQPost ((OS_Q *)&queue, //消息变量指针
(void *)"Fire uC/OS-III", //要发送的数据的指针,将内存块首地址通过队列“发送出去”
(OS_MSG_SIZE )sizeof ( "Fire uC/OS-III" ), //数据字节大小
(OS_OPT )OS_OPT_POST_FIFO | OS_OPT_POST_ALL, //先进先出和发布给全部任务的形式
(OS_ERR *)&err); //返回错误类型
- 应用实例2
u8 buffer[3];
OSQPost ((OS_Q *)&queue, //消息变量指针
(void *)&buffer, //要发送的数据的指针,将内存块首地址通过队列“发送出去”
(OS_MSG_SIZE )3, //数据字节大小
(OS_OPT )OS_OPT_POST_FIFO | OS_OPT_POST_ALL, //先进先出和发布给全部任务的形式
(OS_ERR *)&err); //返回错误类型
消息队列获取->OSQPend()
- 函数原型
void *OSQPend (OS_Q *p_q, //消息队列指针
OS_TICK timeout, //等待期限(单位:时钟节拍)
OS_OPT opt, //选项
OS_MSG_SIZE *p_msg_size,//返回消息大小(单位:字节)
CPU_TS *p_ts, //获取等到消息时的时间戳
OS_ERR *p_err) //返回错误类型
- 等待期限timeout
等待消息的超时时间,如果在指定的时间没有接收到消息的话,任务就会被唤醒,
接着运行。这个参数也可以设置为0,表示任务将一直等待下去,直到接收到消息。 - 选项opt
用来选择是否使用阻塞模式,有两个选项可以选择。
oS_ OPT_ PEND_ BLOCKING如果没有任何消息存在的话就阻塞任务,一直等待,直到接收到消息。
oS_ OPT_ PEND_ NON_ BLOCKING如果消息队列没有任何消息的话任务就直接返回。
- 时间戳
指向一个时间戳,表明什么时候接收到消息。如果这个指针被赋值为NULL的话,说明用户没有要求时间戳。 - 应用实例1
/*
*********************************************************************************************************
* PEND TASK
*********************************************************************************************************
*/
static void AppTaskPend ( void * p_arg )
{
OS_ERR err;
OS_MSG_SIZE msg_size;
CPU_SR_ALLOC(); //使用到临界段(在关/开中断时)时必需该宏,该宏声明和
//定义一个局部变量,用于保存关中断前的 CPU 状态寄存器
// SR(临界段关中断只需保存SR),开中断时将该值还原。
char * pMsg;
(void)p_arg;
while (DEF_TRUE) { //任务体
/* 请求消息队列 queue 的消息 */
pMsg = OSQPend ((OS_Q *)&queue, //消息变量指针
(OS_TICK )0, //等待时长为无限
(OS_OPT )OS_OPT_PEND_BLOCKING, //如果没有获取到信号量就等待
(OS_MSG_SIZE *)&msg_size, //获取消息的字节大小
(CPU_TS *)0, //获取任务发送时的时间戳
(OS_ERR *)&err); //返回错误
if ( err == OS_ERR_NONE ) //如果接收成功
{
OS_CRITICAL_ENTER(); //进入临界段
printf ( "\r\n接收消息的长度:%d字节,内容:%s\r\n", msg_size, pMsg );
OS_CRITICAL_EXIT();
}
}
}
- 应用实例2
static void AppTaskStart2 (void *p_arg)
{
OS_ERR err;
OS_MSG_SIZE msg_size;
CPU_SR_ALLOC(); //使用到临界段(在关/开中断时)时必需该宏,该宏声明和
//定义一个局部变量,用于保存关中断前的 CPU 状态寄存器
// SR(临界段关中断只需保存SR),开中断时将该值还原。
u8 a,b,c;
char * pMsg;
(void)p_arg;
/* 死循环 */
while (DEF_TRUE){
GPIO_WriteBit(LEDPORT, LED2, (BitAction)(1-GPIO_ReadOutputDataBit(LEDPORT, LED2)));
/* 请求消息队列 queue 的消息 */
pMsg = OSQPend ((OS_Q *)&queue, //消息变量指针
(OS_TICK )0, //等待时长为无限
(OS_OPT )OS_OPT_PEND_BLOCKING, //如果没有获取到信号量就等待
(OS_MSG_SIZE *)&msg_size, //获取消息的字节大小
(CPU_TS *)0, //获取任务发送时的时间戳
(OS_ERR *)&err); //返回错误
if ( err == OS_ERR_NONE ) //如果接收成功
{
a=*pMsg;
pMsg++;
b=*pMsg;
pMsg++;
c=*pMsg;
// a=*pMsg;
// b=*(pMsg+1);
// c=*(pMsg+2);
printf ( "\r\n接收消息:%d,%d,%d°C \r\n", a,b,c);
OS_CRITICAL_EXIT();
}
}
}
指针的用法很重要,在获取具体的消息的时候需要用到