天天看點

基于STM32與FreeRTOS的消息傳遞詳解(HAL庫)

基于STM32與FreeRTOS的消息傳遞詳解

  • ​​引言​​
  • ​​介紹​​
  • ​​消息隊列概念​​
  • ​​在FreeRTOS中的消息隊列函數​​
  • ​​執行個體​​
  • ​​需求分析​​
  • ​​發送消息​​
  • ​​接收消息​​
  • ​​現象​​
  • ​​後續​​

引言

我們在裸機開發中,每個函數之間進行資料通信往往采用全局變量。而在嵌入式開發中。我們在進行程序間通信的時候,往往采用消息隊列。對于作業系統來說,消息隊列是非常重要的一個資料結構。本文将介紹一下,如何使用消息隊列進行通信。

介紹

消息隊列概念

隊列又稱消息隊列,是一種常用于任務間通信的資料結構,隊列可以在任務與任務間、中斷和任務間傳遞資訊,實作了任務接收來自其他任務或中斷的不固定長度的消息,任務能夠從隊列裡面讀取消息,當隊列中的消息是空時,讀取消息的任務将被阻塞,使用者還可以指定阻塞的任務時間 xTicksToWait,在這段時間中,如果隊列為空,該任務将保持阻塞狀态以等待隊列資料有效。當隊列中有新消息時,被阻塞的任務會被喚醒并處理新消息;當等待的時間超過了指定的阻塞時間,即使隊列中尚無有效資料,任務也會自動從阻塞态轉為就緒态。消息隊列是一種異步的通信方式。

在FreeRTOS中的消息隊列函數

  1. 設定消息隊列的格式:osMessageQDef(myQueue, len, size);
  • myQueue是消息隊列的名稱。
  • len是消息隊列的長度(有幾個消息)
  • size是每個消息的大小,也就是每個元素的格式
  1. 建立消息:osMessageCreate(osMessageQ(myQueue01), NULL);

    建立消息的函數,實際上是調用了FreeRTOS的osMessageCreate()函數,隻不過HAL庫進行了封裝。

  2. 向消息隊列發送消息

    我們這裡來介紹在中斷中發送消息。使用函數xQueueSendFromISR(QueueHandle,&Res,time);

    其中:

  • QueueHandle:消息隊列的句柄
  • &Res:要發送的資料的位址
  • time:阻塞時間,就是如果消息隊列滿的時候,任務應該阻塞多久
  1. 接收消息隊列中的消息

    xQueueReceive(QueueHandle,&queue_buffer,time);

  • QueueHandle:消息隊列的句柄
  • &queue_buffer:接收的消息要存放在的位址
  • time:阻塞時間,就是如果消息隊列空的時候,任務應該阻塞多久
  1. 查詢消息隊列中消息的數量

    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

後續