ucos 消息队列

1:消息队列
消息队列可以同时传递多个消息,当时间控制块中的变量OSEventType值为:OS_EVENT_TYPE_Q表示此事件控制块是用来表示消息队列的。消息队列数据结构如下:

在上面的事件控制块的OSEventPtr指针指向了消息队列结构体:OS_Q。改结构体OS_Q管理者一个消息数组,这个数组中存放是消息的指针。
2:队列控制块

OS_Q的定义如下:
typedef struct os_q {                   /* QUEUE CONTROL BLOCK                                         */
    struct os_q   *OSQPtr;              /* Link to next queue control block in list of free blocks     */
    void         **OSQStart;            /* Pointer to start of queue data                              */
    void         **OSQEnd;              /* Pointer to end   of queue data                              */
    void         **OSQIn;               /* Pointer to where next message will be inserted  in   the Q  */
    void         **OSQOut;              /* Pointer to where next message will be extracted from the Q  */
    INT16U         OSQSize;             /* Size of queue (maximum number of entries)                   */
    INT16U         OSQEntries;          /* Current number of entries in the queue                      */
} OS_Q;
 其中OSQStart和OSQEnd 是常指针,分别指向队列消息数组的开始和结尾,OSQIn和OSQOut指针随着数据的插入和删除而改变。这些值的改变可以在队列的创建及消息的获取,post函数中看到。

消息队列的初始化函数与其他初始化函数:事件控制块,任务控制块类似的。有一个全局数组(定义了队列个数)及空闲链表(空闲的队列数)。如下全局变量:
#if (OS_Q_EN > 0) && (OS_MAX_QS > 0)
OS_EXT  OS_Q             *OSQFreeList;              /* Pointer to list of free QUEUE control blocks    */
OS_EXT  OS_Q              OSQTbl[OS_MAX_QS];        /* Table of QUEUE control blocks                   */
#endif

经过上面的初始化以后,OS_MAX_QS个消息队列连接成一个链表,OSQFreeList指向链表的开始。每当任务创建一个消息队列时,就会从空闲的队列链表OSQFreeList中取出一个来使用。空闲队列链表的如下:


3:消息队列创建
由于在消息队列中,存放消息的是指针数组,故在建立消息队列之前,必须先建立一个用来存放消息的指针数组。
OS_EVENT  *OSQCreate (void **start, INT16U size)
{
    OS_EVENT  *pevent;
    OS_Q      *pq;
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
    OS_CPU_SR  cpu_sr = 0;
#endif
    if (OSIntNesting > 0) {                      /* See if called from ISR ...                         */
        return ((OS_EVENT *)0);                  /* ... can't CREATE from an ISR                       */
    }
    OS_ENTER_CRITICAL();
    pevent = OSEventFreeList;                    /* Get next free event control block    */空闲的事件控制块
    if (OSEventFreeList != (OS_EVENT *)0) {      /* See if pool of free ECB pool was empty             */
        OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
    }
    OS_EXIT_CRITICAL();
    if (pevent != (OS_EVENT *)0) {               /* See if we have an event control block              */
        OS_ENTER_CRITICAL();
        pq = OSQFreeList;                        /* Get a free queue control block    */在空闲队列链表中取出一个空闲的队列
        if (pq != (OS_Q *)0) {                   /* Were we able to get a queue control block ?        */
            OSQFreeList            = OSQFreeList->OSQPtr; /* Yes, Adjust free list pointer to next free*/
            OS_EXIT_CRITICAL();
            pq->OSQStart           = start;               /*      Initialize the queue                 */
            pq->OSQEnd             = &start[size];分别指向了消息的数组起始和结尾

            pq->OSQIn              = start;
            pq->OSQOut             = start;
            pq->OSQSize            = size;//存放消息的数目
            pq->OSQEntries         = 0;
            pevent->OSEventType    =
OS_EVENT_TYPE_Q;
            pevent->OSEventCnt     = 0;
            pevent->OSEventPtr     = pq;//指向了消息队列指针。
#if OS_EVENT_NAME_SIZE > 1
            pevent->OSEventName[0] = '?';                  /* Unknown name                             */
            pevent->OSEventName[1] = OS_ASCII_NUL;
#endif
            OS_EventWaitListInit(pevent);   /*      Initalize the wait list              */

        } else {
            pevent->OSEventPtr = (void *)OSEventFreeList; /* No,  Return event control block on error  */
            OSEventFreeList    = pevent;
            OS_EXIT_CRITICAL();
            pevent = (OS_EVENT *)0;
        }
    }
    return (pevent);
}
4:向消息队列发送消息
ucos中有俩种方式来向指针数组中存放消息。一种是先进先出FIFO,另一种是:后进先出LIFO。
这俩种方式分别使用函数OSQPost()和OSQPostFront()来实现。
FIFO时,消息队列将在OSQIn  指向的位置插入消息,OSQOut 指向输出消息的指针。
    OS_ENTER_CRITICAL();
    if (pevent->OSEventGrp != 0) {                     /* See if any task pending on queue             */
                                                       /* Ready highest priority task waiting on event */
        (void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_Q, OS_STAT_PEND_OK);
        OS_EXIT_CRITICAL();
        OS_Sched();                                    /* Find highest priority task ready to run      */
        return (OS_ERR_NONE);
    }
    pq = (OS_Q *)pevent->OSEventPtr;                   /* Point to queue control block                 */
    if (pq->OSQEntries >= pq->OSQSize) {               /* Make sure queue is not full                  */
        OS_EXIT_CRITICAL();
        return (OS_ERR_Q_FULL);
    }
    *pq->OSQIn++ = pmsg;                               /* Insert message into queue                    */
    pq->OSQEntries++;                                  /* Update the nbr of entries in the queue       */
    if (pq->OSQIn == pq->OSQEnd) {                     /* Wrap IN ptr if we are at end of queue        */
        pq->OSQIn = pq->OSQStart;
    }

    OS_EXIT_CRITICAL();
LIFO时,使用OSQOut 来完成消息的出入。
    OS_ENTER_CRITICAL();
    if (pevent->OSEventGrp != 0) {                    /* See if any task pending on queue              */
                                                      /* Ready highest priority task waiting on event  */
        (void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_Q, OS_STAT_PEND_OK);
        OS_EXIT_CRITICAL();
        OS_Sched();                                   /* Find highest priority task ready to run       */
        return (OS_ERR_NONE);
    }
    pq = (OS_Q *)pevent->OSEventPtr;                  /* Point to queue control block                  */
    if (pq->OSQEntries >= pq->OSQSize) {              /* Make sure queue is not full                   */
        OS_EXIT_CRITICAL();
        return (OS_ERR_Q_FULL);
    }
    if (pq->OSQOut == pq->OSQStart) {                 /* Wrap OUT ptr if we are at the 1st queue entry */
        pq->OSQOut = pq->OSQEnd;
    }
    pq->OSQOut--;
    *pq->OSQOut = pmsg;                               /* Insert message into queue                     */
    pq->OSQEntries++;                                 /* Update the nbr of entries in the queue        */

    OS_EXIT_CRITICAL();


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

家有工程师

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

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

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

打赏作者

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

抵扣说明:

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

余额充值