RTOS 是一種軟件,可以盡可能高效地管理中央處理單元 (CPU)、微處理單元 (MPU) 甚至數(shù)字信號處理器 (DSP) 的時(shí)間。大多數(shù) RTOS 內(nèi)核都是用 C 編寫的,需要一小部分用 ASSEMBLY 語言編寫的代碼來使內(nèi)核適應(yīng)不同的 CPU 架構(gòu)。
RTOS 內(nèi)核為程序員提供了許多有用的服務(wù),例如多任務(wù)處理、中斷管理、通過消息隊(duì)列的任務(wù)間通信、信令、資源管理、時(shí)間管理、內(nèi)存分區(qū)管理等等。
應(yīng)用程序(即最終產(chǎn)品)基本上分為多個(gè)任務(wù),每個(gè)任務(wù)負(fù)責(zé)應(yīng)用程序的一部分。任務(wù)是一個(gè)簡單的程序,它認(rèn)為它自己擁有 CPU。每個(gè)任務(wù)都根據(jù)任務(wù)的重要性分配一個(gè)優(yōu)先級。
什么是消息隊(duì)列?
如圖 1 所示,消息隊(duì)列是一個(gè)內(nèi)核對象(即數(shù)據(jù)結(jié)構(gòu)),消息通過它從中斷服務(wù)例程 (ISR) 或任務(wù)發(fā)送(即,發(fā)布)到另一個(gè)任務(wù)(即,掛起)。一個(gè)應(yīng)用程序可以有任意數(shù)量的消息隊(duì)列,每個(gè)隊(duì)列都有自己的用途。例如,消息隊(duì)列可用于將從通信接口 ISR 接收到的數(shù)據(jù)包傳遞給任務(wù),該任務(wù)又負(fù)責(zé)處理數(shù)據(jù)包。另一個(gè)隊(duì)列可用于將內(nèi)容傳遞給將負(fù)責(zé)正確更新顯示的顯示任務(wù)。
圖 1.消息隊(duì)列是用于將內(nèi)容傳遞給任務(wù)的內(nèi)核對象。
消息通常是指向包含實(shí)際消息的存儲區(qū)域的空指針。但是,指針可以指向任何東西,甚至是接收任務(wù)要執(zhí)行的函數(shù)。因此,消息的含義取決于應(yīng)用程序。每個(gè)消息隊(duì)列都可以配置其將容納的存儲量。可以將消息隊(duì)列配置為保存單個(gè)消息(也稱為郵箱)或N條消息。隊(duì)列的大小取決于應(yīng)用程序以及接收任務(wù)在隊(duì)列填滿之前處理消息的速度。
如果一個(gè)任務(wù)掛起(即等待)一條消息并且隊(duì)列中沒有消息,那么該任務(wù)將阻塞,直到一條消息被發(fā)布(即發(fā)送)到隊(duì)列中。由于 RTOS 運(yùn)行其他任務(wù),因此等待任務(wù)在等待消息時(shí)不消耗 CPU 時(shí)間。如圖 1 所示,掛起的任務(wù)可以指定一個(gè)超時(shí)時(shí)間。如果在指定的超時(shí)時(shí)間內(nèi)沒有收到消息,則當(dāng)該任務(wù)成為最高優(yōu)先級任務(wù)時(shí),將允許該任務(wù)恢復(fù)執(zhí)行(即解除阻塞)。當(dāng)任務(wù)執(zhí)行時(shí),它基本上被告知它被恢復(fù)的原因是因?yàn)槌瑫r(shí),因此沒有收到消息。
消息隊(duì)列通常實(shí)現(xiàn)為先進(jìn)先出 (FIFO),這意味著接收到的第一條消息將是從隊(duì)列中提取的第一條消息。但是,某些內(nèi)核允許您發(fā)送被認(rèn)為比其他內(nèi)核更重要的消息,因此可以在隊(duì)列的頭部發(fā)布。換句話說,按照后進(jìn)先出 (LIFO) 的順序,使該消息成為任務(wù)提取的第一個(gè)消息。
消息隊(duì)列的一個(gè)重要方面是消息本身需要從發(fā)送到處理期間保持在范圍內(nèi)。這意味著您不能將指針傳遞給堆棧變量、可以被其他代碼更改的全局變量等等。為了使消息保持在范圍內(nèi),您通常會填充從池中獲取的結(jié)構(gòu)如圖 2 所示。發(fā)送消息的 ISR 或任務(wù)將從池中獲取一個(gè)結(jié)構(gòu),填充該結(jié)構(gòu),并將指向該結(jié)構(gòu)的指針發(fā)布到隊(duì)列中。接收任務(wù)將從隊(duì)列中提取指針,處理結(jié)構(gòu),完成后將結(jié)構(gòu)返回到池中。當(dāng)然,發(fā)送方和接收方都需要使用同一個(gè)池,除非數(shù)據(jù)結(jié)構(gòu)中的字段指示使用了哪個(gè)池。
圖 2.消息存儲區(qū)池
在 RTOS 中消息隊(duì)列的許多實(shí)現(xiàn)中,如果隊(duì)列已滿,發(fā)送到隊(duì)列的消息將被丟棄。通常這不是問題,應(yīng)用程序的邏輯可以從這種情況中恢復(fù)。但是,實(shí)現(xiàn)一種機(jī)制相當(dāng)容易,這樣發(fā)送任務(wù)將阻塞,直到接收方提取其中一條消息,如圖 3 所示:
1.計(jì)數(shù)信號量初始化為隊(duì)列可以接受的最大條目數(shù)對應(yīng)的值。
2.在允許發(fā)送消息到隊(duì)列之前,發(fā)送任務(wù)在信號量上掛起。如果信號量值為零,則發(fā)送方等待。
3.如果該值非零,則信號量計(jì)數(shù)遞減,并且發(fā)送方將其消息發(fā)布到隊(duì)列中。
4.消息的接收者像往常一樣在消息隊(duì)列中掛起一個(gè)。
5.當(dāng)接收到消息時(shí),接收者從隊(duì)列中提取指向消息的指針并向信號量發(fā)出信號,表明隊(duì)列中的條目已被釋放。
圖 3.如果隊(duì)列已滿,則阻止發(fā)送者。
如圖所示,此機(jī)制僅適用于兩個(gè)任務(wù),因?yàn)椴辉试S ISR 掛在信號量上。
消息隊(duì)列的其他用途
圖 4 顯示了消息隊(duì)列的不同用途:
1-4。如前所述,消息隊(duì)列通常用于將消息從 ISR 或任務(wù)發(fā)送到另一個(gè)任務(wù)。
5.但是,如果消息適合指針的字長,則不必發(fā)送實(shí)際消息并分配存儲區(qū)域。例如,如果指針是 32 位寬,那么您可以將從 12 位 ADC 讀取的模數(shù)轉(zhuǎn)換器 (ADC) 轉(zhuǎn)換為指針并通過消息隊(duì)列發(fā)送它。只要接收者知道將值轉(zhuǎn)換回整數(shù),它就是完全合法的。
6-7。如果任務(wù)知道消息不會發(fā)送給它,它可以使用超時(shí)機(jī)制將自己延遲一段時(shí)間。在這種情況下,能夠容納單個(gè)條目的隊(duì)列就足夠了。事實(shí)上,如果另一個(gè)任務(wù)或 ISR 發(fā)送消息,延遲將被中止,這可能是您想要實(shí)現(xiàn)的行為。
8.消息隊(duì)列可以用作信號量來簡單地向任務(wù)發(fā)出事件發(fā)生的信號。在這種情況下,消息可以是任何東西。隊(duì)列的大小取決于應(yīng)用程序需要緩沖多少信號。
9-10。消息隊(duì)列也可以用作二進(jìn)制信號量或計(jì)數(shù)信號量以進(jìn)行資源共享。對于二進(jìn)制信號量,隊(duì)列將包含單個(gè)消息,并且將在隊(duì)列中放置一條消息(任何值)。要訪問資源,任務(wù)將在隊(duì)列中掛起。如果隊(duì)列中有消息,則任務(wù)將獲得對資源的訪問權(quán)。一旦完成資源,隊(duì)列將被發(fā)布,從而根據(jù)需要放棄資源以供其他任務(wù)使用。相同的機(jī)制適用于實(shí)現(xiàn)具有N個(gè) 資源的計(jì)數(shù)信號量,并且隊(duì)列將預(yù)先填充N個(gè) 虛擬消息。
11.消息實(shí)際上可用于模擬事件標(biāo)志,其中 32 位指針大小變量(轉(zhuǎn)換為整數(shù))的每一位都可以表示一個(gè)事件。
12.可以使用消息隊(duì)列來實(shí)現(xiàn)棧結(jié)構(gòu)。這基本上是 LIFO 機(jī)制的另一種用法。
圖 4.消息隊(duì)列的許多用途中的一些。
概括
消息隊(duì)列可以以多種不同的方式使用。事實(shí)上,您可以編寫可能只使用消息隊(duì)列的相當(dāng)復(fù)雜的應(yīng)用程序。僅使用消息隊(duì)列可以減少代碼的大?。凑加每臻g),因?yàn)榭梢阅M許多其他服務(wù)(信號量、時(shí)間延遲和事件標(biāo)志)。
審核編輯:郭婷
-
cpu
+關(guān)注
關(guān)注
68文章
10911瀏覽量
213146 -
MPU
+關(guān)注
關(guān)注
0文章
375瀏覽量
48983 -
RTOS
+關(guān)注
關(guān)注
22文章
820瀏覽量
119918
發(fā)布評論請先 登錄
相關(guān)推薦
評論