ucos通信邮箱的理解
? 學習過信號量之后再來看郵箱,發現他們是非常相似的,甚至有時候郵箱可以當做信號量來使用,郵箱相對信號量而言,只是多傳遞一個指針變量
和信號量相似,ucos提供了5個對郵箱操作的函數它們是:
1.建立一個郵箱,OSMboxCreate()
2.等待一個郵箱的消息? OSMboxPend()
3.發送一個消息到郵箱,OSMboxPost()
4.無等待從郵箱中得到一個消息,OSMboxAccept();
5.查詢一個郵箱的狀態 OSMboxQuery();
使用郵箱之前,必須先建立該郵箱,該操作可以通過調用OSMboxCreate函數來完成,并且要指定指針的初始化值,一般情況下,這個初始值是NULL,
但也可以初始化一個郵箱,使其在最開始就包含一條消息,如果使用郵箱的目的是用來通知任務某一個事件已經發生(發送一條消息),那么就要初始化該郵箱為null,
如果用戶用郵箱來共享資源,那么就要初始化該郵箱為一個非null指針,在這種情況下,該郵箱被當成一個二值信號量使用
? OS_EVENT *OSMboxCreate(void *msg)
? {
?????? OS_EVENT *pevent;
?????? OS_ENTER_CRITICAL();
?????? pevent =OSEventFreeList;
????? if(OSEventFreeList!=(OS_EVENT*)0){
???????????????????OSEventFreeList=(OS_EVENT*)OSEventFreeList->OSEventPtr;
???? }
????? OS_EXIT_CRITICAL();
????? if(pevent!=(OS_EVENT*)0)
???? {
??????? pevent->OSEventType=OS_EVENT_TYPE_MBOX;?? (1)
?????? pevent->OSEventPtr=msg?????????????????? (2)
??????? OSEventWaitListInit(pevent);????????????
?
???? }
????? return (pevent)?;? (3)
?
? }
仔細看看,其實和創建一個信號量的過程幾乎是一樣的,先申請一個空事件控制塊,接著初始化這個事件控制塊,最后返回一個紙箱這個事件控制塊的,不同之處在于事件
控制塊的類型被設置成OS_EVENT_TYPE_MBOX 以及使用OSEventPtr來容納消息指針。
?
接著來看等待郵箱函數實現代碼:
void *OSMboxPend(OS_EVENT *pevent,INT16U timeout,INT8U *err)
{
??? void *msg;
???? OS_ENTER_CRITICAL();
???? if(pevent->OSEventType!=OS_EVENT_TYPE_MBOX)???????????????? (1)
??? {
????????????? OS_EXIT_CRITICAL();
???????????? *err=OS_ERR_EVENT_TYPE;
?????????????? return((void*)0);
???? }
??????? msg=pevent->OSEventPtr;
??????? if(msg!=(void*)0)??????????????????????? (2)
?????? {
??????????? pevent->OSEventPtr=(void*)0;????????????? (3)
?????????? OS_EXIT_CRITICAL();
?????????? *err=OS_NO_ERR;
???? }else if(OSIntNesting>0)?????????????????????? (4)
???? {
??????????????OS_EXIT_CRITICAL();
???????????????*err=OS_ERR_PEND_ISR;
???? }
???? else
???? {
??????????? OSTCBCur->OSTCBStat|=OS_STAT_MBOX;????????????? (5)
?????????? OSTCBCur->OSTCBDly=timeout;
?????????? OSEventTaskWait(pevent);
?????????? OS_EXIT_CRITICAL();
?????????? OSSched();
?????????? OS_ENTER_CRITICAL();
??????????? if((msg=OSTCBCur->OSTCBMsg)!=(void*)0)????????? (6)
?????????? {
?????????????????????? OSTCBCur->OSTCBMsg =(void*)0;
????????????????????? OSTCBCur->OSTCBStat=OS_STAT_RDY;
????????????????????? OSTCBCur->OSTCBEventPtr=(OS_EVENT*)0;
???????????????????????OS_EXIT_CRITICAL();
????????????????????? *err =OS_NO_ERR;
?????????? }
????????? else if(OSTCBCur->OSTCBStat&OS_STAT_MBOX)????? (7)
???????? {
??????????????????? OSEventTo(pevent);??????????? (8)
?????????????????? OS_EXIT_CRITICAL();???????
?????????????????? msg?? =(void*)0;??????????????????? (9)
??????????????????? *err? =OS_TIMEOUT;
???????? }
??????? else
???????? {
?????????????????? msg =pevent->OSEventPtr;??? (10);
????????????????? pevent->OSEventPtr? =(void*)0;?????????? (11)
????????????????? OSTCBCur->OSTCBEventPtr =(OS_EVENT*)0;??????? (12)
???????????????? OS_EXIT_CRITICAL();
????????????????? *err? =OS_NO_ERR;
????????? }
?
??? }
??????? return(msg);
}
同樣,它和OSSemPend()也相似,說白了就是先看有沒有有用的消息,要使沒有,就該把任務掛起來。
OSMboxPend首先檢查該事件控制塊是由OSMboxCreate()函數建立(1)。當OSEventPtr域是一個非
NULL的指針時,說明該郵箱有可用的消息(2);這種情況下,OSMboxPend()函數將該域的值復制到句柄變量
msg中,然后將OSEventPtr置為null,這正是我們期望的,也是執行OSMboxPend函數最快的路徑。
如果此時郵箱中沒有消息是可用的額(OSEventPtr域是null指針),OSMboxPend函數檢查它的調用者是否是中斷服務子程序。
像OSSemPend函數一樣,不能在中斷服務子程序中調用OSMboxPend(),因為中斷服務子程序是不能等待的,但是如果郵箱有可用的消息,
即使從中斷服務子程序中調用OSMboxPend()函數,也一樣是成功的。如果沒有可用的消息,OSMboxPend的調用任務就被掛起,直到郵箱中有了
消息或者等待超時時(5).當有其它任務向該郵箱發送了消息(或等待時間超時時),這時,該任務再一次成為最高任務優先級任務,OSSched()返回,這時,
OSMboxPend()函數要檢查是否有消息被放到該任務的任務控制塊中(6),如果有,那么該函數調用成功,對應的消息被返回到調用的函數
?
發送一個消息到郵箱中OSMboxPost()的代碼如下:
INT8U OSMboxPost(OS_EVENT *pevent,void *msg)
{
?? OS_ENTER_CRITICAL();
?? if(pevent->OSEventType!=OS_EVENT_TYPE_MBOX)???? (1)
? {
????????????? OS_EXIT_CRITICAL();
???????????? return(OS_ERR_EVENT_TYPE);
? }
if(pevent->OSEventGrp)???????????????????????????????? (2)
{
???? OSEventTaskRdy(pevent,msg,OS_STAT_MBOX);??????? (3)
????? OS_EXIT_CRITICAL();
????? OSSched();??????????????????? (4)
????? return(OS_NO_ERR);
}
else
{
??? if(pevent->OSEventPtr!=(void*)0)???????????? (5)
? {
??????? OS_EXIT_CRITICAL();
?????? return(OS_MBOX_FULL);
?}
?else
{
??? pevent->OSEventPtr =msg? ;???????????????????????? (6)
??? OS_EXIT_CRITICAL();
??? return(OS_NO_ERR);
}
}
}
?
?
發送一個消息到郵箱和發送一個信號量也相似,就絲毫查看有沒有任務在等待這個消息,如果有就把哪個任務從睡眠態拉回就就緒態。
代碼的詳細解釋如下:
檢查了事件控制塊是否是一個郵箱后(1),OSMboxPost()函數還要檢查是否有任務等待該郵箱匯總的消息(2)。如果事件控制塊中的OSEventGrp域包含非零值,
就暗示有任務在等待該消息,這時,調用OSEventTaskRdy()將其中的最高級優先級任務從等待列表中刪除,加入系統的就緒任務列表中,準備運行,然后,調用OSSched()(4)函數,檢查該任務十分是系統中最高優先級的就緒任務,如果是,這些任務切換【僅當OSMboxPost()】函數是由任務調用時,該任務得以執行,如果該任務不是最高優先級的任務,OSSched()返回,OSMboxPost()的調用函數繼續執行,如果沒有任務任務等待該消息,指向消息的指針就被保存到郵箱中(6)(假設此時郵箱匯總的指針不是非NULL的【5】),這樣,下一個調用OSMboxPend函數的任務就可以立刻得到該消息了。
#define? TASK_STK_SIZE?? 512
char *s ;//MyTask發送的消息指針,
char *ss;//YouTask接收到的消息的指針
INT8U err;
INT8U y=0;
INT32U Times=0;
OS_EVENT *Str_Box;? //定義事件控制塊指針,定義消息郵箱的指針
OS_STK??? StartTask[TASK_STK_SIZE];
OS_STK???? MyTaskStk[TASK_STK_SIZE];
OS_STK???? YouTaskStk[TASK_STK_SIZE];
void StartTask(void *data);
void MyTask(void *data);
void YouTask(void *data);
void main(void)
{
??? OSInit();
??? Str_Box=OSMboxCreate((void*)0);//創建消息郵箱,返回值指向創建消息郵箱指針,初始值為null 表示創建的消息郵箱沒有內容。
???? OSTaskCreate(StartTask,(void*)0,&StartTaskStk[TASK_STK_SIZE-1],0);?
?? ?OSStart();
}
?
void StartTask(void *pdata)
{
#if OS_CRITICAL_METHOD==3
??? OS_CPU_SR?? cpu_sr;
#endif
?? INT16S? key;
?? pdata=pdata;
?? OSStatInit();
?????? OSTaskCreate(MyTask,(void*)0,&StartTaskStk[TASK_STK_SIZE-1],1);?
?????????? OSTaskCreate(YouTask,(void*)0,&StartTaskStk[TASK_STK_SIZE-1],2);?
?? for(;;)
?? {
???????? if(PC_GetKey(&key)==TRUE)
???????? {
????????????? if(key==0x1B)
????????????? {
???????????????????? PC_DOSReturn();
??????????????? }
???????? }
?????????????? OSTimeDlyHMSM(0,0,3,0);
?? }
}
?
void MyTask(void *pdata)
{
#if OS_CRITICAL_METHOD==3
???? OS_CPU_SR? cpu_sr;
#endif
??? pdata=pdata;
? for(;;)
? {
?????? sprintf(s,"%d",times);//把Times賦值給s
??????? OSMboxPost(Str_Box,s);//發送消息s 其中兩個參數Str_Box是OS_EVENT *pevent表示消息郵箱指針,s是void*msg表示消息指針
???????????????????????????????????????????????? 該函數表示把消息s發送到消息郵箱Str_Box中
?????????????Times++;//MyTask的運行次數加1
??????????? OSTimeDlyHMSM(0,0,1,0);
? }
}
?
void YouTask(void *pdata)
{
? #if OS_CRITICAL_METHOD==3
??? OS_CPU_SR cpu_sr;
? #endif
?? pdata=pdata;
?? for(;;)
??? {
???????? ss=OSMboxPend(Str_Box,10,&err);//請求消息郵箱參數表示:Str_Box是消息郵箱指針,10表示等待時間 ss是郵箱中的消息指針
????????? OSTimeDlyHMSM(0,0,1,0);?? //等待1s
??? }
?
}
//OSMboxPend時指定等待時間為10,所以當等待時間到了,即使郵箱中還是無消息,YouTask也會進入就緒態的,然后繼續往下運行,但是
?當OSMboxPend的等待時間設置為0,表示無限等待。
?
?
?
?
總結
以上是生活随笔為你收集整理的ucos通信邮箱的理解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 从T型人才理解ALM Polarion
- 下一篇: PSI-Blast最新版单机安装,批量生