对ECB的操作一般包括:
* 初始化一个事件控制块 (void OS_EventWaitListInit (OS_EVENT *pevent))
* 使一个任务进入就绪态 (INT8U OS_EventTaskRdy (OS_EVENT *pevent, void *msg, INT8U msk))
* 使一个任务进入等待某事件的状态 (void OS_EventTaskWait (OS_EVENT *pevent))
* 因为等待超时而使一个任务进入就绪态 (void OS_EventTO (OS_EVENT *pevent))
对OS_EventTaskRdy()函数和OS_EventTO函数的调用都需要关中断。
1. OS_EventWaitListInit (OS_EVENT *pevent)
此函数被与ECB建立相关的函数调用,如OSSemCreate()、OSMutexCreate()、OSQCreate()和OSMboxCreate()。函数功能就是对ECB中的等待任务列表进行初始化,函数创建时,等待任务列表初始化为空。这个函数是对内的,即此函数可以被uC/OS II调用,用户应用程序不可以直接调用此函数。代码如下:
#if ((OS_Q_EN > 0) && (OS_MAX_QS > 0)) || (OS_MBOX_EN > 0) || (OS_SEM_EN > 0) || (OS_MUTEX_EN > 0)
void OS_EventWaitListInit (OS_EVENT *pevent)
{
INT8U *ptbl;
pevent->OSEventGrp = 0x00;
ptbl = &pevent->OSEventTbl[0];
#if OS_EVENT_TBL_SIZE > 0
*ptbl++ = 0x00;
#endif
#if OS_EVENT_TBL_SIZE > 1
*ptbl++ = 0x00;
#endif
#if OS_EVENT_TBL_SIZE > 2
*ptbl++ = 0x00;
#endif
#if OS_EVENT_TBL_SIZE > 3
*ptbl++ = 0x00;
#endif
#if OS_EVENT_TBL_SIZE > 4
*ptbl++ = 0x00;
#endif
#if OS_EVENT_TBL_SIZE > 5
*ptbl++ = 0x00;
#endif
#if OS_EVENT_TBL_SIZE > 6
*ptbl++ = 0x00;
#endif
#if OS_EVENT_TBL_SIZE > 7
*ptbl = 0x00;
#endif
}
#endif
上面的代码功能比较简单,唯一需要注意的是,Labrosse先生使用条件编译代替了for循环,这样做的目的是减少编译时间(具体的效率,暂不清楚)。
2. INT8U OS_EventTaskRdy (OS_EVENT *pevent, void *msg, INT8U msk)
当某事件发生时,要将等待该事件任务列表中优先级最高的的任务置于就绪态,信号量、互斥型信号量、消息邮箱、消息队列所对应的POST函数都会调用OS_EventTaskRdy()。这个函数是对内的,即此函数可以被uC/OS II调用,用户应用程序不可以直接调用此函数。源码如下:
#if OS_EVENT_EN > 0
INT8U OS_EventTaskRdy (OS_EVENT *pevent, void *msg, INT8U msk)
{
OS_TCB *ptcb;
INT8U x;
INT8U y;
INT8U bitx;
INT8U bity;
INT8U prio;
y = OSUnMapTbl[pevent->OSEventGrp];
bity = OSMapTbl[y];
x = OSUnMapTbl[pevent->OSEventTbl[y]];
bitx = OSMapTbl[x];
prio = (INT8U)((y << 3) + x);
if ((pevent->OSEventTbl[y] &= ~bitx) == 0x00) {
pevent->OSEventGrp &= ~bity;
}
ptcb = OSTCBPrioTbl[prio];
ptcb->OSTCBDly = 0;
ptcb->OSTCBEventPtr = (OS_EVENT *)0;
#if ((OS_Q_EN > 0) && (OS_MAX_QS > 0)) || (OS_MBOX_EN > 0)
ptcb->OSTCBMsg = msg;
#else
msg = msg;
#endif
ptcb->OSTCBStat &= ~msk;
if (ptcb->OSTCBStat == OS_STAT_RDY) {
OSRdyGrp |= bity;
OSRdyTbl[y] |= bitx;
}
return (prio);
}
#endif
需要注意的是if (ptcb->OSTCBStat == OS_STAT_RDY),这说明最高优先级任务得到该事件后不一定就能进入就绪态,也许该任务由于其他原因“suspend”了。
3. void OS_EventTaskWait (OS_EVENT *pevent)
当某任务等待某事件的发生时,信号量、互斥型信号量、消息邮箱、消息队列所对应的PEND函数就会调用OS_EventTaskWait(),是当前任务脱离就绪态,并放到相应的ECB的任务等待表中。这个函数是对内的,即此函数可以被uC/OS II调用,用户应用程序不可以直接调用此函数。源码如下:
#if OS_EVENT_EN > 0
void OS_EventTaskWait (OS_EVENT *pevent)
{
OSTCBCur->OSTCBEventPtr = pevent;
if ((OSRdyTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0x00) {
OSRdyGrp &= ~OSTCBCur->OSTCBBitY;
}
pevent->OSEventTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX;
pevent->OSEventGrp |= OSTCBCur->OSTCBBitY;
}
#endif
4. void OS_EventTO (OS_EVENT *pevent)
这个函数牵涉到任务等待超时问题,uC/OS II中可以为任务等待设置一个等待时间,如果在规定的时间内任务等待的事件得不到相应(没有发生),那么OSTimeTick()函数会因为等待超时而将任务置为就绪态。信号量、互斥型信号量、消息邮箱、消息队列所对应的PEND函数就会调用OS_EventTO()函数,完成上述工作。这个函数是对内的,即此函数可以被uC/OS II调用,用户应用程序不可以直接调用此函数。源码如下:
#if OS_EVENT_EN > 0
void OS_EventTO (OS_EVENT *pevent)
{
if ((pevent->OSEventTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0x00) {
pevent->OSEventGrp &= ~OSTCBCur->OSTCBBitY;
}
OSTCBCur->OSTCBStat = OS_STAT_RDY;
OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;
}
#endif