从零开始学习UCOSII操作系统6--事件控制块

从零开始学习UCOSII操作系统6--事件控制块

1、任务和任务,任务和中断子程序是如何进行通信的?--事件控制块

事件控制块使用的几点须知:

(1)任务或者中断服务子程序可以给事件控住块ECB发送信号。
(2)中断服务子程序不能等待事件控制块ECB给它发送信号的。
(3)等待事件可以设置超时时间,后面会详细的说明实现的原理。
(4)多个任务可以同时等待同一个事件发生,在这种情况下面,当事件发生后,所有等待该事件的任务中,只有优先级最高的任务得到该事件并进入就绪状态。

2、事件控制块的结构

(1)只有当所定义的事件是消息邮箱或者消息队列的时候才能使用,当所定义的事件是邮箱时,它指向的是一个消息;而当所定义的事件是消息队列时,它指向一个数据结构。

(2)此事件控制块指向的任务,用到的是位图的数据结构,而不是使用链表来访问任务结构

typedef struct os_event {
    INT8U    OSEventType;                    /* 事件控制块的类型 */
    void    *OSEventPtr;                     /* 指向事件需要带有的信息 */
    INT16U   OSEventCnt;                     /* 信号量计数器*/
    OS_PRIO  OSEventGrp;                     /* 事件优先级组*/
    OS_PRIO  OSEventTbl[OS_EVENT_TBL_SIZE];  /* 等待任务列表*/

#if OS_EVENT_NAME_EN > 0u
    INT8U   *OSEventName;
#endif
} OS_EVENT;

3、当任务接收到等待事件,然后将任务从就绪列表中删除,然后插入到等待的事件表中

prevent->OSEventGrp |= OSMapTbl[prio >> 3];
prevent->OSEventTbl[prio >> 3] |= OSMapTbl[prio & 0x07];

4、空闲事件控制块链表

(1)事件控制块的总数由应用程序所需要的信号量、互斥型信号量、邮箱以及消息队列的总数决定。
也就是:#define OS_MAX_EVENTS 语句定义。

(2)所有的事件控制块ECB被链接成一个单向链表--空闲事件控制块,并对其进行初始化。每当建立一个信号量,互斥型信号量,就从该链表中取出空余事件控制块。

5、初始化一个事件控制块OS_EventWaitListInit()

所有的任务之间进行的通信都需要通过调用这个事件控制块进行调用函数OS_EventWaitListinit();
该函数初始化一个空的等待任务列表,这个函数传递一个指针变量给事件控制块。

void  OS_EventWaitListInit (OS_EVENT *pevent)
{
    INT8U  i;

    pevent->OSEventGrp = 0u;                     /* No task waiting on event                           */
    for (i = 0u; i < OS_EVENT_TBL_SIZE; i++) {
        pevent->OSEventTbl[i] = 0u;
    }
}

6、使一个任务进入就绪态:OS_EventTaskRdy()

就是简单的对就绪表进行相应的赋值就行。就是接收到相应的事件的时候把任务放置到就绪态中。

信号量、互斥型信号量、消息邮箱、消息队列所对应的POST函数调用OS_EventTaskRdy(),
以实现该操作。该函数的主要的功能就是将等待队列中使最高优先级任务脱离等待任务,并把该任务置于就绪态中。

INT8U  OS_EventTaskRdy (OS_EVENT  *pevent,
                        void      *pmsg,
                        INT8U      msk,
                        INT8U      pend_stat)
{
    OS_TCB   *ptcb;
    INT8U     y;
    INT8U     x;
    INT8U     prio;
#if OS_LOWEST_PRIO > 63u
    OS_PRIO  *ptbl;
#endif


#if OS_LOWEST_PRIO <= 63u
    y    = OSUnMapTbl[pevent->OSEventGrp];              /* Find HPT waiting for message                */
    x    = OSUnMapTbl[pevent->OSEventTbl[y]];
    prio = (INT8U)((y << 3u) + x);                      /* Find priority of task getting the msg       */
#else
    if ((pevent->OSEventGrp & 0xFFu) != 0u) {           /* Find HPT waiting for message                */
        y = OSUnMapTbl[ pevent->OSEventGrp & 0xFFu];
    } else {
        y = OSUnMapTbl[(OS_PRIO)(pevent->OSEventGrp >> 8u) & 0xFFu] + 8u;
    }
    ptbl = &pevent->OSEventTbl[y];
    if ((*ptbl & 0xFFu) != 0u) {
        x = OSUnMapTbl[*ptbl & 0xFFu];
    } else {
        x = OSUnMapTbl[(OS_PRIO)(*ptbl >> 8u) & 0xFFu] + 8u;
    }
    prio = (INT8U)((y << 4u) + x);                      /* Find priority of task getting the msg       */
#endif

    ptcb                  =  OSTCBPrioTbl[prio];        /* Point to this task's OS_TCB                 */
    ptcb->OSTCBDly        =  0u;                        /* Prevent OSTimeTick() from readying task     */
#if ((OS_Q_EN > 0u) && (OS_MAX_QS > 0u)) || (OS_MBOX_EN > 0u)
    ptcb->OSTCBMsg        =  pmsg;                      /* Send message directly to waiting task       */
#else
    pmsg                  =  pmsg;                      /* Prevent compiler warning if not used        */
#endif
    ptcb->OSTCBStat      &= (INT8U)~msk;                /* Clear bit associated with event type        */
    ptcb->OSTCBStatPend   =  pend_stat;                 /* Set pend status of post or abort            */
                                                        /* See if task is ready (could be susp'd)      */
    if ((ptcb->OSTCBStat &   OS_STAT_SUSPEND) == OS_STAT_RDY) {
        OSRdyGrp         |=  ptcb->OSTCBBitY;           /* Put task in the ready to run list           */
        OSRdyTbl[y]      |=  ptcb->OSTCBBitX;
    }

    OS_EventTaskRemove(ptcb, pevent);                   /* Remove this task from event   wait list     */
#if (OS_EVENT_MULTI_EN > 0u)
    if (ptcb->OSTCBEventMultiPtr != (OS_EVENT **)0) {   /* Remove this task from events' wait lists    */
        OS_EventTaskRemoveMulti(ptcb, ptcb->OSTCBEventMultiPtr);
        ptcb->OSTCBEventPtr       = (OS_EVENT  *)pevent;/* Return event as first multi-pend event ready*/
    }
#endif

    return (prio);
}

相当于等待事件的发生:
也就是收到相应的事件就可以直接把任务从事件等待的列表中移除了。

void  OS_EventTaskWait (OS_EVENT *pevent)
{
    INT8U  y;


    OSTCBCur->OSTCBEventPtr               = pevent;                 /* Store ptr to ECB in TCB         */

    pevent->OSEventTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX;    /* Put task in waiting list        */
    pevent->OSEventGrp                   |= OSTCBCur->OSTCBBitY;

    y             =  OSTCBCur->OSTCBY;            /* Task no longer ready                              */
    OSRdyTbl[y]  &= (OS_PRIO)~OSTCBCur->OSTCBBitX;
    if (OSRdyTbl[y] == 0u) {                      /* Clear event grp bit if this was only task pending */
        OSRdyGrp &= (OS_PRIO)~OSTCBCur->OSTCBBitY;
    }
}
发布了89 篇原创文章 · 获赞 86 · 访问量 13万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章