STM32 HAL庫 UART 串口讀寫功能筆記


https://www.cnblogs.com/Mysterious/p/4804188.html

STM32L0 HAL庫 UART 串口讀寫功能

串口發送功能:

uint8_t TxData[10]= "01234abcde";
HAL_UART_Transmit(&huart2,TxData,10,0xffff);//把TxData的內容通過uart2發送出去,長度是10,timeout的時間是最大值0xffff

串口接收功能1:

uint8_t value='F';
HAL_UART_Receive(&huart2,(uint8_t *)&value,1,1000);//在這個語句停留1000ms內等待接收1個字節數據,把數據存放在value中

串口接收功能2:

HAL_UART_Receive_IT(&huart2,(uint8_t *)&value,1);//程序不會在這個語句停留,直接會按照中斷方式把接收數據存放在value中,但是這個語句只能使能一次串口中斷。所以要在中斷服務函數或者回調函數中重新使能

串口接收功能3:

if(HAL_UART_Receive_IT(&huart2,(uint8_t *)&value,1) != HAL_OK){    //這一句寫在main函數的while(1)上面。用於啟動程序啟動一次中斷接收
        HAL_UART_Transmit(&huart2, (uint8_t *)&"ERROR\r\n",7,10);    
        while(1);
} 
復制代碼
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)
{
    HAL_UART_Transmit(&huart2, (uint8_t *)&"\r\ninto HAL_UART_RxCpltCallback\r\n",32,0xffff);    //驗證進入這個函數了
    HAL_UART_Transmit(&huart2,(uint8_t *)&value,1,0xffff);      //把接收到的數據通過串口發送出去        
    HAL_UART_Receive_IT(&huart2,(uint8_t *)&value,1);        //重新打開串口中斷
}
復制代碼

串口DMA發送

DMA的TX要這樣設置

    uint8_t txData[] = {"HelloWorld\r\n"};
    HAL_UART_Transmit_DMA(&huart2,txData,sizeof(txData));//可以通過DMA把數據發出去

 DMA接收

if(HAL_UART_Receive_DMA(&huart2, (uint8_t *)rxData, sizeof(rxData)-1) != HAL_OK)//main函數while(1)前,啟動一次DMA接收
    {
        Error_Handler();
    }

 串口回調函數:

復制代碼
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle){
    
    uint8_t temp[] = {"\r\nin Callback\r\n"};
    HAL_UART_Transmit_DMA(&huart2,temp,sizeof(temp)-1);//可以通過DMA把數據發出去
    
    HAL_UART_Receive_DMA(&huart2, (uint8_t *)rxData, sizeof(rxData)-1);    //重新使能接收    
}
復制代碼

 main函數while(1)中不斷輸出rxData值

HAL_UART_Transmit_DMA(&huart2,rxData,sizeof(rxData)-1);//可以通過DMA把數據發出去

https://www.cnblogs.com/UnfriendlyARM/p/10321838.html

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   }
復制代碼

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

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

  這樣就可以實現多次數據返回了,新的執行結果如下圖:

 

  可見,函數HAL_UART_Receive_IT還有中斷使能的作用。這一功能的實現我們可以在HAL_UART_Receive_IT函數中找到。

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

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

  ②注冊中斷函數    

復制代碼
 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使用了標准庫中斷處理數據的思想。


免責聲明!

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



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