STM32—cubeMX+DMA+USART 接收任意長度的數據


前言

原文:https://blog.csdn.net/u014470361/article/details/79206352

之前的一篇文章中我為了可以實現USART接收任意長度的數據,對HAL的庫進行了修改,可以實現接收以0x0a結尾的任意長度數據,即認為接收到0x0a時接收結束,見鏈接:HAL USART接收任意長度
  然而,上述這種方法並不合適,原則上HAL庫一般不去修改,不便於其他人移植程序,降低了程序中庫的適用性,這是很不好的習慣,所以這種方法並不可取。
  后查資料得知STM32中還可以利用DMA的方式實現串口的任意長度數據的接收,故開始學習DMA+串口接收任意長度的數據這種方式。

cubeMX軟件配置過程

首先,第一步都是進行時鍾樹的配置,配置好系統的時鍾,不同的芯片配置不同的時鍾頻率,如圖。
這里寫圖片描述
接着,配置USART1,選擇異步asynchronous,軟件自動配置了PA9和PA10管腳。
這里寫圖片描述
然后,繼續添加USART1的發送和接收DMA,其余默認即可。
這里寫圖片描述
接着,勾選上USART1的中斷使能。
這里寫圖片描述
最后,生成MDK-ARM V5版本環境的程序。
這里寫圖片描述

UASRT串口程序

//添加變量,為什么用關鍵字volatile見鏈接:[鏈接](http://blog.csdn.net/u014470361/article/details/78830147)
volatile uint8_t rx_len=0;
volatile uint8_t recv_end_flag=0;
uint8_t rx_buffer[200];
static void MX_USART1_UART_Init(void)
{

  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
  //上面的usart配置代碼為cubemx自動生成的,在下方添加使能idle中斷和打開串口DMA接收語句
	__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);//使能idle中斷
	HAL_UART_Receive_DMA(&huart1,rx_buffer,BUFFER_SIZE);//打開DMA接收,數據存入rx_buffer數組中。	
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

接下來修改串口中斷函數。

void USART1_IRQHandler(void)
{
	uint32_t tmp_flag = 0;
	uint32_t temp;
	tmp_flag =__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE); //獲取IDLE標志位
	if((tmp_flag != RESET))//idle標志被置位
	{ 
		__HAL_UART_CLEAR_IDLEFLAG(&huart1);//清除標志位
		temp = huart1.Instance->SR;  //清除狀態寄存器SR,讀取SR寄存器可以實現清除SR寄存器的功能
		temp = huart1.Instance->DR; //讀取數據寄存器中的數據
		HAL_UART_DMAStop(&huart1); //
		temp  = hdma_usart1_rx.Instance->NDTR;// 獲取DMA中未傳輸的數據個數,NDTR寄存器分析見下面
		rx_len =  BUFFER_SIZE - temp; //總計數減去未傳輸的數據個數,得到已經接收的數據個數
		recv_end_flag = 1;	// 接受完成標志位置1	
	 }
  HAL_UART_IRQHandler(&huart1);

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

DMA通道結構體中定義了NDTR寄存器,那為什么是未傳輸的數據數呢,STM32的中文手冊給出了該寄存器的具體說明。

typedef struct
{
  __IO uint32_t CR;     /*!< DMA stream x configuration register      */
  __IO uint32_t NDTR;   /*!< DMA stream x **number of data register**     */
  __IO uint32_t PAR;    /*!< DMA stream x peripheral address register */
  __IO uint32_t M0AR;   /*!< DMA stream x memory 0 address register   */
  __IO uint32_t M1AR;   /*!< DMA stream x memory 1 address register   */
  __IO uint32_t FCR;    /*!< DMA stream x FIFO control register       */
} DMA_Stream_TypeDef;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

這里寫圖片描述
接着,編寫主函數中串口中斷的處理函數。

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_USART1_UART_Init();
  while (1)
  {
		if(recv_end_flag ==1)
		{
			printf("rx_len=%d\r\n",rx_len);//打印接收長度
			HAL_UART_Transmit(&huart1,rx_buffer, rx_len,200);接收數據打印出來
			for(uint8_t i=0;i<rx_len;i++)
				{
					rx_buffer[i]=0;//清接收緩存
				}
			rx_len=0;//清除計數
			recv_end_flag=0;//清除接收結束標志位
		}
		HAL_UART_Receive_DMA(&huart1,rx_buffer,BUFFER_SIZE);//重新打開DMA接收		
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

程序的運行效果如下圖所示 ,輸入任意長度數據,串口打印出接收的數據長度並打印出接收的數據。本程序設置的接收長度最大BUFFER_SIZE是200,若想接收更長的數據,也可以把BUFFER_SIZE和數組長度改大。
這里寫圖片描述
###DMA參數和函數解析
DMA的基本原理、參數和函數解析在下一篇文章進行分析(鏈接)

本文章的源代碼下載地址:https://download.csdn.net/download/u014470361/10234803

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM