基于STM32與FreeRTOS的消息傳遞詳解
- 引言
- 介紹
- 消息隊列概念
- 在FreeRTOS中的消息隊列函數
- 執行個體
- 需求分析
- 發送消息
- 接收消息
- 現象
- 後續
引言
我們在裸機開發中,每個函數之間進行資料通信往往采用全局變量。而在嵌入式開發中。我們在進行程序間通信的時候,往往采用消息隊列。對于作業系統來說,消息隊列是非常重要的一個資料結構。本文将介紹一下,如何使用消息隊列進行通信。
介紹
消息隊列概念
隊列又稱消息隊列,是一種常用于任務間通信的資料結構,隊列可以在任務與任務間、中斷和任務間傳遞資訊,實作了任務接收來自其他任務或中斷的不固定長度的消息,任務能夠從隊列裡面讀取消息,當隊列中的消息是空時,讀取消息的任務将被阻塞,使用者還可以指定阻塞的任務時間 xTicksToWait,在這段時間中,如果隊列為空,該任務将保持阻塞狀态以等待隊列資料有效。當隊列中有新消息時,被阻塞的任務會被喚醒并處理新消息;當等待的時間超過了指定的阻塞時間,即使隊列中尚無有效資料,任務也會自動從阻塞态轉為就緒态。消息隊列是一種異步的通信方式。
在FreeRTOS中的消息隊列函數
- 設定消息隊列的格式:osMessageQDef(myQueue, len, size);
- myQueue是消息隊列的名稱。
- len是消息隊列的長度(有幾個消息)
- size是每個消息的大小,也就是每個元素的格式
-
建立消息:osMessageCreate(osMessageQ(myQueue01), NULL);
建立消息的函數,實際上是調用了FreeRTOS的osMessageCreate()函數,隻不過HAL庫進行了封裝。
-
向消息隊列發送消息
我們這裡來介紹在中斷中發送消息。使用函數xQueueSendFromISR(QueueHandle,&Res,time);
其中:
- QueueHandle:消息隊列的句柄
- &Res:要發送的資料的位址
- time:阻塞時間,就是如果消息隊列滿的時候,任務應該阻塞多久
-
接收消息隊列中的消息
xQueueReceive(QueueHandle,&queue_buffer,time);
- QueueHandle:消息隊列的句柄
- &queue_buffer:接收的消息要存放在的位址
- time:阻塞時間,就是如果消息隊列空的時候,任務應該阻塞多久
-
查詢消息隊列中消息的數量
uxQueueMessagesWaiting(myQueue01Handle),可以傳回消息隊列(句柄為myQueue01Handle)中消息的數量,傳回值為整數。
執行個體
需求分析
此樣例我們使用PC充當上位機,上位機發送資料後,在序列槽中斷函數中将接收到的PC資料發送在消息隊列myQueue01Handle中,之後在一個接收線程中接收這個消息的内容,并通過序列槽将接受到的消息的大小和内容輸出出來。
發送消息
當上位機PC下發資料後,序列槽中斷函數将接收到的資料發送在消息隊列中。
void USART3_IRQHandler(void)
{
uint8_t Res;
if(__HAL_UART_GET_FLAG(&huart3,UART_FLAG_RXNE)!=RESET)//檢測到有單個位元組的中斷
{
HAL_UART_Receive(&huart3,&Res,1,0Xffff);
xQueueSendFromISR(myQueue01Handle,&Res,0)//發送消息
}
else if(__HAL_UART_GET_FLAG(&huart3,UART_FLAG_IDLE)!=RESET)//空閑中斷(代表這一幀資料傳輸完了)
{
printf(" Receive a frame data.");
__HAL_UART_CLEAR_IDLEFLAG(&huart3)
}
接收消息
我們建立一個任務,此任務的重要功能就是接收消息隊列中的消息。我們将接受到的消息的大小和内容通過序列槽發送出來。沒有消息的時候,一直實作LED的閃爍。
void LEDToggleTesk(void const * argument)
{
/* USER CODE BEGIN LEDToggleTesk */
BaseType_t xReturn=pdTRUE;//定義一個建立消息傳回值,預設為pdTRUE
UBaseType_t num_queue ;
uint8_t Res[20];//存放我們接收到的一包資料
uint8_t queue_buffer;
int i=0;//接收數組下标
for(;;)
{
i=0;
HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_5);
num_queue=uxQueueMessagesWaiting(myQueue01Handle);//擷取消息隊列中有多少資料
while(num_queue--)
{
xReturn=xQueueReceive(myQueue01Handle,&queue_buffer,0);//将消息隊列中的資料放在queue_buffer中
if(xReturn)
Res[i++]=queue_buffer;
}
if(i!=0)
printf(" count %d,LEDTask Receive %s",i,Res);//輸出接收消息的大小和内容
osDelay(500);
}
}
現象
PC端發送123456789,MCU回複。
Receive a frame data
count 8,LEDTask Receive 12345678