事件控制块使用的几点须知:
(1)任务或者中断服务子程序可以给事件控住块ECB发送信号。
(2)中断服务子程序不能等待事件控制块ECB给它发送信号的。
(3)等待事件可以设置超时时间,后面会详细的说明实现的原理。
(4)多个任务可以同时等待同一个事件发生,在这种情况下面,当事件发生后,所有等待该事件的任务中,只有优先级最高的任务得到该事件并进入就绪状态。
(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;
prevent->OSEventGrp |= OSMapTbl[prio >> 3];
prevent->OSEventTbl[prio >> 3] |= OSMapTbl[prio & 0x07];
(1)事件控制块的总数由应用程序所需要的信号量、互斥型信号量、邮箱以及消息队列的总数决定。
也就是:#define OS_MAX_EVENTS 语句定义。
(2)所有的事件控制块ECB被链接成一个单向链表--空闲事件控制块,并对其进行初始化。每当建立一个信号量,互斥型信号量,就从该链表中取出空余事件控制块。
所有的任务之间进行的通信都需要通过调用这个事件控制块进行调用函数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;
}
}
就是简单的对就绪表进行相应的赋值就行。就是接收到相应的事件的时候把任务放置到就绪态中。
信号量、互斥型信号量、消息邮箱、消息队列所对应的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;
}
}