UCOSII学习笔记——事件控制块(Event Control Blocks)

  任务与任务,任务与中断服务程序之间可以通信,通信介质称为事件控制块。通信方式有以下几种,如下图:
在这里插入图片描述

  (1)中断服务程序或者任务可以给ECB发送信号;只有任务能够等到中断服务程序或者ECB发送的信号;等待ECB设置有超时机制,如图A。
  (2)当多个任务等到任务或者中断服务程序给ECB发送信号时,只有等待的最高优先级任务才会加入就序列表准备运行。ECB可以是信号量,消息邮箱,消息队列。
  (3)当ECB使用信号量时,任务既能等待ECB响应,也能给ECB发送信号。

  ucosII通过结构体OS_EVENT来管理ECB
  OSEventType:事件类型(信号量、锁、邮箱、消息队列);
  OSEventPtr:ECB为邮箱或消息队列时使用;
  OSEventTbl和OSEventGrp:等待事件表,类似于任务就绪表OSRdyTbal与OSRdyGrp;
  OSEventCnt:用来给锁或者信号量计数。

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)          */
    INT8U    OSEventGrp;                     /* Group corresponding to tasks waiting for event to occur */
    INT8U    OSEventTbl[OS_EVENT_TBL_SIZE];  /* List of tasks waiting for event to occur                */
    }OS_EVENT

等待事件的任务会加入等待队列,由变量OSEventTbl和OSEventGrp实现,实现原理与任务就绪表的实现原理相同,均采用优先级位图法,这里不加赘述。下面介绍关于ECB的相关操作。

1. 将任务加载置任务就绪表

将任务加载至事件等待列表过程与将任务加载至就绪列表相同,具体代码如下:

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

2. 将任务从等待列表移除

将任务从等待列表移除过程与将任务从就绪列表移除相同,具体代码如下:

if((pevent->OSEventTbl[prio >> 3] &= ~OSMapTbl[prio & 0x07])== 0){
	pevent->OSEventGrp &= ~OSMapTbl[prio >> 3];
}

3. 找到等待ECB的最高优先级任务

y = OSUnMapTbl[pevent->OSEventGrp];
x = OSUnMapTbl[pevent->OSEventTbl[y]];
prio = (y << 3) + x;

4. ECB空闲链表

各个事件的ECB数量取决于定义在OS_CFG.H中的OS_MAX_EVENTS。在函数OS_InitEventList()中进行初始化。当任一事件(信号量、锁、邮箱、消息队列)被创造时,就会从空闲列表移除并初始化。
在这里插入图片描述
OS_InitEventList()函数如下:

static void OS_InitEventList(void)
{
 #if(OS_MAX_EVENTS > 1)
    INT16U     i;
    OS_EVENT  *pevent1;
    OS_EVENT  *pevent2;
    OS_MemClr((INT8U *)&OSEventTbl[0], sizeof(OSEventTbl)); /* Clear the event table                   */
    pevent1 = &OSEventTbl[0];
    pevent2 = &OSEventTbl[1];
    for (i = 0; i < (OS_MAX_EVENTS - 1); i++) {             /* Init. list of free EVENT control blocks */
        pevent1->OSEventType    = OS_EVENT_TYPE_UNUSED;
        pevent1->OSEventPtr     = pevent2;
        pevent1++;
        pevent2++;
    }
    pevent1->OSEventType            = OS_EVENT_TYPE_UNUSED;
    pevent1->OSEventPtr             = (OS_EVENT *)0;
#endif
    OSEventFreeList                 = &OSEventTbl[0];
#else
    OSEventFreeList                 = &OSEventTbl[0];       /* Only have ONE event control block       */
    OSEventFreeList->OSEventType    = OS_EVENT_TYPE_UNUSED;
    OSEventFreeList->OSEventPtr     = (OS_EVENT *)0;
}

5. 初始化ECB,OS_EventWaitListInit()

函数OS_EventWaitListInit()用来初始化事件等待列表,在事件被创建时调用(OSSemCreate()、OSMutexCreate()、OSMboxCreate()和OSQcreate())。

void  OS_EventWaitListInit (OS_EVENT *pevent)
{
#if OS_LOWEST_PRIO <= 63
    INT8U  *ptbl;
#else
    INT16U *ptbl;
#endif
    INT8U   i;

    pevent->OSEventGrp = 0;                      /* No task waiting on event                           */
    ptbl               = &pevent->OSEventTbl[0];

    for (i = 0; i < OS_EVENT_TBL_SIZE; i++) {
        *ptbl++ = 0;
    }
}

6. 任务就绪,OS_EventTaskRdy()

当事件接收到了信号时,在等待列表内的最高优先级的任务需要加入任务就绪列表,并将其移除事件等待列表。该函数被POST函数调用。

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 > 63
    INT16U  *ptbl;
#endif


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

    ptcb                  =  OSTCBPrioTbl[prio];        /* Point to this task's OS_TCB                 */
    ptcb->OSTCBDly        =  0;                         /* Prevent OSTimeTick() from readying task     */
#if ((OS_Q_EN > 0) && (OS_MAX_QS > 0)) || (OS_MBOX_EN > 0)
    ptcb->OSTCBMsg        =  pmsg;                      /* Send message directly to waiting task       */
#else
    pmsg                  =  pmsg;                      /* Prevent compiler warning if not used        */
#endif
    ptcb->OSTCBStat      &= ~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 > 0)
    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);
}

7. 将任务加入事件等待列表,OS_EventTaskWait()

当ECB正在被占用时,任务需要等待,便要将其从就绪列表移除,加入等待列表。

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]  &= ~OSTCBCur->OSTCBBitX;
    if (OSRdyTbl[y] == 0) {
        OSRdyGrp &= ~OSTCBCur->OSTCBBitY;         /* Clear event grp bit if this was only task pending */
    }
}

8. 任务等待超时,随即加入就绪列表,OS_EventTO()

void  OS_EventTaskRemove (OS_TCB   *ptcb,
                          OS_EVENT *pevent)
{
    INT8U  y;


    y                       =  ptcb->OSTCBY;
    pevent->OSEventTbl[y]  &= ~ptcb->OSTCBBitX;         /* Remove task from wait list                  */
    if (pevent->OSEventTbl[y] == 0) {
        pevent->OSEventGrp &= ~ptcb->OSTCBBitY;
    }
	OSTCBCur->OSTCBStat     = OS_STAT_RDY;
	OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;
}
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值