【STM32】HAL庫 STM32CubeMX教程四---UART串口通信詳解

前言: 

今天我們學習STM32CubeMX串口的操作,以及HAL庫串口的配置,我們會詳細的講解各個模塊的使用和具體功能,並且基於HAL庫實現Printf函數功能重定向,UART中斷接收,本系列教程將HAL庫與STM32CubeMX結合在一起講解,使您可以更快速的學會各個模塊的使用

 

所用工具

1、芯片: STM32F407ZET6

2、STM32CubeMx軟件

3、IDE: MDK-Keil軟件

4、STM32F1xx/STM32F4xxHAL庫 

5、串口: 使用USART1 PA9,PA10

知識概括:

通過本篇博客您將學到:

STM32CubeMX創建串口例程

HAL庫UATR函數庫

重定義printf函數

HAL庫,UART中斷接收

HAL庫UATR接收與發送例程

工程創建

 

1設置RCC

  • 設置高速外部時鐘HSE 選擇外部時鐘源

2設置串口

  • 1點擊USATR1   
  • 2設置MODE爲異步通信(Asynchronous)       
  • 3基礎參數:波特率爲115200 Bits/s。傳輸數據長度爲8 Bit。奇偶檢驗無,停止位1      接收和發送都使能 
  • 4GPIO引腳設置 USART1_RX/USART_TX
  • 5 NVIC Settings 一欄使能接收中斷

3設置時鐘

我的是  外部晶振爲8MHz 

  • 1選擇外部時鐘HSE 8MHz   
  • 2PLL鎖相環倍頻72倍
  • 3系統時鐘來源選擇爲PLL
  • 4設置APB1分頻器爲 /2

32的時鐘樹框圖  如果不懂的話請看《【STM32】系統時鐘RCC詳解(超詳細,超全面)》

 

4項目文件設置

  • 1 設置項目名稱
  • 2 設置存儲路徑
  • 3 選擇所用IDE

5創建工程文件

然後點擊GENERATE CODE  創建工程

配置下載工具

新建的工程所有配置都是默認的  我們需要自行選擇下載模式,勾選上下載後復位運行

HAL庫UART函數庫介紹

 

  UART結構體定義

UART_HandleTypeDef huart1;

UART的名稱定義,這個結構體中存放了UART所有用到的功能,後面的別名就是我們所用的uart串口的別名,默認爲huart1

可以自行修改

1、串口發送/接收函數

  • HAL_UART_Transmit();串口發送數據,使用超時管理機制 
  • HAL_UART_Receive();串口接收數據,使用超時管理機制
  • HAL_UART_Transmit_IT();串口中斷模式發送  
  • HAL_UART_Receive_IT();串口中斷模式接收
  • HAL_UART_Transmit_DMA();串口DMA模式發送
  • HAL_UART_Transmit_DMA();串口DMA模式接收

這幾個函數的參數基本都是一樣的,我們挑兩個講解一下

串口發送數據:

HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)

功能:串口發送指定長度的數據。如果超時沒發送完成,則不再發送,返回超時標誌(HAL_TIMEOUT)。

參數:

  • UART_HandleTypeDef *huart      UATR的別名    如 :   UART_HandleTypeDef huart1;   別名就是huart1  
  • *pData      需要發送的數據 
  • Size    發送的字節數
  • Timeout   最大發送時間,發送數據超過該時間退出發送   
舉例:   HAL_UART_Transmit(&huart1, (uint8_t *)ZZX, 3, 0xffff);   //串口發送三個字節數據,最大傳輸時間0xffff

中斷接收數據:

HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)

功能:串口中斷接收,以中斷方式接收指定長度數據。
大致過程是,設置數據存放位置,接收數據長度,然後使能串口接收中斷。接收到數據時,會觸發串口中斷。
再然後,串口中斷函數處理,直到接收到指定長度數據,而後關閉中斷,進入中斷接收回調函數,不再觸發接收中斷。(只觸發一次中斷)

參數:

  • UART_HandleTypeDef *huart      UATR的別名    如 :   UART_HandleTypeDef huart1;   別名就是huart1  
  • *pData      接收到的數據存放地址
  • Size    接收的字節數
舉例:    HAL_UART_Receive_IT(&huart1,(uint8_t *)&value,1);   //中斷接收一個字符,存儲到value中

2、串口中斷函數

 

  • HAL_UART_IRQHandler(UART_HandleTypeDef *huart);  //串口中斷處理函數
  • HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart);  //串口發送中斷回調函數
  • HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart);  //串口發送一半中斷回調函數(用的較少)
  • HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);  //串口接收中斷回調函數
  • HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart);//串口接收一半回調函數(用的較少)
  • HAL_UART_ErrorCallback();串口接收錯誤函數

串口接收中斷回調函數:

HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);  

功能:HAL庫的中斷進行完之後,並不會直接退出,而是會進入中斷回調函數中,用戶可以在其中設置代碼,

           串口中斷接收完成之後,會進入該函數,該函數爲空函數,用戶需自行修改,

參數:

  • UART_HandleTypeDef *huart      UATR的別名    如 :   UART_HandleTypeDef huart1;   別名就是huart1  
