STM32串口接收中斷——基於HAL庫

寫在前面  

  最近須要使用一款STM32L4系列的芯片進行開發,須要學習使用HAL庫。在進行串口中斷使用的時候遇到了一些小麻煩,寫下解決方案供你們參考。

1.UART相關的頭文件引用錯誤

   因爲本人直接使用MDK進行開發,沒有使用CubeMX,因此一些初始化須要手動進行。在引用UART相關的頭文件時,記得將"stm32l4xx_hal_conf.h"文件中的相關宏定義取消註釋,以下圖:

2.如何接收字符串(屢次進入中斷)

  接收字符串主要有兩種方法,一種是對中斷函數進行改造,另外一種是對接收回調函數進行改造。
  在闡述這兩種方法以前,須要介紹函數「HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)」。該函數的做用是用戶自定義一個緩衝區(即參數pData),接受必定數量(由參數Size決定)的字符存入緩衝區中。同時,參數Size還決定着進入回調函數的頻率,即每接收Size個字符,就進入一次回調函數。須要注意的是,Size只決定進入回調函數的頻率,而不能影響進入接收中斷的頻率,不管Size是多少,每接收完成一個字符都會進入一次接收中斷。

方法1:改造回調函數

  ①首先在主函數中進入主循環前的位置調用一次 HAL_UART_Receive_IT函數,定義一個字符數組getBuffer[]做爲緩衝區,參數Size設定爲10。即每接收10個字符,就進入一次回調函數。

  ②註冊中斷函數   數組

1  void USART1_IRQHandler(void) 2  { 3    HAL_UART_IRQHandler(&UartHandle); //該函數會清空中斷標誌,取消中斷使能,並間接調用回調函數
4  }

  ③在文件「stm32l4xx_hal_uart.h」中,咱們能夠看到串口接收回調函數的定義。使用「_weak」關鍵字定義的函數,其具備以下特性: 通常狀況下和通常函數相同。可是當有一個同名函數可是不帶__weak被定義時,全部對這個函數的調用都是指向後者(不帶__weak那個)。也就是說,ST官方提供的這個回調函數須要咱們本身進行改寫。  函數

 1    /**  2  * @brief Rx Transfer completed callback.  3  * @param huart UART handle.  4  * @retval None  5     */
 6   __weak void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)  7  {  8     /* Prevent unused argument(s) compilation warning */
 9  UNUSED(huart); 10       
11     /* NOTE : This function should not be modified, when the callback is needed, 12  the HAL_UART_RxCpltCallback can be implemented in the user file. 13      */
14   }

  咱們在主函數所在的文件中對回調函數進行改寫:  學習

1   uint8_t myBuffer[] = "I have gotten your message: "; //用戶提示信息
2   uint8_t Enter[] = "\r\n"; //回車換行
3   uint8_t getBuffer[100]; //用戶自定義的緩衝區
4   void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle) 5  { 6    while(HAL_UART_Transmit(UartHandle, (uint8_t*)myBuffer, COUNTOF(myBuffer), 5000)!= HAL_OK); //發送字符串,用戶提示信息
7    while(HAL_UART_Transmit(UartHandle, (uint8_t*)getBuffer, 10, 5000)!= HAL_OK); //發送用戶自定義緩衝區中的數據
8    while(HAL_UART_Transmit(UartHandle, (uint8_t*)Enter, COUNTOF(Enter), 5000)!= HAL_OK); //發送回車換行
9   }

  以上代碼的做用是把用戶發送給單片機數據再返回給用戶。運行效果以下圖:ui

 
  咱們能夠看到,用戶向單片機發送了10個字符,單片機向串口助手返回了這10個數據。可是以上程序只能實現一次,當咱們再次向單片機發送數據時,單片機卻再也不返回數據。這是由於咱們在中斷函數中取消了中斷使能,因此致使了進入一次中斷後,中斷被關閉,沒法再次進入中斷的現象。爲了實現屢次數據返回,咱們要在中斷處理函數中添加一行代碼: 
1  void USART1_IRQHandler(void) 2  { 3    HAL_UART_IRQHandler(&UartHandle); //該函數會清空中斷標誌,取消中斷使能,並間接調用回調函數
4    HAL_UART_Receive_IT(&UartHandle, (uint8_t *)&value,1);  //添加的一行代碼
5  }

  這樣就能夠實現屢次數據返回了,新的執行結果以下圖:spa

 

  可見,函數HAL_UART_Receive_IT還有中斷使能的做用。這一功能的實現咱們能夠在HAL_UART_Receive_IT函數中找到。code

 方法2:改造中斷處理函數

  ①首先在主函數中進入主循環前的位置調用一次 HAL_UART_Receive_IT函數,定義一個字符value做爲緩衝區,參數Size設定爲1。即每接收1個字符,就進入一次回調函數。使得進入回調函數的頻率與進入中斷處理函數的頻率相同。這樣,咱們就能夠直接在中斷函數中對接收的數據進行處理了。

  ②註冊中斷函數    blog

 1   uint8_t myBuffer[] = "I have gotten your message: ";  2   uint8_t getBuffer[10];  3   uint8_t Enter[] = "\r\n";  4   void USARTx_IRQHandler(void)  5  {  6    HAL_UART_IRQHandler(&UartHandle); //該函數會清空中斷標誌,取消中斷使能,並間接調用回調函數
 7    
 8    getBuffer[countOfGetBuffer++] = value;  9    if(countOfGetBuffer == 10) 10  { 11     while(HAL_UART_Transmit(&UartHandle, (uint8_t*)myBuffer, COUNTOF(myBuffer), 5000)!= HAL_OK); 12     while(HAL_UART_Transmit(&UartHandle, (uint8_t*)getBuffer, countOfGetBuffer, 5000)!= HAL_OK); 13     while(HAL_UART_Transmit(&UartHandle, (uint8_t*)Enter, COUNTOF(Enter), 5000)!= HAL_OK); 14     countOfGetBuffer = 0; 15  } 16    HAL_UART_Receive_IT(&UartHandle, (uint8_t *)&value,1);  //因爲接收中斷是每接收一個字符便進入一次,因此這一行代碼必須添加,不然只能接收一個字符,而沒法接收整個字符串
17   }

  以上代碼的做用是接收每一個來自用戶的字符,並依次存入用戶自定義的緩衝區中,數量達到10個後,將緩衝區中的全部數據返回給用戶,同時清空計數,準備接下來10個字符的接收。運行效果以下圖:開發

 

寫在最後

  看完本文,你們可能對回調函數中斷處理函數的關係產生了疑問。實際上是這樣的,單片機每完成接收一個字符,就會進入一次中斷處理函數,而在中斷處理函數中,咱們又調用了函數「void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)」,該函數會間接調用回調函數,也就是說回調函數是由中斷處理函數間接調用的。而函數「HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)」決定了中斷處理函數調用回調函數的頻率,若Size爲1,則每進入一次中斷處理函數都會調用一次回調函數;若Size爲10,則每第十次進入中斷處理函數時,纔會調用回調函數。方法2使用了標準庫中斷處理數據的思想。字符串

相關文章
相關標籤/搜索