到目前爲止,所有的線程間通信方法都只用於觸發線程的執行;他們不支持線程間的數據交換。很明顯,在實際程序中,我們需要在線程之間移動數據。這可以通過讀取和寫入全局變量來完成,這種方式,除了一個非常簡單的程序之外,嘗試保證數據完整性將非常困難並且容易出現無法預料的錯誤。 線程之間的數據交換需要更正式的異步通信方法。
CMSIS-RTOS提供了兩種線程之間的數據傳輸方法。 第一種方法是消息隊列,它在兩個線程之間創建緩衝數據“管道”。 消息隊列旨在傳輸整數值。
第二種形式的數據傳輸是郵件隊列。 這與消息隊列非常相似,只是它傳輸數據塊而不是單個整數。
消息和郵件隊列都提供了一種在線程之間傳輸數據的方法。這允許您將設計視爲由數據流互連的對象(線程)的集合。數據流由消息和郵件隊列實現。 這提供了數據傳輸的緩衝區和線程之間良好定義的通信接口。基於通過郵件和消息隊列連接的線程的系統級設計開始,您可以編寫項目的不同子系統,如果在團隊中工作,這很有用。此外,由於每個線程都有明確定義的輸入和輸出,因此很容易隔離以進行測試和代碼複用。
基於RTOS的項目的系統級視圖包括由消息和郵件隊列形式的數據流連接的線程對象。
消息隊列
設置消息隊列,我們首先需要分配內存資源。
osMessageQId Q_LED; /*聲明消息隊列ID*/
osMessageQDef (Q_LED,16_Message_Slots,unsigned int);
/*定義消息隊列結構體, 消息隊列ID,
16_Message_Slots指示空間大小爲16,unsigned int指示空間類型*/
這定義了具有16個存儲元素的消息隊列。 在此特定隊列中,每個元素都定義爲unsigned int。
雖然我們可以將數據直接發佈到消息隊列中,但也可以發佈指向數據對象的指針。
osEvent result;
我們還需要定義一個osEvent變量,該變量將用於檢索隊列數據。 osEvent變量是一個聯合體變量,允許您以多種格式從消息隊列中檢索數據。
union{
uint32_t v
void *p
int32_t signals
}value
osEvent聯合體可以將您將發佈到消息隊列的數據作爲unsigned int或void指針讀取。 一旦創建了內存資源,我們就可以在一個線程中聲明消息隊列。
Q_LED = osMessageCreate(osMessageQ(Q_LED),NULL); /*在進程中創建消息隊列*/
一旦創建了消息隊列,我們就可以從一個線程將數據放入隊列。
osMessagePut(Q_LED,0x0,osWaitForever); /*在進程中發送數據到消息隊列*/
然後從另一個隊列中讀取。
result = osMessageGet(Q_LED,osWaitForever); /* 在另一進程中獲取消息隊列數據*/
LED_data = result.value.v;
消息隊列聯繫
在本練習中,我們將研究在兩個線程之間定義消息隊列,然後使用它來發送過程數據。
在Pack Installer中選擇“Ex 16 Message Queue”並將其複製到教程目錄中。
打開Main.c並查看消息隊列初始化代碼。
int main (void) {
LED_Init ();
Q_LED = osMessageCreate(osMessageQ(Q_LED),NULL);
我們在主線程中定義和創建消息隊列以及事件結構。
osMessagePut(Q_LED,0x1,osWaitForever);
osDelay(100);
然後在其中一個線程中,我們可以發佈數據並在第二個線程中接收數據。
result = osMessageGet(Q_LED,osWaitForever);
LED_On(result.value.v);
構建項目並啓動調試器。
在led_thread1中設置斷點。
現在運行代碼並在數據到達時觀察數據。
自己實現的一個小例子:https://download.csdn.net/download/white_loong/10833909