舉例:   HAL_UART_RxCpltCallback(&huart1){           //用戶設定的代碼               }

串口中斷處理函數

HAL_UART_IRQHandler(UART_HandleTypeDef *huart);  

功能:對接收到的數據進行判斷和處理  判斷是發送中斷還是接收中斷,然後進行數據的發送和接收,在中斷服務函數中使用

 

如果接收數據,則會進行接收中斷處理函數

 /* UART in mode Receiver ---------------------------------------------------*/
  if((tmp_flag != RESET) && (tmp_it_source != RESET))
  { 
    UART_Receive_IT(huart);
  }

如果發送數據,則會進行發送中斷處理函數

  /* UART in mode Transmitter ------------------------------------------------*/
  if (((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET))
  {
    UART_Transmit_IT(huart);
    return;
  }

3串口查詢函數

  HAL_UART_GetState();  判斷UART的接收是否結束,或者發送數據是否忙碌

  舉例:     

while(HAL_UART_GetState(&huart4) == HAL_UART_STATE_BUSY_TX)   //檢測UART發送結束

 

USATR接收與發送

 

重新定義printf函數

  • 在 stm32f4xx_hal.h 中包含#include <stdio.h>
#include "stm32f4xx_hal.h"
#include <stdio.h>
  • 在 stm32f4xx_hal.c 中重寫fget和fput函數
  • /**
      * 函數功能: 重定向c庫函數printf到DEBUG_USARTx
      * 輸入參數: 無
      * 返 回 值: 無
      * 說    明:無
      */
    int fputc(int ch, FILE *f)
    {
      HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
      return ch;
    }
    
    /**
      * 函數功能: 重定向c庫函數getchar,scanf到DEBUG_USARTx
      * 輸入參數: 無
      * 返 回 值: 無
      * 說    明:無
      */
    int fgetc(FILE *f)
    {
      uint8_t ch = 0;
      HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
      return ch;
    }
    
    在main.c中添加
 #define RXBUFFERSIZE  256
char RxBuffer[RXBUFFERSIZE]; 

  while (1)
  {
    /* USER CODE END WHILE */
			printf("Z小旋測試\n");
			HAL_Delay(1000);
    /* USER CODE BEGIN 3 */
  }

之後便可以使用Printf函數

UART接收中斷

因爲中斷接收函數只能觸發一次接收中斷,所以我們需要在中斷回調函數中再調用一次中斷接收函數

具體流程:

1、初始化串口

2、在main中第一次調用接收中斷函數

3、進入接收中斷,接收完數據  進入中斷回調函數

4、修改HAL_UART_RxCpltCallback中斷回調函數,處理接收的數據,

5  回調函數中要調用一次HAL_UART_Receive_IT函數,使得程序可以重新觸發接收中斷

函數流程圖:

HAL_UART_Receive_IT(中斷接收函數   ->  USART2_IRQHandler(void)(中斷服務函數)    ->    HAL_UART_IRQHandler(UART_HandleTypeDef *huart)(中斷處理函數)    ->    UART_Receive_IT(UART_HandleTypeDef *huart) (接收函數)   ->    HAL_UART_RxCpltCallback(huart);(中斷回調函數)

HAL_UART_RxCpltCallback函數就是用戶要重寫在main.c裏的回調函數。

代碼實現:

    並在main.c中添加下列定義:

#include <string.h>

#define RXBUFFERSIZE  256     //最大接收字節數
char RxBuffer[RXBUFFERSIZE];   //接收數據
uint8_t aRxBuffer;			//接收中斷緩衝
uint8_t Uart1_Rx_Cnt = 0;		//接收緩衝計數

在main()主函數中,調用一次接收中斷函數

/* USER CODE BEGIN 2 */
	HAL_UART_Receive_IT(&huart1, (uint8_t *)&aRxBuffer, 1);
/* USER CODE END 2 */

在while循環中添加:

  while (1)
  {
    /* USER CODE END WHILE */
		HAL_Delay(1000);
		HAL_UART_RxCpltCallback(&huart1);
    /* USER CODE BEGIN 3 */
  }

在main.c下方添加中斷回調函數

/* USER CODE BEGIN 4 */

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(huart);
  /* NOTE: This function Should not be modified, when the callback is needed,
           the HAL_UART_TxCpltCallback could be implemented in the user file
   */
 
	if(Uart1_Rx_Cnt >= 255)  //溢出判斷
	{
		Uart1_Rx_Cnt = 0;
		memset(Uart1_RxBuff,0x00,sizeof(Uart1_RxBuff));
		HAL_UART_Transmit(&huart1, (uint8_t *)"數據溢出", Uart1_Rx_Cnt,0xFFFF); 	
        
	}
	else
	{
		Uart1_RxBuff[Uart1_Rx_Cnt++] = aRxBuffer;   //接收數據轉存
	
		if((Uart1_RxBuff[Uart1_Rx_Cnt-1] == 0x0A)&&(Uart1_RxBuff[Uart1_Rx_Cnt-2] == 0x0D)) //判斷結束位
		{
			HAL_UART_Transmit(&huart1, (uint8_t *)&Uart1_RxBuff, Uart1_Rx_Cnt,0xFFFF); //將收到的信息發送出去
                        while(HAL_UART_GetState(&huart4) == HAL_UART_STATE_BUSY_TX)   //檢測UART發送結束
			Uart1_Rx_Cnt = 0;
			memset(Uart1_RxBuff,0x00,sizeof(Uart1_RxBuff)); //清空數組
		}
	}
	
	HAL_UART_Receive_IT(&huart1, (uint8_t *)&aRxBuffer, 1);   //再開啓接收中斷
}
/* USER CODE END 4 */

發送數據被正常返回

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章