Uart非同步串列埠通訊
阿新 • • 發佈:2021-02-11
技術標籤: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);
}
參考資料
[2] UART串列埠通訊協議原理