從零開始學習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;
}
}