从零开始学习UCOSII操作系统11--消息队列

从零开始学习UCOSII操作系统11--消息队列

1、什么是消息队列?

(1)传递多个邮箱的一种任务之间进行通信的方式

(2)消息队列时UCOSII中的另一种的通信机制,他允许一个任务或者中断服务子程序向另一个任务发送以指针方式定义的变量或者其他的任务。因为具体的应用不同,每个指针指向的包含了消息的数据结构的变量类型也有所不同。

(3)UCOSII提供了9个对消息队列进行操作的函数:OSQCreate(),OSQDel(),OSQPend(),OSQPost(),OSQPostFront()等等。

(4)至少要调用发送消息队列中的一个函数OSQPost(),OSQPostFront()以及OSQPostOpt()功能函数中的一个函数。

(5)其中消息队列看做是多个邮箱组成的数组,只是他们共用一个等待任务列表,每个指针所指向的数据结构类型是由具体的应用程序决定的。

2、怎么使用消息队列?

(1)是实现消息队列所需要的各种数据结构:

OS_EVENT_TYPE_Q == OSEVENTType;
OSEventCnt == 0x00;
OSEventPtr == OS_Q ==指向一个数组的数组头函数

用于消息队列的数据结构

(2)消息其实就是存储在一段内存中的一些数据,UCOS中的消息传递就是将这段内存的首地址传递出去,PEND请求到的消息就是这段内存的首地址,然后从这个地址开始读取消息就可以了,一般情况下面这段内存通过定义一个数组来实现,数组名就是内存的首地址。

(3)这里也需要事件控制块ECB记录等待任务列表,而且事件控制块可以使多个消息队列的 操作与信号量函数、互斥性信号量以及邮箱使用相同的代码。

(4)在建立一个消息队列之前,必须先定义一个含有与消息队列最大消息数相同的指针数组,换句话说,这个数组的单元数与队列中的单元数是一致的

3、一个简单的实例:说明怎么使用消息队列:

消息队列其实就是多个消息邮箱的应用。

//首先定义一个消息队列的存储地址,最大支持256个消息:
void * MsgGrp[256];

//对列消息显示任务
void qmsgshow_task(void pdata)
{
u8 
p;u8 err;
while(1)
{
p = OSQpend(q_msg,0,&err); //请求消息队列
LCD_ShowString(5,170,240,16,16,p);//显示消息
myfree(SRAMIN,p);
}
}

//然后是任意的一个函数的任务:
void tmr3_callback()
{
OSQPost(q_msg,p); //发送队列
}

void *OSQPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)
{
    void  *msg;
    OS_Q  *pq;

    pq = pevent->OSEventPtr;                     /* Point at queue control block                       */
//然后看队列中是否有消息
    if (pq->OSQEntries != 0) {                   
/* 不断的查看消息对列中是否有信息  */
        msg = *pq->OSQOut++;                     
/* Yes, extract oldest message from the queue         */

pq->OSQEntries--;                       
 /* Update the number of entries in the queue          */

if (pq->OSQOut == pq->OSQEnd) 
{         
 /* Wrap OUT pointer if we are at the end of the queue */
            pq->OSQOut = pq->OSQStart;//如果到头则重新进行初始化
}
        OS_EXIT_CRITICAL();
        *err = OS_NO_ERR;
    } else if (OSIntNesting > 0) {              
 /* See if called from ISR ...                         */
        OS_EXIT_CRITICAL();                      /* ... can't PEND from an ISR                         */
        *err = OS_ERR_PEND_ISR;
    } else {
    //若没有消息,则置为等待消息的状态
        OSTCBCur->OSTCBStat    |= OS_STAT_Q;     /* Task will have to pend for a message to be posted  */
//并决定是否需要等待
OSTCBCur->OSTCBDly      = timeout;       /* Load timeout into TCB                              */
//把此任务加入到等待消息的列表中
OSEventTaskWait(pevent);                 /* Suspend task until event or timeout occurs         */
        OS_EXIT_CRITICAL();
//然后切换任务
OSSched();                               /* Find next highest priority task ready to run       */
        OS_ENTER_CRITICAL();
//待任务回来,判断是否已经得到消息
        if ((msg = OSTCBCur->OSTCBMsg) != (void *)0) {/* Did we get a message?                         */
            OSTCBCur->OSTCBMsg      = (void *)0;      /* Extract message from TCB (Put there by QPost) */
//若等到消息,则更改为直接就绪状态


OSTCBCur->OSTCBStat     = OS_STAT_RDY;
            OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;  /* No longer waiting for event                   */
            OS_EXIT_CRITICAL();
            *err                    = OS_NO_ERR;
        }
//若没有收到消息,则说明任务超时
               //表明一定是时间超时造成

else if (OSTCBCur->OSTCBStat & OS_STAT_Q) 
              { /* Timed out if status indicates pending on Q    */
            OSEventTO(pevent);//若消息依然在等待消息,则强制任务从等待列表中返回
                        OS_EXIT_CRITICAL();
            msg                     = (void *)0;      /* No message received                           */
            *err                    = OS_TIMEOUT;     /* Indicate a timeout occured                    */
        } else {//这里的else很疑惑:如果已经超时,且等待状态标志也被清零,则说明已经得到了消息(从OSQPend()中得到 )
//那么为何还要从队列中取消息呢        
msg = *pq->OSQOut++;                      /* Extract message from queue                    */
            pq->OSQEntries--;                         /* Update the number of entries in the queue     */
            if (pq->OSQOut == pq->OSQEnd) {           /* Wrap OUT pointer if we are at the end of Q    */
                pq->OSQOut = pq->OSQStart;
            }
            OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;
            OS_EXIT_CRITICAL();
            *err = OS_NO_ERR;
        }
    }                                                 
    return (msg);                                     /* Return message received (or NULL)             */
}
  • 3
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值