UC/OS II事件管理(1)
阿新 • • 發佈:2019-01-23
ucosii支援事件,事件包括訊號量、訊息等機制。需要配置OS_EVENT_EN、OS_MAX_EVENTS等相關的巨集。
事件控制塊(ECB)
事件控制塊(ECB)是事件管理的核心資料結構。其定義如下:
typedef struct os_event {
INT8U OSEventType; //事件型別,具體有訊號量、訊息郵箱、訊息佇列、互斥訊號量、事件標誌組,都相關的巨集
void *OSEventPtr; //指向下一個ECB或者是訊息或是佇列的指標
INT16U OSEventCnt; //訊號量的計數值,就只跟訊號量有關係,跟其他事件沒有關係
OS_PRIO OSEventGrp; //等待事件標誌表
OS_PRIO OSEventTbl[OS_EVENT_TBL_SIZE]; //等待事件標誌組
#if OS_EVENT_NAME_EN > 0u
INT8U *OSEventName; //事件名稱
#endif
} OS_EVENT; #endif 等待事件表和等待事件標誌組跟就緒表和就緒組基本上一樣。 事件控制塊在ucosii中以陣列的方式定義OS_EVENT OSEventTbl[OS_MAX_EVENTS]; OS_MAX_EVENTS可以根據需要自己配置,系統預設值是10。 空閒的時間控制塊都組成一個單鏈表,並且由指標OSEventFreeList指向該連結串列。 事件控制塊初始化函式OS_InitEventList
該函式在系統開始前做在呼叫OSInit()進行初始化的時候需要用到該函式。
該函式主要功能的將ucosii中定義的事件控制塊形成連結串列,並且對各個時間控制塊的成員進行相應的初始化。
等待事件設定函式OS_EventTaskWait
這個函式是將對應的事件控制塊以及相應的事件進行設定。這個函式是將對應的事件控制塊以及相應的事件和申請任務進行設定。將當前的任務在對應ECB中登記,更新任務的執行狀態。
void OS_EventTaskWait (OS_EVENT *pevent) //os_core.c中定義
{
INT8U y;
OSTCBCur->OSTCBEventPtr = pevent; //將任務控制塊的事件控制塊指標指向該事件控制塊
pevent->OSEventTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX; //更新表和陣列
pevent->OSEventGrp |= OSTCBCur->OSTCBBitY;
y = OSTCBCur->OSTCBY;
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;
} } 取消等待事件(OS_EventTaskRemove)就是將該上面函式的逆。 等待事件中的任務就緒OS_EventTaskRdy
當有事件發生的時候,就有必要更新事件控制塊,同時將在ECB事件表和就緒組進行更新,並將註冊的任務(此時應該已經是阻塞了)的狀態進行更新
INT8U OS_EventTaskRdy (OS_EVENT *pevent, void *pmsg, INT8U msk,INT8U pend_stat)
該函式的引數解釋:OS_EVENT *pevent 對應的事件控制塊 void *pmsg 訊息指標,只有在用到訊息的時候才會用到
INT8U msk 清除狀態的掩碼。前面我們知道,TCB中的OSTCBStat中不同位關於不同事件的標誌位,該掩碼就是用來消除因等待該事件而OSTCBStat相應的位。
NT8U pend_stat 表示等待(阻塞)任務等待結束,任務就緒的原因。可能是這幾個值
#define OS_STAT_PEND_OK 0u //正常結束,是事件發生
#define OS_STAT_PEND_TO 1u //等待超時
#define OS_STAT_PEND_ABORT 2u //異常
其程式碼主要如下:
找到最高優先順序的註冊任務
y = OSUnMapTbl[pevent->OSEventGrp];
x = OSUnMapTbl[pevent->OSEventTbl[y]];
prio = (INT8U)((y << 3u) + x);
ptcb = OSTCBPrioTbl[prio]; //指向任務等待優先順序最高的任務控制塊
ptcb->OSTCBDly = 0u; //將其等待事件清零(因為在等待的時間裡,時間發生了)
#if ((OS_Q_EN > 0u) && (OS_MAX_QS > 0u)) || (OS_MBOX_EN > 0u)
ptcb->OSTCBMsg = pmsg; //傳送訊息
#else
pmsg = pmsg; /* Prevent compiler warning if not used */
#endif ptcb->OSTCBStat &= (INT8U)~msk; //更新任務控制塊的狀態 ptcb->OSTCBStatPend = pend_stat; //跟新相應任務控制塊的阻塞狀態 /* See if task is ready (could be susp'd) */ if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY) { OSRdyGrp |= ptcb->OSTCBBitY; //更新就緒陣列和就緒表 OSRdyTbl[y] |= ptcb->OSTCBBitX;
} OS_EventTaskRemove(ptcb, pevent); //將該任務從該等待事件中取消 #if (OS_EVENT_MULTI_EN > 0u) if (ptcb->OSTCBEventMultiPtr != (OS_EVENT **)0) { //若是多事件等待,相關的操作,這個在後面再介紹 OS_EventTaskRemoveMulti(ptcb, ptcb->OSTCBEventMultiPtr); ptcb->OSTCBEventPtr = (OS_EVENT *)pevent; }
#endif return (prio); //返回就緒狀態的優先順序
} OS_EVENT; #endif 等待事件表和等待事件標誌組跟就緒表和就緒組基本上一樣。 事件控制塊在ucosii中以陣列的方式定義OS_EVENT OSEventTbl[OS_MAX_EVENTS]; OS_MAX_EVENTS可以根據需要自己配置,系統預設值是10。 空閒的時間控制塊都組成一個單鏈表,並且由指標OSEventFreeList指向該連結串列。 事件控制塊初始化函式OS_InitEventList
if (OSRdyTbl[y] == 0u) { /* Clear event grp bit if this was only task pending */
OSRdyGrp &= (OS_PRIO)~OSTCBCur->OSTCBBitY;
} } 取消等待事件(OS_EventTaskRemove)就是將該上面函式的逆。 等待事件中的任務就緒OS_EventTaskRdy
pmsg = pmsg; /* Prevent compiler warning if not used */
#endif ptcb->OSTCBStat &= (INT8U)~msk; //更新任務控制塊的狀態 ptcb->OSTCBStatPend = pend_stat; //跟新相應任務控制塊的阻塞狀態 /* See if task is ready (could be susp'd) */ if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY) { OSRdyGrp |= ptcb->OSTCBBitY; //更新就緒陣列和就緒表 OSRdyTbl[y] |= ptcb->OSTCBBitX;
} OS_EventTaskRemove(ptcb, pevent); //將該任務從該等待事件中取消 #if (OS_EVENT_MULTI_EN > 0u) if (ptcb->OSTCBEventMultiPtr != (OS_EVENT **)0) { //若是多事件等待,相關的操作,這個在後面再介紹 OS_EventTaskRemoveMulti(ptcb, ptcb->OSTCBEventMultiPtr); ptcb->OSTCBEventPtr = (OS_EVENT *)pevent; }
#endif return (prio); //返回就緒狀態的優先順序