STM32單片機基礎08——使用USART發送和接收數據(DMA模式)

本篇文章主要介紹如何使用STM32CubeMX初始化STM32L431RCT6的USART,並使用DMA模式發送數據和接收數據。

1. 準備工作

硬件準備

mark

軟件準備

  • 需要安裝好Keil - MDK及芯片對應的包,以便編譯和下載生成的代碼;

Keil MDK和串口助手的安裝包都可以關注“小熊派開源社區”微信公衆號,在資料教程一欄中可獲取安裝包。

2.生成MDK工程

選擇芯片型號

打開STM32CubeMX,打開MCU選擇器:

mark

搜索並選中芯片STM32L431RCT6:

mark

配置時鐘源

  • 如果選擇使用外部高速時鐘(HSE),則需要在System Core中配置RCC;
  • 如果使用默認內部時鐘(HSI),這一步可以略過;

這裏我都使用外部時鐘:

mark

配置串口

小熊派開發闆闆載ST-Link並且虛擬了一個串口,原理圖如下:

mark

這裏我將開關撥到AT-MCU模式,使PC的串口與USART1之間連接。

接下來開始配置USART1

mark

USART DMA配置

知識小卡片 —— DMA

DMA 全稱 Direct Memory Access(直接存儲器訪問), 是STM32的一個外設,它的特點在於:

不佔用CPU的情況下將數據從存儲器直接搬運到外設,或者從外設直接搬運到存儲器,當然也可以從存儲器直接搬運到存儲器。

比如在需要串口發送大量數據的時候,CPU只需要發起DMA傳輸請求,然後就可以去做別的事情了,DMA會將數據傳輸到串口發送,DMA傳輸完之後會觸發中斷,CPU如果有需要,可以對該中斷進行處理,這樣一來CPU的效率是不是大大提高了?

在STM32L431RCT6中有 2 個 DMA 外設:DMA1 和 DMA2,每個DMA外設有 7 個通道,每個通道都是獨立的,配置DMA的時候有幾個關鍵點:

  • 數據從哪裏來?
  • 數據到哪裏去?
  • 有多少數據?

知識小卡片結束啦~對STM32的DMA外設有沒有了解呢?

接下來我們配置DMA,將存儲器(SRAM)中的數據直接搬運到串口外設去發送:

mark

配置時鐘樹

STM32L4的最高主頻到80M,所以配置PLL,最後使HCLK = 80Mhz即可:

mark

生成工程設置

mark

代碼生成設置

最後設置生成獨立的初始化文件:

mark

生成代碼

點擊GENERATE CODE即可生成MDK-V5工程:

mark

3. 在MDK中編寫、編譯、下載用戶代碼

定義發送數據區域

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
uint8_t dat[] = "Hello, I am Mculover666.\n";
/* USER CODE END 0 */

在main函數中發起DMA傳輸

int main(void)
{
  HAL_Init();

  SystemClock_Config();

  MX_GPIO_Init();
  MX_USART1_UART_Init();

  /* USER CODE BEGIN 2 */
  HAL_UART_Transmit_DMA(&huart1, (uint8_t*)dat, sizeof(dat));
  /* USER CODE END 2 */

  while (1)
  {
  }
}

實驗現象

編譯下載運行後,實驗現象如下:

mark

4. 使用DMA接收串口數據

說明

  • 使用HAL庫的時候不能同時使用DMA發送和接收數據,會出錯。
  • 所有的步驟和發送時一樣,這裏我只給出需要修改的部分。

修改串口DMA配置

mark

添加串口接收緩衝區

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
uint8_t dat[] = "Hello, I am Mculover666.\n";
uint8_t recv_buf[13] = {0};		//串口接收緩衝區
/* USER CODE END 0 */

修改main函數

int main(void)
{
  HAL_Init();

  SystemClock_Config();

  MX_GPIO_Init();
  MX_DMA_Init();
  MX_USART1_UART_Init();

  /* USER CODE BEGIN 2 */
  HAL_UART_Transmit(&huart1, (uint8_t*)dat, sizeof(dat), 0xFFFF);
  HAL_UART_Receive_DMA(&huart1, recv_buf, 13);  //使能DMA接收
  /* USER CODE END 2 */

  while (1)
  {
  }
}

添加串口接收中斷回調函數

/* USER CODE BEGIN 4 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) 
{ 
	//將接收到的數據再發送
	HAL_UART_Transmit(&huart1,recv_buf,13, 0xFFFF);
}
/* USER CODE END 4 */

實驗現象

mark

至此,我們已經學會了如何配置USART使用DMA模式發送數據和接收數據,下一節將討論實現printf()函數的多種方法。

發佈了50 篇原創文章 · 獲贊 2 · 訪問量 5578
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章