• ucosii事件控制块------消息邮箱与消息队列


    UCOSII 使用叫做事件控制块(ECB)的数据结构来描述诸如信号量、邮箱(消息邮箱)和消息队列这些事件

    #define  OS_EVENT_EN           (((OS_Q_EN > 0u) && (OS_MAX_QS > 0u)) || (OS_MBOX_EN > 0u) || (OS_SEM_EN > 0u) || (OS_MUTEX_EN > 0u))
    

     事件控制块类型定义:

    typedef struct os_event {
        INT8U    OSEventType;                    /* Type of event control block (see OS_EVENT_TYPE_xxxx)    */
        void    *OSEventPtr;                     /* Pointer to message or queue structure                   */
        INT16U   OSEventCnt;                     /* Semaphore Count (not used if other EVENT type)          */
        OS_PRIO  OSEventGrp;                     /* Group corresponding to tasks waiting for event to occur */
        OS_PRIO  OSEventTbl[OS_EVENT_TBL_SIZE];  /* List of tasks waiting for event to occur                */
    
    #if OS_EVENT_NAME_EN > 0u
        INT8U   *OSEventName;
    #endif
    } OS_EVENT;

    消息邮箱:

    向邮箱发送消息函数:INT8U  OSMboxPost (OS_EVENT  *pevent, void   *pmsg)其中 pevent 为消息邮箱的指针, msg 为消息指针

      该函数先检查消息邮箱结构体成员指针变量OSEventPtr是否为0,若为0,则说明消息邮箱为空,为其赋值pevent->OSEventPtr = pmsg;否则返回对应错误代码。

    请求邮箱函数:void *OSMboxPend (OS_EVENT *pevent, INT16U timeout,INT8U *err) 其中 pevent 为请求邮箱指针, timeout 为等待时限, err 为错误信息。

      这个函数的主要作用就是查看邮箱指针 OSEventPtr 是否为 NULL,如果不是 NULL 就把邮箱中的消息指针返回给调用函数的任务,然后清空邮箱pevent->OSEventPtr = (void *)0;同时用 OS_NO_ERR 通过函数的参数 err 通知任务获取消息成功。

    果邮箱指针OSEventPtr NULL,则使任务进入等待状态,并引发一次任务调度
    创建消息邮箱:OS_EVENT  *OSMboxCreate (void *pmsg),
    例如:

    msg_key=OSMboxCreate((void*)0);	//创建邮箱并初始化为空
    

    如果指针不为空,建立的消息邮箱将含有消息

     消息队列:

    与邮箱相比,消息队列在OS_EVENT结构基础之上添加了一循环队列,可以同时容纳多个消息,而邮箱只能容纳一个。因此,可以将消息队列看作同时接收多条消息的邮箱。

    队列控制块类型定义:

    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;
    

     OSQSize:消息指针数组的大小

     OSQEntries:消息指针数组中当前存放的消息指针数量(对应消息数量)

     

    1) 创建消息队列函数
    创建一个消息队列首先需要定义一指针数组,然后把各个消息数据缓冲区的首地址存
    入这个数组中,然后再调用函数 OSQCreate 来创建消息队列。创建消息队列函数 OSQCreate
    的原型为: OS_EVENT *OSQCreate(void**start,INT16U size)。其中, start 为存放消息缓冲
    区指针数组的地址, size 为该数组大小。该函数的返回值为消息队列指针。
    2) 请求消息队列函数

    请求消息队列的目的是为了从消息队列中获取消息。任务请求消息队列需要调用函数
    OSQPend,该函数原型为: void*OSQPend(OS_EVENT*pevent,INT16U timeout,INT8U *err)
    其中, pevent 为所请求的消息队列的指针, timeout 为任务等待时限, err 为错误信息。

    下面是函数的部分关键代码:

    pq = (OS_Q *)pevent->OSEventPtr;             /* Point at queue control block                       */
        if (pq->OSQEntries > 0u) {                   /* See if any messages in the queue                   */
            pmsg = *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();
            *perr = OS_ERR_NONE;
            return (pmsg);                           /* Return message received                            */
        }

    3) 向消息队列发送消息函数

    任务可以通过调用函数 OSQPost OSQPostFront 两个函数来向消息队列发送消息。函数 OSQPost FIFO( 先进先出)的方式组织消息队列,函数 OSQPostFront LIFO(后
    进先出)的方式组织消息队列。这两个函数的原型分别为: INT8U OSQPost(OS_EVENT*pevent,void *msg)INT8U OSQPost(OS_EVENT*pevent,void*msg)
    其中, pevent 为消息队列的指针, msg 为待发消息的指针。

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

      

     注:消息队列用作消息缓冲区是明智的(适合于进程通信),可要是用它来作为接收批量数据的数据缓冲区就不行了,因为ucos中的消息队列每次只能取出一条消息和每次只能放入一条消息。

  • 相关阅读:
    php 延迟静态绑定: static关键字
    python分片
    用逗号分隔数字,神奇
    ubuntu 屏幕截图
    js 获取随机数
    netty : NioEventLoopGroup 源码分析
    LinkedList 源码分析
    面向对象
    JS
    网页
  • 原文地址:https://www.cnblogs.com/prayer521/p/6825497.html
Copyright © 2020-2023  润新知