1. 程式人生 > >uC/OS-II 學習筆記之:訊息郵箱

uC/OS-II 學習筆記之:訊息郵箱

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

更多原創“uC/OS-II學習筆記之:系列”基礎及嵌入式相關知識詳解,請訪問可樂虎部落格:

相信不會讓您失望!!
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

一、訊息郵箱的概念:

由圖可見:訊息郵箱裡裝的是訊息緩衝區的地址
    訊息郵箱是uC/OS-II中的一種通訊機制,可以使一個任務或者中斷服務子程式向另一個任務傳送一個指標型的變數,而該指標指向一個包含了“訊息(的地址)”的特定資料結
構(參:訊息郵箱 百度百科)。具體描述如下:
    為了適應不同資料在任務之間的傳遞,需要在儲存器中建立一個數據緩衝區,把要傳遞的資料放在這個緩衝區裡就能實現任務之間的通訊;如果把資料緩衝區的指標賦給一個
事件控制塊的成員OSEventPrt,同時使事件控制塊的成員OSEventType為常數OS_EVENT_TYPE_MBOX(此過程在訊息郵箱建立函式裡已實現,使用者不用管),則該事件控制塊就是訊息郵箱。由此可見,訊息郵箱就是一個特定的事件控制塊

。事件控制塊如下:
typedef struct
{
    INT8U  OSEventType;//事件的型別
    INT16U OSEventCnt;//訊號量計數器
    void   *OSEventPtr;//訊息或訊息佇列的指標
    INT8U  OSEventGrp;//等待事件的任務組
    INT8U  OSEventTbl[OS_EVENT_TBL_SIZE];//任務等代表
} OS_EVENT;

若定義一個事件控制塊:OS_EVENT *pEvent;
還定義一個空型別的指標:void *pMsg;
則訊息郵箱需要具備的基本條件是:
pEvent->OSEventType = OS_EVENT_TYPE_MBOX;
pEvent->OSEventPtr = msg;
此時事件控制塊pEvent就是一個郵箱(次要條件在此不考慮)。

二、訊息郵箱的相關函式:
(1)建立訊息郵箱函式:OS_EVENT *OSMboxCreate(void *pMsg)//pMsg為訊息的指標(初始值一般為(void*)0))
(2)向訊息郵箱傳送訊息函式:INT8U OSMboxPost(OS_EVENT *pEventT, void *pMsg)
(3)請求訊息郵箱函式:void *OSMboxPend(OS_EVENT *pEvent, INT16U timeout, INT8U *err) //timeout為超時定義,任務若在指定數目的時鐘節拍後還沒有得到訊息則恢復執行;若timeout為0則任務將持續等待訊息直到收到訊息才進入就緒。但最大的等待時間為65535個時鐘節拍。
(4)查詢郵箱狀態函式:INT8U OSMboxQuery(OS_EVENT *pEvent, OS_MBOX_DATA *pData)
(5)刪除郵箱函式:OS_EVENT *OSMboxDel(OS_EVENT *pEvent, INT8U opt, INT8U *err)

三、訊息郵箱的應用(建立、傳送、請求)舉例:
…………;//程式碼省略部分 
OS_EVENT *pMsgBox;//定義事件控制塊指標(指向訊息郵箱)
…………; 
void main(void)
{
    …………; 
    pMsgBox = OSMboxCreate((void *)0);//(1)建立訊息郵箱
    OSTaskCreate(StartTask, (void *)0, &StartTaskStk[TASK_STK_SIZE - 1], 0);//建立起始任務
    …………; 

    return 0;
}

void StartTask(void *pData)
{
    …………;
    //建立任務1
    OSTaskCreate(MyTask, (void *)0, &MyTaskStk[TASK_STK_SIZE - 1], 1);
    //建立任務2
    OSTaskCreate(YouTask, (void *)0, &YouTaskStk[TASK_STK_SIZE - 1], 2);
    …………;     
}

//任務1
void MyTask(void *pData)
{
    INT32U Times = 0;
    char *pMsg;
    …………; 
    while (1)
    {
        sprintf(pMsg, "%d", Times);//記錄執行次數
        OSMboxPost(pMsgBox, pMsg);//(2)向訊息郵箱傳送訊息
        Times++;
        OSTimeDlyHMSM(0, 0, 1, 0);//延時1秒
    }
}

//任務2
void YouTask(void *pData)
{
    char *pStr;
    …………; 
    while (1)
    {
        pStr = OSMboxPend(pMsgBox, 10, &err);//(3)請求訊息郵箱
        PC_DispStr(10, ++y, pStr, DISP_BGND_BLACK + DISP_FGND_WHITE);
        OSTimeDlyHMSM(0, 0, 1, 0);//延時1秒
    }
}

    現象:輸出結果為0、1、2、3……
    解析:任務1中Times每自增一次都會被sprintf函式轉換為字串,且將其地址儲存在pMsg中,然後將其作為訊息(的指標)傳送給郵箱;程式執行到任務2中時,再將郵箱中的訊息取出打印出來。

    注:訊息郵箱中裝的是訊息的地址而不是訊息本身,傳送訊息時也是傳送的訊息的地址!

參:   任哲 《嵌入式實時作業系統uC/OS-II原理及應用》
參:   盧有亮 《嵌入式實時作業系統uC/OS原理與實踐》