1. 程式人生 > 其它 >Uart非同步串列埠通訊

Uart非同步串列埠通訊

技術標籤:STM32學習筆記

1. 什麼是UART?

(1)UART,通用非同步收發器。相比於USART,UART收發是以字元為單位,沒有CLK同步時鐘。

(2)UART最主要的是三根資料線:

  • TXD傳送引腳
  • RXD接收引腳
  • GND接地引腳

(3)UART比較重要的幾個引數:

  • 波特率:每秒傳送的碼元數,比如9600,115200
  • 資料位:典型值5、6、8、9位
  • 奇偶校驗位:一般分為奇校驗和偶校驗或者無校驗位
  • 停止位:典型值1、1.5、2位

(4)UART工作示意圖如下圖所示:


UART工作模式 這是典型的UART非同步通訊模式,資料位為8,無奇偶校驗位,一位停止位。UART串列埠傳送一次包含:起始位,資料位(低位在前),奇偶校驗位(可選),以及停止位。

2. 以STM32為例,分析UART工作原理

(1)瞭解STM32串列埠主要特性

  • 可程式設計資料字長度(8位或9位)
  • 可配置的停止位-支援1或2個停止位
  • 可配置的使用DMA的多緩衝器通訊
  • 單獨的傳送器和接收器使能位
  • 檢測標誌:接收緩衝器滿、傳送緩衝器空、傳輸結束標誌

(2)瞭解STM32串列埠主要暫存器

STM32串列埠工作流程如下圖:


UART工作流程

狀態暫存器USART_SR

  • TXE(傳送資料暫存器空),當資料全部移入傳送移位暫存器時,置1
  • TC(傳送完成),當一幀資料傳送完成,且TXE=1時,置1
  • RXNE(讀資料暫存器非空),當有資料讀入資料暫存器USART_DR時,置1

資料暫存器USART_DR,傳送或接收快取資料

控制暫存器1 USART_CR1,主要用於配置中斷和使能

  • UE(USART使能),TE(傳送使能),RE(接收使能)
  • TXEIE 傳送緩衝區空中斷使能
  • TCIE 傳送完成中斷使能
  • RXNEIE 接收緩衝區非空中斷使能

(3)STM32基本配置:波特率,資料位,奇偶校驗位,停止位,串列埠/中斷使能

3. UART傳送資料

(1)首先是對UART串列埠的初始化配置

(2)呼叫函式 HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)

  • huart是UART控制代碼結構體(姑且先這麼叫)
  • pData是待發送的字元陣列,每次傳送前都需要進行一次讀寫,可以呼叫sprintf函式
  • Size是指pData字元陣列的長度,一般是strlen(pData)
  • Timeout是待發送資料的生存時間,若超時會返回HAL_TIMEOUT

(3)自定義函式usUART_sendString(UART_HandleTypeDef *huart, uint8_t *pData)

  • 這是根據HAL庫傳送函式由使用者進行改寫的字串傳送函式,形參只有兩個
  • 函式編寫借鑑51微控制器串列埠思想,程式碼編寫如下:
void usUart_sendString(UART_HandleTypeDef *huart, uint8_t *pData)
{
  /*
  判斷是否傳送完成
  */
  while(*pData)   
  {
    /*
    每次傳送一個字元
    */
    HAL_StatusTypeDef HAL_UART_Transmit(huart, pData, 1, 0xffff);
    /*
    字元指標移位,指向下一個字元的內容
    */
    pData++;
  }
}

4. UART接收

(1)首先對UART串列埠進行初始化

(2)呼叫函式HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)

  • 採用這種方法一般都是查詢法,如下:
/* 判斷是否接收成功 */
if(HAL_UART_Receive(&huart1, &uRx_Data, 1, 1000) == HAL_OK)
{
  /* 將接收成功的資料通過串列埠發出來 */
  HAL_UART_Transmit(&huart1, &uRx_Data, 1, 0xffff);
}
  • 這種方式接收,必須事先知曉接收資料的長度,否則大概率會出錯;其次,採用此方法會嚴重佔用MCU的資源,尤其是放到while函式中。
  • 除此之外,若是採用中斷的方法,像這樣接收後直接處理,就會出現另一個問題,即,還未傳送出去(移位暫存器還未清空)就直接進入下一次中斷

(3)採用中斷方式(接收完成後再處理)

  • 首先需要配置中斷,中斷配置在此略過……
  • 中斷函式程式碼編寫如下:
/*
* @brief This function handles USART1 global interrupt.
*/
void USART1_IRQHandler(void)
{
  static unsigned char   uRx_Data[1024] = {0}     ;    //儲存陣列
  static unsigned char * pRx_Data       = uRx_Data;    //指向儲存陣列將要儲存資料的位
  static unsigned char   uLength        =  0      ;    //接收資料長度

  /* -1- 接收資料 */
  HAL_UART_Receive(&huart1, pRx_Data, 1, 1000);

  /* -2- 判斷資料結尾 */
  if(*pRx_Data == '\n')
  {
      /* -3- 將接收成功的資料通過串列埠發出去 */
      HAL_UART_Transmit(&huart1, uRx_Data, uLength, 0xffff);

      /* -4- 初始化指標和資料長度 */
      pRx_Data = uRx_Data;   //重新指向陣列起始位置
      uLength  = 0;          //長度清零
  }
  /* -5- 若未結束,指標往下一位移動,長度自增一 */
  else
  {
      pRx_Data++;
      uLength++;
  }
  HAL_UART_IRQHandler(&huart1);
}

參考資料

[1] 基於STM32之UART串列埠通訊協議(三)接收

[2] UART串列埠通訊協議原理