這里,我重點講解如何結(jié)合RTOS進(jìn)行處理數(shù)據(jù)。我們巧妙的利用了RTSO自帶的消息隊列,我們可以把每一個接收的數(shù)據(jù)看做一個消息元素。
先回顧一下知識點:
FreeRTOS消息隊列
基于 FreeRTOS 的應(yīng)用程序由一組獨立的任務(wù)構(gòu)成——每個任務(wù)都是具有獨立權(quán)限的程序。這些獨立的任務(wù)之間的通訊與同步一般都是基于操作系統(tǒng)提供的IPC通訊機(jī)制,而FreeRTOS 中所有的通信與同步機(jī)制都是基于隊列實現(xiàn)的。
消息隊列是一種常用于任務(wù)間通信的數(shù)據(jù)結(jié)構(gòu),隊列可以在任務(wù)與任務(wù)間、中斷和任務(wù)間傳送信息,實現(xiàn)了任務(wù)接收來自其他任務(wù)或中斷的不固定長度的消息。任務(wù)能夠從隊列里面讀取消息,當(dāng)隊列中的消息是空時,掛起讀取任務(wù),用戶還可以指定掛起的任務(wù)時間;當(dāng)隊列中有新消息時,掛起的讀取任務(wù)被喚醒并處理新消息,消息隊列是一種異步的通信方式。
隊列特性1.數(shù)據(jù)存儲
隊列可以保存有限個具有確定長度的數(shù)據(jù)單元。隊列可以保存的最大單元數(shù)目被稱為隊列的“深度”。在隊列創(chuàng)建時需要設(shè)定其深度和每個單元的大小。
通常情況下,隊列被作為 FIFO(先進(jìn)先出)緩沖區(qū)使用,即數(shù)據(jù)由隊列尾寫入,從隊列首讀出。當(dāng)然,由隊列首寫入也是可能的。
往隊列寫入數(shù)據(jù)是通過字節(jié)拷貝把數(shù)據(jù)復(fù)制存儲到隊列中;從隊列讀出數(shù)據(jù)使得把隊列中的數(shù)據(jù)拷貝刪除。
2.讀阻塞
當(dāng)某個任務(wù)試圖讀一個隊列時,其可以指定一個阻塞超時時間。在這段時間中,如果隊列為空,該任務(wù)將保持阻塞狀態(tài)以等待隊列數(shù)據(jù)有效。當(dāng)其它任務(wù)或中斷服務(wù)例程往其等待的隊列中寫入了數(shù)據(jù),該任務(wù)將自動由阻塞態(tài)轉(zhuǎn)移為就緒態(tài)。當(dāng)?shù)却臅r間超過了指定的阻塞時間,即使隊列中尚無有效數(shù)據(jù),任務(wù)也會自動從阻塞態(tài)轉(zhuǎn)移為就緒態(tài)。
由于隊列可以被多個任務(wù)讀取,所以對單個隊列而言,也可能有多個任務(wù)處于阻塞狀態(tài)以等待隊列數(shù)據(jù)有效。這種情況下,一旦隊列數(shù)據(jù)有效,只會有一個任務(wù)會被解除阻塞,這個任務(wù)就是所有等待任務(wù)中優(yōu)先級最高的任務(wù)。而如果所有等待任務(wù)的優(yōu)先級相同,那么被解除阻塞的任務(wù)將是等待最久的任務(wù)。
說些題外話,ucos中是具有廣播消息的,當(dāng)有多個任務(wù)阻塞在隊列上,當(dāng)發(fā)送消息的時候可以選擇廣播消息,那么這些阻塞的任務(wù)都能被解除阻塞。
3.寫阻塞
與讀阻塞想反,任務(wù)也可以在寫隊列時指定一個阻塞超時時間。這個時間是當(dāng)被寫隊列已滿時,任務(wù)進(jìn)入阻塞態(tài)以等待隊列空間有效的最長時間。
由于隊列可以被多個任務(wù)寫入,所以對單個隊列而言,也可能有多個任務(wù)處于阻塞狀態(tài)以等待隊列空間有效。這種情況下,一旦隊列空間有效,只會有一個任務(wù)會被解除阻塞,這個任務(wù)就是所有等待任務(wù)中優(yōu)先級最高的任務(wù)。而如果所有等待任務(wù)的優(yōu)先級相同,那么被解除阻塞的任務(wù)將是等待最久的任務(wù)。
消息隊列的工作流程1.發(fā)送消息
任務(wù)或者中斷服務(wù)程序都可以給消息隊列發(fā)送消息,當(dāng)發(fā)送消息時,如果隊列未滿或者允許覆蓋入隊, FreeRTOS 會將消息拷貝到消息隊列隊尾,否則,會根據(jù)用戶指定的阻塞超時時間進(jìn)行阻塞,在這段時間中,如果隊列一直不允許入隊,該任務(wù)將保持阻塞狀態(tài)以等待隊列允許入隊。當(dāng)其它任務(wù)從其等待的隊列中讀取入了數(shù)據(jù)(隊列未滿),該任務(wù)將自動由阻塞態(tài)轉(zhuǎn)為就緒態(tài)。當(dāng)任務(wù)等待的時間超過了指定的阻塞時間,即使隊列中還不允許入隊,任務(wù)也會自動從阻塞態(tài)轉(zhuǎn)移為就緒態(tài),此時發(fā)送消息的任務(wù)或者中斷程序會收到一個錯誤碼 errQUEUE_FULL。
發(fā)送緊急消息的過程與發(fā)送消息幾乎一樣,唯一的不同是,當(dāng)發(fā)送緊急消息時,發(fā)送的位置是消息隊列隊頭而非隊尾,這樣,接收者就能夠優(yōu)先接收到緊急消息,從而及時進(jìn)行消息處理。
下面是消息隊列的發(fā)送API接口,函數(shù)中有FromISR則表明在中斷中使用的。
消息隊列讀取
任務(wù)調(diào)用接收函數(shù)收取隊列消息, 函數(shù)首先判斷當(dāng)前隊列是否有未讀消息, 如果沒有, 則會判斷參數(shù) xTicksToWait, 決定直接返回函數(shù)還是阻塞等待。
如果隊列中有消息未讀, 首先會把待讀的消息復(fù)制到傳進(jìn)來的指針?biāo)竷?nèi), 然后判斷函數(shù)參數(shù) xJustPeeking == pdFALSE的時候, 符合的話, 說明這個函數(shù)讀取了數(shù)據(jù), 需要把被讀取的數(shù)據(jù)做出隊處理, 如果不是, 則只是查看一下(peek),只是返回數(shù)據(jù),但是不會把數(shù)據(jù)清除。
對于正常讀取數(shù)據(jù)的操作, 清除數(shù)據(jù)后隊列會空出空位, 所以查看隊列中的等待列表中是否有任務(wù)等發(fā)送數(shù)據(jù)而被掛起, 有的話恢復(fù)一個任務(wù)就緒, 并根據(jù)優(yōu)先級判斷是否需要出進(jìn)行任務(wù)切換。
對于只是查看數(shù)據(jù)的, 由于沒有清除數(shù)據(jù), 所以沒有空間新空出,不需要檢查發(fā)送等待鏈表, 但是會檢查接收等待鏈表, 如果有任務(wù)掛起會切換其到就緒并判斷是否需要切換。
接下來,我們可以從中斷再到任務(wù)這樣一個流程去編寫代碼:
如下的框圖來說明一下 FreeRTOS 消息隊列的實現(xiàn),讓大家有一個形象的認(rèn)識。
1. 中斷如何處理:
///《LPUART0 中斷服務(wù)函數(shù)
void LpUart0_IRQHandler(void)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
uint8_t res=0;
// if(LPUart_GetStatus(M0P_LPUART0, LPUartPE)) /*奇偶檢驗錯誤*/
// {
// LPUart_ClrStatus(M0P_LPUART0, LPUartPE);
// }
if(LPUart_GetStatus(M0P_LPUART0, LPUartRC)) ///接收數(shù)據(jù)中斷
{
LPUart_ClrStatus(M0P_LPUART0, LPUartRC); ///《清接收中斷請求
res = LPUart_ReceiveData(M0P_LPUART0);
xQueueSendFromISR(usart_Queue,(void *) &res,&xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
}
任務(wù)中接收信號,這里并不是每一條消息都接收嗎,因為沒有空閑中斷,而是做了100ms絕對延時,確保一幀數(shù)據(jù)接收完成。
/**
** \brief 2400波特率:‘100ms = 24bytes’
**
**
** \param 1 :void
** \retval void
void APP_LocalCOM_ReadData(void)
{
uint8_t temp_bytes = 0; /*隊列中字節(jié)長度new*/
uint8_t cnt;
static uint8_t buff[QueueSIZE] = {0}; /*暫存接收協(xié)議,從0x68開始,用于crc計算*/
static TickType_t StartTick = 0;
static uint8_t ShadowBytes = 0; /*old*/
temp_bytes = uxQueueMessagesWaiting(usart_Queue);//檢查消息數(shù)
if(temp_bytes == 0)//檢查隊列的長度
{
ShadowBytes = 0;
}
else
{
if(ShadowBytes != temp_bytes)//有新的數(shù)據(jù)
{
ShadowBytes = temp_bytes;
StartTick = xTaskGetTickCount();
}
else
{
if(xTaskGetTickCount() - StartTick 》 100)
{
for(cnt = 0; cnt《temp_bytes; cnt++)
{
xQueueReceive(usart_Queue,(void*)&buff[cnt%QueueSIZE],(TickType_t)100);//接收數(shù)據(jù)
}
protocol_parse(buff,temp_bytes);
//BSP_UARTx_SendBytes(M0P_UART0,temp_bytes, buff); //test
}}}}
編輯:hfy
-
數(shù)據(jù)存儲
+關(guān)注
關(guān)注
5文章
1006瀏覽量
52114 -
數(shù)據(jù)處理
+關(guān)注
關(guān)注
0文章
635瀏覽量
29644 -
FreeRTOS
+關(guān)注
關(guān)注
14文章
495瀏覽量
65697
發(fā)布評論請先 登錄
數(shù)據(jù)處理問題!
FreeRTOS隊列創(chuàng)建任務(wù)間通信的基本應(yīng)用程序
FreeRTOS任務(wù)創(chuàng)建到閃存LED的基本應(yīng)用程序
FreeRTOS隊列創(chuàng)建任務(wù)間通信的基本應(yīng)用程序
用于創(chuàng)建閃存LED任務(wù)的FreeRTOS應(yīng)用程序
LabVIEW環(huán)境下基于數(shù)據(jù)文件讀寫的數(shù)據(jù)處理程序設(shè)計
基于Matlab的轉(zhuǎn)爐耳軸軸承狀態(tài)檢測數(shù)據(jù)處理程序的開發(fā)
密立根油滴實驗-數(shù)據(jù)處理C程序
網(wǎng)上錄取數(shù)據(jù)處理中重復(fù)記錄去除程序的設(shè)計_董國鋼
Thumb數(shù)據(jù)處理指令
基于AD574模數(shù)轉(zhuǎn)換的數(shù)據(jù)處理程序設(shè)計

在TM4C MCU上用FreeRTOS開發(fā)通用應(yīng)用程序應(yīng)用說明

評論