從零開始學習UCOSII操作系統10--消息郵箱
1、什麼是消息郵箱?
UCOSII中的另一種的通信機制,可以使得一個任務或者中斷服務子程序向另一個任務發送一個指針型的變量,通常指針指向一個包含了消息的特定數據結構。
提供了6種操作郵箱的接口函數:
OSMboxCreate():創建郵箱也就是初始化郵箱的函數
OSMboxPend():請求郵箱的函數,也就是沒有郵箱發送過來的話,就會一直處於等待的狀態。
OSMboxPost():接收郵箱的函數,接收到郵箱的內容,就可以從郵箱的等待列表中移除,並把任務進入就緒的列表當中。
OSMboxPostOpt():
OSMboxAccept():無等待的郵箱接口
OSMboxQuery():查詢郵箱的接口
2、怎麼使用郵箱?
任務、中斷服務子程序和郵箱之間的關係,沙漏表示OSMboxPend()所定義的超時時限。郵箱包含的內容是一個指向一條消息的指針。指針所指向的內容是可以指定的。
PS:一個郵箱只能包含一個這樣的指針(郵箱爲滿的時候)或者一個指向NULL的指針(郵箱爲空的時候,也就是不指向所有的內容)
注意的幾點?
任務和中斷服務子程序都可以調用函數OSMboxPost()或者OSMboxPostopt()
然而僅僅只有任務可以調用OSMboxDel(),OSMboxPend()以及OSMboxQuery()函數。
應用程序可以使用任意多個郵箱,其最大的數目就是由OS_CFG.h文件中的配置常數OS_MAX_EVENTS設定。
3、使用郵箱的API函數
(1)創建郵箱的函數OSMboxPend():使用郵箱之前,必須先建立郵箱,該操作可以通過調用OSMboxCreate()函數來完成,並且定義指針的初始值,一般情況下面,這個初始值是NULL,但是也可以初始化郵箱在最開始的時候就包含一條信息。
OS_EVENT *OSMboxCreate(void * msg)
{
OS_EVENT * pevent; //局部建立一個事件控制塊列表
pevent = OSEventFreeList; //插入到事件控制塊鏈表中
if(OSEventFreeList != (OS_EVENT *)0)
{
OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
}
if(pevent != (OS_EVENT *)0)
{
pevent->OSEventType = OS_EVENT_TYPE_MBOX;
pevent->OSEventCnt = 0; //郵箱不用使用這個變量
pevent->OSEventPtr = msg;
OS_EventWaitListInit(pevent);
}
return (pevent);
}
(2)等待郵箱中的消息OSMboxPend()
PS:需要注意的是:如果郵箱中有消息的話,那麼從郵箱中取出該消息,返回給調用函數,並將NULL指針存入郵箱中,同時OSMboxPend()函數將無措的代碼返回給它的調用函數,這個返回結果表示,已經由另一個任務或者中斷服務子程序將消息發送到郵箱中,這也是運行OSMboxPend()函數最快的情況。
如果郵箱爲空的話,那麼調用OSMboxPend函數的任務要進入睡眠狀態,等待另一個任務,通過發送郵箱發送消息。允許定義一個最長等待時間作爲他的參數,這樣可以避免該任務無限期的等待郵箱消息。
void * OSMboxPend(OS_Event *pevent, INT16U timeout,INT8U *err)
{
void *msg;
msg = pevent->OSEventPtr;
if(msg != (void *)0)
{
pevent->OSEventPtr = (void *)0;
OS_EXIT_CRITICAL();
* err = OS_NO_ERR;
return msg;
}
//設置郵箱的初始化的狀態:
OSTCBCur->OSTCBStat |= OS_STAT_MBOX;
OSTCBCur->OSTCBDly = timeout;
OSEventTaskWait(pevent);
OS_EXIT_CRITICAL();
msg = OSTCBCur->OSTCBMsg;
if(msg != (void *)0)
{
OSTCBCur->OSTCBMsg = (void *)0;
OSTCBCur->OSTCBStat = OS_STAT_RDY;
OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;
*err = OS_NO_ERR;
return msg;
}
}
(3)向郵箱中發送一則消息OSMboxPost()
INT8U OSMboxPost(OS_EVENT * pevent, void *msg)
{
//檢查一下事件控制塊中是否有任務等待
if(pevent->OSEventGrp != 0x00)
{
//如果有的話就直接加入到事件隊列中
OS_EventTaskRdy(pevent, msg, OS_STAT_MBOX);
//任務的切換
OS_Sched();
return (OS_NOE_ERR);
}
if(pevent->OSEventPtr != (void *)0)
{
//返回一個郵箱已滿的信息,就是說不要重複覆蓋郵箱的內容
return OS_MBOX_FULL;
}
//前面的都沒有了,所以傳遞一個郵箱進入
pevent->OSEventPtr = msg;
OS_EXIT_CRITICAL();
return OS_NO_ERR;
}
4、怎麼使用郵箱來進行延時
郵箱的等待超時的功能可以用來模仿OSTimeDly()函數的延時,如果在指定的時間段TIMEOUT內沒有消息到來,Task1函數將繼續執行,實質上,這與OSTimeDly(TimeOUT)內沒有消息到來。
如果Task2在指定的時間結束之前,向該郵箱發送一個dummy消息,那麼Task1就會提前開始繼續執行,這與調用函數OSTimeDlyResume()功能是一樣的。
注意:這裏忽略了對返回消息的檢查,因爲此時並不需要從另一個任務或者中斷服務子程序得到消息。