這個是全網(wǎng)最詳細的STM32項目教學(xué)視頻。
第一篇CSDN文章在這里在這里:
75
V3:HAL庫開發(fā)、手把手教學(xué)下面功能:PID速度控制、PID循跡、PID跟隨、遙控、避障、PID角度控制、openmv視覺控制、電磁循跡、FreeRTOS、K210視覺智能車(更新中)、K230視覺智能車(更新中)、MSPM0G3507視覺智能車(更新中)
23.1.1-消息隊列的概念和函數(shù)
消息隊列概念
消息隊列簡稱隊列,是一種常用于任務(wù)間通信的數(shù)據(jù)結(jié)構(gòu)。
如下圖:消息隊列可以在任務(wù)與任務(wù)間、中斷與任務(wù)間傳遞消息,實現(xiàn)任務(wù)接收來自其它任務(wù)或中斷的不固定長度的消息。
相比于裸機的全局數(shù)組,使用消息隊列有如下優(yōu)勢:
- 消息隊列具有超時機制,可以讓 FreeRTOS 內(nèi)核有效地管理任務(wù)。
- 使用消息隊列可以防止多任務(wù)的訪問沖突、防止數(shù)據(jù)競爭 出現(xiàn)錯誤.
- 使用消息隊列可以有效地解決中斷服務(wù)程序與任務(wù)之間消息傳遞的問題,使用全局數(shù)組的話,任務(wù)得不斷去監(jiān)測標(biāo)志位以獲取數(shù)據(jù)
- 消息隊列具有FIFO與LIFO儲存機制,方便處理數(shù)據(jù)。
消息隊列的通信機制
消息隊列是一種異步的通信方式。
任務(wù)能夠從隊列中讀取消息,當(dāng)隊列中的消息為空時,讀取消息的任務(wù)將被阻塞。用戶可以指定阻塞的任務(wù)時間 xTicksToWait,在這段時間中,如果隊列為空,該任務(wù)將保持阻塞狀態(tài)以等待隊列數(shù)據(jù)有效。當(dāng)隊列中有新消息時,被阻塞的任務(wù)會被喚醒并處理新消息;當(dāng)?shù)却臅r間超過指定的阻塞時間,即使隊列中沒有有效數(shù)據(jù),任務(wù)也會自動從阻塞態(tài)轉(zhuǎn)為就緒態(tài)。
通過消息隊列服務(wù),任務(wù)或中斷服務(wù)可以將一條或多條消息放入消息隊列中。同樣,一個或多個任務(wù)可以從消息隊列中獲得消息。當(dāng)有多個消息發(fā)送到消息隊列時,通常是將先進入消息隊列的消息先傳給任務(wù),也就是說,任務(wù)先得到的是最先進入消息隊列的消息,即先進先出原則(FIFO),F(xiàn)reeRTOS的隊列也支持后進先出原則(LIFO)。
FreeRTOS中消息隊列特性
- 消息支持先進先出方式排隊,支持異步讀寫工作方式
- 讀寫隊列均支持超時機制
- 消息支持后進先出方式排隊,向隊首發(fā)送消息(LIFO)
- 可以允許不同長度(不超過隊列節(jié)點最大值)的任意類型消息
- 一個任務(wù)能夠從任意一個消息隊列接收和發(fā)送消息
- 多個任務(wù)能夠從同一個消息隊列接收和發(fā)送消息
- 當(dāng)隊列使用結(jié)束后,可以通過刪除隊列函數(shù)進行刪除
消息隊列應(yīng)用場景
消息隊列可用于發(fā)送不定長消息的場合。
隊列是FreeRTOS 主要的任務(wù)間通信方式,可以在任務(wù)與任務(wù)間、中斷和任務(wù)間傳送信息,發(fā)送到隊列的消息是通過復(fù)制方式實現(xiàn)的,這意味著隊列存儲的數(shù)據(jù)是原始數(shù)據(jù),而不是原始數(shù)據(jù)的引用。
消息隊列的常用API函數(shù)
創(chuàng)建消息隊列
xQueueCreate():
QueueHandle_t xQueueCreate(
UBaseType_t uxQueueLength, //隊列的最大長度,表示隊列可以容納的元素個數(shù)。
UBaseType_t uxItemSize //隊列中每個元素的大小(以字節(jié)為單位)。即每個元素占用的內(nèi)存空間??梢允侨魏螖?shù)據(jù)類型的大小,例如 sizeof(int)、sizeof(char) 等。
);
QueueHandle_t 返回值:
成功:返回隊列句柄(QueueHandle_t),這個句柄將用于后續(xù)的隊列操作(如發(fā)送和接收數(shù)據(jù))。
失?。喝绻麆?chuàng)建隊列失敗,返回 NULL。
任務(wù)中向隊列發(fā)送數(shù)據(jù)-不會覆蓋原有數(shù)據(jù)
xQueueSend() :
A
BaseType_t xQueueSend(
QueueHandle_t xQueue, //隊列句柄,表示你要操作的隊列。
const void * pvItemToQueue, //指向要發(fā)送到隊列的數(shù)據(jù)的指針。數(shù)據(jù)會被復(fù)制到隊列中。
TickType_t xTicksToWait //等待隊列空間的時間。如果隊列滿了,xQueueSend 會等待空閑空間。此值可以是 0 表示非阻塞操作,portMAX_DELAY 表示無限等待,或者其他自定義的等待時間。
);
BaseType_t 返回值:
pdPASS:成功將數(shù)據(jù)發(fā)送到隊列。
errQUEUE_FULL:隊列已滿,無法立即放入數(shù)據(jù)。如果 xTicksToWait 設(shè)置為 0,則是非阻塞的,隊列滿時返回 errQUEUE_FULL。
errQUEUE_BLOCKED:如果隊列滿且設(shè)置了阻塞時間,任務(wù)會被阻塞直到有空間。
任務(wù)中向隊列發(fā)送數(shù)據(jù)-會強制覆蓋原有數(shù)據(jù)
BaseType_t xQueueOverwrite( QueueHandle_t xQueue, //隊列句柄
const void *pvItemToQueue //要發(fā)送到隊列的數(shù)據(jù)指針
);
函數(shù)作用:函數(shù)會強制將新數(shù)據(jù)寫入隊列,并覆蓋隊列中原有的元素。
返回值:
如果操作成功,返回 pdPASS。
如果隊列為空或出現(xiàn)其他錯誤,返回 errQUEUE_FULL。
任務(wù)中接收隊列數(shù)據(jù)-會從隊列中移除該數(shù)據(jù)
xQueueReceive():
BaseType_t xQueueReceive(
QueueHandle_t xQueue, //要接收數(shù)據(jù)的隊列句柄。這個句柄是在創(chuàng)建隊列時由 xQueueCreate() 返回的。它標(biāo)識了隊列。
void * const pvBuffer, //指向接收數(shù)據(jù)存儲位置的指針。數(shù)據(jù)將被放置到這個緩沖區(qū)中,緩沖區(qū)的大小應(yīng)當(dāng)足夠存儲隊列中每個消息的內(nèi)容。
TickType_t xTicksToWait//指定任務(wù)在隊列中沒有數(shù)據(jù)時應(yīng)該等待的時間,單位是 FreeRTOS 系統(tǒng)中的“滴答”(tick)。如果設(shè)置為 0,則表示不等待,隊列為空時 xQueueReceive() 將立即返回。如果設(shè)置為 portMAX_DELAY,表示無限期等待,直到隊列中有數(shù)據(jù)。
);
返回值:
pdPASS:
如果成功從隊列接收數(shù)據(jù),返回 pdPASS(即 1)。
errQUEUE_EMPTY:
如果隊列為空且任務(wù)設(shè)置的等待時間為 0,或者任務(wù)等待超時,返回 errQUEUE_EMPTY(即 0)。
任務(wù)中接收隊列數(shù)據(jù)-但不會將數(shù)據(jù)移除
BaseType_t xQueuePeek( QueueHandle_t xQueue,//這是隊列的句柄,指向你想要查看的隊列。隊列句柄是通過 xQueueCreate() 創(chuàng)建隊列時獲得的。
void * pvBuffer, //這是一個指向接收數(shù)據(jù)的緩沖區(qū)的指針,隊列中的數(shù)據(jù)會被復(fù)制到這個緩沖區(qū)。注意,數(shù)據(jù)將從隊列復(fù)制到該緩沖區(qū)中,但不會刪除隊列中的數(shù)據(jù)。
TickType_t xTicksToWait //如果隊列為空,xQueuePeek() 會阻塞直到隊列中有數(shù)據(jù)可用。如果 xTicksToWait 為 0,表示函數(shù)不會阻塞(即,如果隊列為空,函數(shù)會立即返回)。如果為 portMAX_DELAY,則函數(shù)會一直等待,直到隊列有數(shù)據(jù)可用。
);
返回值
pdPASS:如果成功地從隊列中“查看”到數(shù)據(jù),則返回 pdPASS。
errQUEUE_EMPTY:如果隊列為空且 xTicksToWait 為 0,表示沒有數(shù)據(jù)可查看,函數(shù)將返回 errQUEUE_EMPTY。
其他返回值:在發(fā)生錯誤時,可能會返回其他錯誤碼。
如果隊列為空, xQueuePeek() 會阻塞直到隊列中有數(shù)據(jù)可用。如果 xTicksToWait 為 0,表示函數(shù)不會阻塞(即,如果隊列為空,函數(shù)會立即返回)。如果為 portMAX_DELAY,則函數(shù)會一直等待,直到隊列有數(shù)據(jù)可用。
中斷中向隊列發(fā)送數(shù)據(jù)-不會覆蓋原有數(shù)據(jù)
xQueueSendFromISR():
BaseType_t xQueueSendFromISR(
QueueHandle_t xQueue, // 要發(fā)送數(shù)據(jù)的隊列句柄
const void * pvItemToQueue, // 指向要發(fā)送的數(shù)據(jù)的指針
BaseType_t * pxHigherPriorityTaskWoken // 用于指示是否喚醒了更高優(yōu)先級的任務(wù)
);
**返回值**
- **`pdPASS`**: 表示隊列成功接收數(shù)據(jù)并且返回成功。
- **`errQUEUE_FULL`**: 表示隊列已滿,無法發(fā)送數(shù)據(jù)到隊列中。
在 FreeRTOS 中,默認情況下, xQueueSendFromISR() 會根據(jù)隊列是否已滿來判斷是否將數(shù)據(jù)寫入隊列。如果隊列已經(jīng)滿了,并且沒有使用 隊列覆蓋機制,它會返回 errQUEUE_FULL,并且數(shù)據(jù)不會被寫入隊列。如果希望強制寫入隊列使用 xQueueOverwriteFromISR()
中斷中向隊列發(fā)送數(shù)據(jù)-會且強制覆蓋原有數(shù)據(jù)
BaseType_t xQueueOverwriteFromISR(
QueueHandle_t xQueue, //要操作的隊列句柄(通過 xQueueCreate() 創(chuàng)建)。
const void *pvItemToQueue, //指向要發(fā)送到隊列的數(shù)據(jù)的指針。數(shù)據(jù)的大小由創(chuàng)建隊列時指定的大?。╱xItemSize)決定。
BaseType_t *pxHigherPriorityTaskWoken // 用于指示是否需要任務(wù)切換的標(biāo)志
);
BaseType_t 返回值
pdPASS:表示數(shù)據(jù)已成功寫入隊列(覆蓋舊數(shù)據(jù))。
此函數(shù)沒有返回 errQUEUE_FULL,因為它總是會覆蓋數(shù)據(jù),即使隊列已滿。
FreeRTOS 中的一個特殊隊列操作函數(shù),專門用于在 中斷服務(wù)例程(ISR)中 向隊列寫入數(shù)據(jù),并 強制覆蓋隊列中的現(xiàn)有數(shù)據(jù)。也就是在隊列已經(jīng)滿的時候依舊可以寫入最新數(shù)據(jù)。
中斷中從隊列接收數(shù)據(jù)-會從隊列中移除該數(shù)據(jù)
**xQueueReceiveFromISR(): **
BaseType_t xQueueReceiveFromISR(
QueueHandle_t xQueue, // 要從中接收數(shù)據(jù)的隊列句柄
void * const pvBuffer, // 用于存儲接收到的數(shù)據(jù)的緩沖區(qū)
BaseType_t * const pxHigherPriorityTaskWoken // 用于指示是否需要任務(wù)切換的標(biāo)志
);
返回值:
- **`pdPASS`**:表示從隊列成功接收到數(shù)據(jù)。
- **`errQUEUE_EMPTY`**:表示隊列為空,沒有數(shù)據(jù)可以接收。
xQueueReceiveFromISR() 在 接收數(shù)據(jù)時會 接收完數(shù)據(jù)后,會將該數(shù)據(jù)移除
中斷中從隊列接收數(shù)據(jù)-但不移除該數(shù)據(jù)
BaseType_t xQueuePeekFromISR(
QueueHandle_t xQueue, //隊列的句柄,指定你要從中讀取數(shù)據(jù)的隊列
void *pvBuffer, //指向存儲接收數(shù)據(jù)的緩沖區(qū)的指針。接收到的數(shù)據(jù)會存放在這里,但不會從隊列中移除。
BaseType_t *pxHigherPriorityTaskWoken //指向 BaseType_t 類型的變量,標(biāo)記是否有高優(yōu)先級任務(wù)被喚醒。如果在調(diào)用過程中有高優(yōu)先級任務(wù)就緒,F(xiàn)reeRTOS 會根據(jù)這個標(biāo)志決定是否進行任務(wù)切換。
);
xQueuePeekFromISR() 從隊列中讀取數(shù)據(jù),但 不移除數(shù)據(jù)。這意味著即使讀取了隊列中的數(shù)據(jù),隊列中原來的數(shù)據(jù)仍然保留,其他任務(wù)或中斷可以繼續(xù)讀取隊列中的數(shù)據(jù)。
返回值:
pdPASS:表示成功接收到數(shù)據(jù)。
errQUEUE_EMPTY:表示隊列為空,沒有接收到任何數(shù)據(jù)。