今天,做了uc/OS-II系統的訊息迴圈的實驗,寫一些收穫。
先說說訊息機制的原理。通過訊息迴圈可以實現基於時間驅動的應用程式,即每一個事件都會產生特定的訊息,然後這個訊息被發送到某個/某些任務訊息佇列中,任務讀取到訊息後作出相應的處理。任務訊息佇列一般採用FIFO結構,即最先發送的訊息任務會最先讀取到。
用uc/OS實現的系統訊息迴圈感覺類似windows編程的訊息機制。系統不斷輪詢來從訊息佇列中取出最近的訊息進行處理。當然,用uc/OS實現的訊息機制就要比windows的簡單多了。在uc/OS中,通訊機制裡面有一種就是訊息佇列,通過這種通訊方式我們就能在uc/OS中實現我們的訊息機制。
在uc/OS中,訊息佇列可以工作與一對一的工作方式,即一個任務發送訊息到訊息佇列,而另一個任務從訊息佇列中讀取訊息。這種方式簡單也常用。另外還有一種多對一的工作方式,即多個任務發送訊息佇列到同一個訊息佇列,而另外只有一個任務從這個訊息佇列中讀取資訊,這種即是我們實現訊息機制需要用到的工作方式。當然,訊息佇列還有其他工作方式,但是都不常用。
我們把訊息佇列作為任務訊息佇列,然後任務就可以通過讀取訊息佇列中的訊息來擷取訊息。當然,一般哪個任務需要處理訊息迴圈才會建立相應自己的任務訊息佇列。訊息的儲存需要空間,所以還需要定義一個數組來進行訊息的儲存。因為訊息的類型不同,所以數組的類型為void。而將任務隊列與任務訊息佇列儲存區串連起來的關鍵就是OS_EVENT *OSQCreate (void **start, INT16U size)訊息佇列建立函數。任務訊息的隊列建立需在啟動uc/OS之前。
實驗中用到的關於訊息函數已經有現成的了。在任務訊息標頭檔中,我們可以自訂訊息。
如:
#define TM_KEY
5762
#define TM_KEYDOWN 5763
......
定義好訊息結構體
typedef struct tagMSG
{
uint32 message; // 訊息值
uint32 wParam; // 訊息附加資訊1
uint32 lParam; // 訊息附加資訊2
} MSG;
然後是最重要的兩個訊息函數SendMessage()和GetMessage()。
/****************************************************************************
* 名稱:SendMessage()
* 功能:發送一個訊息,即訊息發送管理器。
* 根據實際情況,將訊息指派到不同的任務訊息佇列中。
* 入口參數:msg 所要發送的訊息(指標)
* 出口參數:操作成功返回TRUE,否則返回FALSE。
****************************************************************************/
uint8 SendMessage(MSG *msg)
{
uint32 message;
TMQ *target;
uint8 err;
message = msg->message;
switch(message)
{
case TM_KEY:
case TM_KEYDOWN:
case TM_KEYUP:
target = task_tmq; // 若是鍵盤訊息,向task1_tmq任務訊息佇列發送
break;
case TM_UART0RCV:
target = task_tmq; // 若是串口接收訊息,向task1_tmq任務訊息佇列發送
break;
// (在此添加使用者任務訊息指派處理)
default: target = NULL;
break;
}
err = OSQPost(target, msg);
if(err==OS_NO_ERR)
return(TRUE);
else
return(FALSE);
}
/****************************************************************************
* 名稱:GetMessage()
* 功能:等待一個訊息。當接收到訊息時才返回。
* 入口參數:tmq 等待的任務訊息佇列(指標)
* 出口參數:返回接收到的訊息。
****************************************************************************/
MSG *GetMessage(TMQ *tmq)
{
uint8 err;
return(OSQPend(tmq, 0, &err));
}
具體實現的代碼就不用寫了,重要是這個思想和實現方法。