uCos中的邮箱和消息队列

文章目录

    • 1. 背景
    • 2. 直接通信与间接通信
    • 3. 消息机制
    • 4. 消息队列
    • 5. ucos-ii中实现
      • 5.1. 任务创建
      • 5.2. 发送消息
      • 5.3. 等待消息

1. 背景

前段时间老师上课讲到了uC/OS中的邮箱和消息队列,所以我想要结合《μC/OS-III源码分析笔记》和中国大学MOOC-电子科技大学《嵌入式系统及应用》PPT写一篇笔记对这部分的内容进行总结。

2. 直接通信与间接通信

  • 直接通信:在通信过程中双方必须明确地知道(命名)彼此。

    • Send (P,message) – 发送一个消息到任务P
    • Receive(Q,message) – 从任务Q接收一个消息
  • 间接通信:通信双方不需要指出消息的来源或去向,而通过中间机 制来通信

    • send(A,message) – 发送一个消息给邮箱A
    • receive(A,message) – 从邮箱A接收一个消息

3. 消息机制

  • 消息队列:属于间接通信方式
    • 消息:内存空间中一段长度可变的缓冲区,其长度和内容均可以由用户定义和解释,其内容可以是实际的数据、数据块的指针或空
    • 从操作系统观点看,消息没有定义的格式,所有的消息都是字节流,没有特定的含义。
    • 应用可以只把消息当成一个标志,这时消息机制用于实现同步。
  • 消息机制可进一步分为:邮箱和消息队列邮箱仅能存放单条消息, 消息队列可存放若干消息
  • 消息机制可支持定长与可变长度两种模式的消息。

4. 消息队列

uCos中的邮箱和消息队列_第1张图片

Figure 1. 消息队列机制的主要数据结构 \text{Figure 1. 消息队列机制的主要数据结构} Figure 1. 消息队列机制的主要数据结构

  • 消息队列控制块:管理所有创建的消息队列,系统运行时动态分配和 回收消息队列控制块。
  • 消息队列缓冲区:存放该队列的消息内容。
  • 如何进行消息的发送或接收?完整的消息内容拷贝 or传递指针(效率高、系统性能好、空间占用小)?

uCos中的邮箱和消息队列_第2张图片

Figure 2. 消息队列的状态图 \text{Figure 2. 消息队列的状态图} Figure 2. 消息队列的状态图

uCos中的邮箱和消息队列_第3张图片

Figure 3. 消息队列的主要数据结构 \text{Figure 3. 消息队列的主要数据结构} Figure 3. 消息队列的主要数据结构

uCos中的邮箱和消息队列_第4张图片

Figure 4. 消息队列的环形缓冲 \text{Figure 4. 消息队列的环形缓冲} Figure 4. 消息队列的环形缓冲

uCos中的邮箱和消息队列_第5张图片

Figure 5. 接收消息流程图 \text{Figure 5. 接收消息流程图} Figure 5. 接收消息流程图

uCos中的邮箱和消息队列_第6张图片

Figure 6.消息队列的典型应用 \text{Figure 6.消息队列的典型应用} Figure 6.消息队列的典型应用

5. ucos-ii中实现

5.1. 任务创建

OS_EVENT  *OSQCreate (void **start, INT16U size)
{
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
    OS_CPU_SR  cpu_sr;
#endif
    OS_EVENT  *pevent;
    OS_Q      *pq;


    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;
            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);
}









5.2. 发送消息

INT8U  OSQPost (OS_EVENT *pevent, void *msg)
{
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
    OS_CPU_SR  cpu_sr;
#endif
    OS_Q      *pq;


#if OS_ARG_CHK_EN > 0
    if (pevent == (OS_EVENT *)0) {                    /* Validate 'pevent'                             */
        return (OS_ERR_PEVENT_NULL);
    }
    if (msg == (void *)0) {                           /* Make sure we are not posting a NULL pointer   */
        return (OS_ERR_POST_NULL_PTR);
    }
    if (pevent->OSEventType != OS_EVENT_TYPE_Q) {     /* Validate event block type                     */
        return (OS_ERR_EVENT_TYPE);
    }
#endif
    OS_ENTER_CRITICAL();
    if (pevent->OSEventGrp != 0x00) {                 /* See if any task pending on queue              */
        OS_EventTaskRdy(pevent, msg, OS_STAT_Q);      /* Ready highest priority task waiting on event  */
        OS_EXIT_CRITICAL();
        OS_Sched();                                   /* Find highest priority task ready to run       */
        return (OS_NO_ERR);
    }
    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_Q_FULL);
    }
    *pq->OSQIn++ = msg;                               /* 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();
    return (OS_NO_ERR);
}










5.3. 等待消息

void  *OSQPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
    OS_CPU_SR  cpu_sr;
#endif
    void      *msg;
    OS_Q      *pq;


    if (OSIntNesting > 0) {                      /* See if called from ISR ...                         */
        *err = OS_ERR_PEND_ISR;                  /* ... can't PEND from an ISR                         */
        return ((void *)0);
    }
#if OS_ARG_CHK_EN > 0
    if (pevent == (OS_EVENT *)0) {               /* Validate 'pevent'                                  */
        *err = OS_ERR_PEVENT_NULL;
        return ((void *)0);
    }
    if (pevent->OSEventType != OS_EVENT_TYPE_Q) {/* Validate event block type                          */
        *err = OS_ERR_EVENT_TYPE;
        return ((void *)0);
    }
#endif
    OS_ENTER_CRITICAL();
    pq = (OS_Q *)pevent->OSEventPtr;             /* Point at queue control block                       */
    if (pq->OSQEntries > 0) {                    /* See if any messages in the queue                   */
        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;
        return (msg);                            /* Return message received                            */
    }
    OSTCBCur->OSTCBStat |= OS_STAT_Q;            /* Task will have to pend for a message to be posted  */
    OSTCBCur->OSTCBDly   = timeout;              /* Load timeout into TCB                              */
    OS_EventTaskWait(pevent);                    /* Suspend task until event or timeout occurs         */
    OS_EXIT_CRITICAL();
    OS_Sched();                                  /* Find next highest priority task ready to run       */
    OS_ENTER_CRITICAL();
    msg = OSTCBCur->OSTCBMsg;
    if (msg != (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;
        return (msg);                            /* Return message received                            */
    }
    OS_EventTO(pevent);                          /* Timed out                                          */
    OS_EXIT_CRITICAL();
    *err = OS_TIMEOUT;                           /* Indicate a timeout occured                         */
    return ((void *)0);                          /* No message received                                */
}









联系邮箱[email protected]

CSDN:https://me.csdn.net/qq_41729780

知乎:https://zhuanlan.zhihu.com/c_1225417532351741952

公众号复杂网络与机器学习

欢迎关注/转载,有问题欢迎通过邮箱交流。

uCos中的邮箱和消息队列_第7张图片

你可能感兴趣的:(课程笔记,#,嵌入式系统,嵌入式,队列,邮箱,ucos)