STM32 HAL庫UART的使用

初始化

首先講下UART的初始化
1.聲明UART的初始化結構體,並賦值
2.MX生成的代碼會調用HAL_UART_MspInit();來初始化UART,固然這個代碼也是自動生成,不過用戶能夠在這個函數裏面添加本身想要添加的操做,時麪包括了NVIC_Configuration,DMA_Configuration等,也能夠添加一些置位操做如__HAL_UART_ENABLE,__HAL_UART_ENABLE_IT等等
3.在HAL_UART_MspDeInit()中添加一些與HAL_UART_MspInit相反的操做來完成UART的重置操做
對於以上的初始化操做,均可以由stm32cubemx自動生成,無需去具體配置寄存器。函數

而用戶使用HAL庫來驅動UART,在初始化好參數以後,測試

官方提供了三種方式


1、輪詢模式(Polling mode IO operation)

使用HAL_UART_Transmit()與HAL_UART_Receive()來配合超時操做來發送與接收數據
以ECHO方式(即收到什麼發什麼)爲例,這種方式進行操做
用輪詢方式的代碼是比較簡短的ui

if(HAL_UART_Receive(&huart1, testReceiveData, 10, 1000) == HAL_OK)
      {
            HAL_UART_Transmit(&huart1, testReceiveData, 10, 1000);
      }

以這種方式就能夠實現發送接收的數據,不過這種方式來處理的話,長度不定的時候,數據的丟失量會比較大code

減小等待超時,與調整BUFFER的長度都仍是會有不一樣程度的數據丟失
若是將BUFFER的長度調整爲1,數據丟失量會減小,不過這個時候會出現UART工做一段時間以後就發生異常,由於UART發生ORE錯誤置位,須要將這個錯誤置位清除掉才能夠再正常接收
代碼以下回調函數

if(HAL_UART_Receive(&huart1, testReceiveData, 1, 10) == HAL_OK)
      {
            HAL_UART_Transmit(&huart1, testReceiveData, 1, 10);
      }
      else
      {
            __HAL_UART_CLEAR_OREFLAG(&huart1);
      }

若是將發送改成由寄存器直接操做的話it

if(HAL_UART_Receive(&huart1, testReceiveData, 1, 10) == HAL_OK)
      {
            huart1.Instance->DR = testReceiveData[0];
      }
      else
      {
            __HAL_UART_CLEAR_OREFLAG(&huart1);
      }

這樣測試過來數據就沒有丟失。
說明仍是在發送API的時候,同時又接收到數據致使的數據丟失,或者說API發送使用時間相對於直接操做寄存器仍是要長不少io


2、中斷模式(Interrupt mode IO operation)

使用HAL_UART_Transmit_IT()與HAL_UART_Receive_IT來發送接收,在發送或接收完以後,再進行函數回調HAL_UART_TxCpltCallback與HAL_UART_RxCpltCallback來進行處理這兩個函數都是由用戶從新定義的,來實現用戶本身的操做test

在系統初始化後,直接調用HAL_UART_Receive_IT(&huart1, testReceiveData, 1);便可這個長度可由用戶本身定義
當達到接收長度以後,就能夠進行cplt完成函數的重構及回調重構

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *uartHandle)
{
      if(uartHandle->Instance == USART1)
      {
            uartHandle->Instance->DR = testReceiveData[0];
            //HAL_UART_Transmit_IT(uartHandle, testReceiveData, 1);
            HAL_UART_Receive_IT(uartHandle, testReceiveData, 1);
      }
}

使用寄存器直接操做的方式是能夠作到數據不丟失,而使用發送函數仍是會出現不一樣程序的數據丟失
數據接收完以後,若要從新開始接收必須從新開啓HAL_UART_Receive_IT配置


3、DMA模式(DMA mode IO operation)

使用HAL_UART_Transmit_DMA()與HAL_UART_Receive_DMA()來發送接收,在發送或接收完以後,也使用HAL_UART_TxCpltCallback與HAL_UART_RxCpltCallback來完成實際操做,同時接收到一半的時候,也能夠調用相應的HAL_UART_TxHalfCpltCallback與HAL_UART_RxHalfCpltCallback,若是須要用到這個操做的狀況下能夠添加本身的操做,固然來還用到一關於DMA的API函數,如HAL_UART_DMAPause,HAL_UART_DMAResume, HAL_UART_DMAStop等

在初始化UART的同時須要初始化相應的DMA,並將DMA與UART進行關聯,不過這部分代碼均可以自動生成
開始時調用HAL_UART_Receive_DMA(&huart1, uartDeviceRxBuf, UART_BUF_LEN);
在接收到的相應長度的數據以後DMA會產生一個完成的中斷,其回調函數與中斷模式相同,雖然二者發生中斷地方不一致,可是操做是同一個

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *uartHandle)
{
      if(uartHandle->Instance == USART1)
      {
            HAL_UART_Transmit(uartHandle, uartDeviceRxBuf, 100, 1000);
            HAL_UART_Receive_DMA(uartHandle, uartDeviceRxBuf, 100);
      }
}

一樣在接收完成後,要從新開啓接收,否則以後的數據就接收不到了

其餘

除了上述官方的方式,固然還有一些別的方式,直接操做寄存器確定也是能夠的,而用HAL庫時面也有必定宏定義能夠直接來操做寄存器

__HAL_UART_CLEAR_FLAG(uartHandle, UART_FLAG_RXNE);
      __HAL_UART_ENABLE_IT(uartHandle, UART_IT_RXNE);

能夠使用這些定義來直接操做寄存器,初化接收中斷
在中斷中也直接操做寄存器來完成接收

/* USER CODE BEGIN USART1_IRQn 0 */
      if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE) != RESET)
      {
            uint8_t tmp;
            __HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_RXNE);
            tmp = huart1.Instance->DR;
            huart1.Instance->DR = tmp;
      }
  /* USER CODE END USART1_IRQn 0 */
  //HAL_UART_IRQHandler(&huart1);

中斷中如此操做來完成ECHO操做

對於官方提供的操做方式,不管是哪一種方式基本上是不能同時使用Transmit與Receive操做,並且官方提供的這些API,很好用,可是用到實際的應用中,還須要用戶寫一部分代碼來完成整個操做,主要就是一個BUFFER的進出操做,使數據在很短的時間從設備的代碼提取出來,而不影響設備的接收與發送,能夠防止數據丟失的發生。

相關文章
相關標籤/搜索