一、前言
1、簡介
寫的這篇博客,是為了簡單講解一下UART通信協議,以及UART能夠實現的一些功能,還有有關使用STM32CubeMX來配置芯片的一些操作,在后面我會以我使用的STM32F429開發板來舉例講解(其他STM32系列芯片大多數都可以按照這些步驟來操作的),如有不足請多多指教。
2、UART簡介
嵌入式開發中,UART串口通信協議是我們常用的通信協議(UART、I2C、SPI等)之一,全稱叫做通用異步收發傳輸器(Universal Asynchronous Receiver/Transmitter)。
3、准備工作
1)Keil5
鏈接:點擊下載
提取碼:wrt9
2)STMCubeMX5.1.0版本
鏈接:點擊下載
提取碼:20xs
3)STMF429開發板

注:
只要是stm32的開發板都可以用到的,在STM32CubeMx里選對型號、配置好就行了。
二、UART詳解
1、UART簡介
嵌入式開發中,UART串口通信協議是我們常用的通信協議(UART、I2C、SPI等)之一,全稱叫做通用異步收發傳輸器(Universal Asynchronous Receiver/Transmitter),是異步串口通信協議的一種,工作原理是將傳輸數據的每個字符一位接一位地傳輸,它能將要傳輸的資料在串行通信與並行通信之間加以轉換,能夠靈活地與外部設備進行全雙工數據交換。
注:
在此開發板中,是有USART(Universal Synchronous Asynchronous Receiver and Transmitter通用同步異步收發器)串口的,USART相當於UART的升級版,USART支持同步模式,因此USART 需要同步始終信號USART_CK(如STM32 單片機),通常情況同步信號很少使用,因此一般的單片機UART和USART使用方式是一樣的,都使用異步模式。因為USART的使用方法上跟UART基本相同,所以在此就以UART來講該通信協議了。
2、UART通信協議

1)起始位
當未有數據發送時,數據線處於邏輯“1”狀態;先發出一個邏輯“0”信號,表示開始傳輸字符。
2)數據位
緊接着起始位之后。資料位的個數可以是4、5、6、7、8等,構成一個字符。通常采用ASCII碼。從最低位開始傳送,靠時鍾定位。
3)奇偶校驗位
資料為加上這一位后,使得“1”的位數應為偶數(偶校驗)或奇數(奇校驗),以此來校驗資料傳送的正確性。
4)停止位
它是一個字符數據的結束標志。可以是1位、1.5位、2位的高電平。 由於數據是在傳輸線上定時的,並且每一個設備有其自己的時鍾,很可能在通信中兩台設備間出現了小小的不同步。因此停止位不僅僅是表示傳輸的結束,並且提供計算機校正時鍾同步的機會。適用於停止位的位數越多,不同時鍾同步的容忍程度越大,但是數據傳輸率同時也越慢。
5)空閑位或起始位
處於邏輯“1”狀態,表示當前線路上沒有資料傳送,進入空閑狀態。
處於邏輯“0”狀態,表示開始傳送下一數據段。
6)波特率
表示每秒鍾傳送的碼元符號的個數,是衡量數據傳送速率的指標,它用單位時間內載波調制狀態改變的次數來表示。
常用的波特率有:9600、115200……
時間間隔計算:1秒除以波特率得出的時間,例如,波特率為9600的時間間隔為1s / 9600(波特率) = 104us。
3、UART功能說明
接口通過三個引腳從外部連接到其它設備。任何 USART 雙向通信均需要 至少兩個引腳:接收數據輸入引腳 (RX) 和發送數據引腳輸出 (TX):
RX:接收數據輸入引腳就是串行數據輸入引腳。過采樣技術可區分有效輸入數據和噪聲,從而用於恢復數據。
TX:發送數據輸出引腳。如果關閉發送器,該輸出引腳模式由其 I/O 端口配置決定。如果使 能了發送器但沒有待發送的數據,則 TX 引腳處於高電平。在單線和智能卡模式下,該 I/O 用於發送和接收數據(USART 電平下,隨后在 SW_RX 上接收數據)。
1)正常 USART 模式下,通過這些引腳以幀的形式發送和接收串行數據:
- 發送或接收前保持空閑線路
- 起始位
- 數據(字長 8 位或 9 位),最低有效位在前
- 用於指示幀傳輸已完成的 0.5 個、1 個、1.5 個、2 個停止位
- 該接口使用小數波特率發生器 - 帶 12 位尾數和 4 位小數
- 狀態寄存器 (USART_SR)
- 數據寄存器 (USART_DR)
- 波特率寄存器 (USART_BRR) - 12 位尾數和 4 位小數。
- 智能卡模式下的保護時間寄存器 (USART_GTPR)。
2)在同步模式下連接時需要以下引腳:
- SCLK:發送器時鍾輸出。該引腳用於輸出發送器數據時鍾,以便按照 SPI 主模式進行同步發送(起始位和結束位上無時鍾脈沖,可通過軟件向最后一個數據位發送時鍾脈沖)。RX 上可同步接收並行數據。這一點可用於控制帶移位寄存器的外設(如 LCD 驅動器)。時鍾相位和極性可通過軟件編程。在智能卡模式下,SCLK 可向智能卡提供時鍾。在硬件流控制模式下需要以下引腳:
- nCTS:“清除以發送”用於在當前傳輸結束時阻止數據發送(高電平時)。
- nRTS:“請求以發送”用於指示 USART 已准備好接收數據(低電平時)。
USART框圖如下:

4、UART工作原理
1)發送接收
2)波特率產生
波特率除數(baud-rate divisor)是一個22 位數,它由16 位整數和6 位小數組成。波特率發生器使用這兩個值組成的數字來決定位周期。通過帶有小數波特率的除法器,在足夠高的系統時鍾速率下,UART 可以產生所有標准的波特率,而誤差很小。
3)數據收發
發送時,數據被寫入發送FIFO。如果UART 被使能,則會按照預先設置好的參數(波特率、數據位、停止位、校驗位等)開始發送數據,一直到發送FIFO 中沒有數據。一旦向發送FIFO 寫數據(如果FIFO 未空),UART 的忙標志位BUSY 就有效,並且在發送數據期間一直保持有效。BUSY 位僅在發送FIFO 為空,且已從移位寄存器發送最后一個字符,包括停止位時才變無效。即 UART 不再使能,它也可以指示忙狀態。
在UART 接收器空閑時,如果數據輸入變成“低電平”,即接收到了起始位,則接收計數器開始運行,並且數據在Baud16 的第8 個周期被采樣。如果Rx 在Baud16 的第8 周期仍然為低電平,則起始位有效,否則會被認為是錯誤的起始位並將其忽略。
4)中斷控制
出現以下情況時,可使UART 產生中斷:
-
FIFO 溢出錯誤
-
線中止錯誤(line-break,即Rx 信號一直為0 的狀態,包括校驗位和停止位在內)
-
奇偶校驗錯誤
-
幀錯誤(停止位不為1)
-
接收超時(接收FIFO 已有數據但未滿,而后續數據長時間不來)
-
發送
-
接收
由於所有中斷事件在發送到中斷控制器之前會一起進行“或運算”操作,所以任意時刻 UART 只能向中斷產生一個中斷請求。通過查詢中斷狀態函數,軟件可以在同一個中斷服務函數里處理多個中斷事件(多個並列的if 語句)。
5)FIFO 操作
FIFO 是“First-In First-Out”的縮寫,意為“先進先出”,是一種常見的隊列操作。 Stellaris 系列ARM 的UART 模塊包含有2 個16 字節的FIFO:一個用於發送,另一個用於接收。可以將兩個FIFO 分別配置為以不同深度觸發中斷。可供選擇的配置包括:1/8、 1/4、1/2、3/4 和7/8 深度。例如,如果接收FIFO 選擇1/4,則在UART 接收到4 個數據時產生接收中斷。
6)回環操作
UART 可以進入一個內部回環(Loopback)模式,用於診斷或調試。在回環模式下,從Tx 上發送的數據將被Rx 輸入端接收。
三、CubeMx配置
說明:
在使用STM32CubeMx配置的時候,首先要選擇正在使用的芯片的型號,再配置芯片的時鍾,然后才去配置所需要用到的功能。
1、新建項目
1)選擇新建

2)選擇芯片型號

2、時鍾配置
1)配置界面

2)時鍾模式配置

3)設置調試接口

4)時鍾配置(盡量將下面方框內的值設成最高值即可)

3、功能配置
1)啟用串口

2)配置串口(默認即可,波特率為115200)

4、生成工程
1)項目信息設置

2)選擇生成必要的代碼

3)生成代碼

4)打開項目(生成代碼成功后會彈出窗口,可以直接打開工程)

注:
因為STM32CubeMX自動生成的代碼中,沒有設置把每次下載燒寫都重置一下,所以生成代碼后,我們需要自己選上該功能,步驟如下:
1)功能界面
2)選擇小錘子
3)選擇Debug->Settings
4)選擇Flash Download->勾選Reset and Run
完成上面的操作后,在每次燒寫都會重置,並運行新下載燒寫的程序了。
四、HAL庫關鍵函數說明
1、初始化/還原初始化函數
1 /* Initialization/de-initialization functions **********************************/ 2 HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart); //根據UART_InitTypeDef中指定的參數初始化UART模式,並創建關聯的句柄。 3 HAL_StatusTypeDef HAL_HalfDuplex_Init(UART_HandleTypeDef *huart); //根據UART_InitTypeDef中指定的參數初始化半雙工模式並創建關聯句柄。 4 HAL_StatusTypeDef HAL_LIN_Init(UART_HandleTypeDef *huart, uint32_t BreakDetectLength); //根據UART_InitTypeDef中指定的參數初始化LIN模式,並創建關聯的句柄。 5 HAL_StatusTypeDef HAL_MultiProcessor_Init(UART_HandleTypeDef *huart, uint8_t Address, uint32_t WakeUpMethod); //根據UART_InitTypeDef中指定的參數初始化多處理器模式,並創建關聯的句柄。 6 HAL_StatusTypeDef HAL_UART_DeInit(UART_HandleTypeDef *huart); //非初始化UART外圍設備。 7 void HAL_UART_MspInit(UART_HandleTypeDef *huart); //弱函數UART MSP初始化 8 void HAL_UART_MspDeInit(UART_HandleTypeDef *huart); //弱函數UART MSP初始化還原
2、IO口操作函數
1 /* IO operation functions *******************************************************/ 2 HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);//以阻塞模式發送大量數據。 3 HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout); //在阻塞模式下接收大量數據。 4 HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size); //以非阻塞模式發送大量數據。 5 HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size); //在非阻塞模式下接收大量數據。 6 HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size); //以非阻塞模式發送大量數據。 7 HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size); //在非阻塞模式下接收大量數據。 8 HAL_StatusTypeDef HAL_UART_DMAPause(UART_HandleTypeDef *huart); //暫停DMA傳輸。 9 HAL_StatusTypeDef HAL_UART_DMAResume(UART_HandleTypeDef *huart); //恢復DMA傳輸。 10 HAL_StatusTypeDef HAL_UART_DMAStop(UART_HandleTypeDef *huart); //停止DMA傳輸。
3、傳輸中斷函數
1 /* Transfer Abort functions */ 2 HAL_StatusTypeDef HAL_UART_Abort(UART_HandleTypeDef *huart); //中止正在進行的傳輸(阻塞模式)。 3 HAL_StatusTypeDef HAL_UART_AbortTransmit(UART_HandleTypeDef *huart); //中止正在進行的傳輸傳輸(阻塞模式)。 4 HAL_StatusTypeDef HAL_UART_AbortReceive(UART_HandleTypeDef *huart); //中止正在進行的接收傳輸(阻塞模式)。 5 HAL_StatusTypeDef HAL_UART_Abort_IT(UART_HandleTypeDef *huart); //中止正在進行的傳輸(中斷模式)。 6 HAL_StatusTypeDef HAL_UART_AbortTransmit_IT(UART_HandleTypeDef *huart); //中止正在進行的傳輸(中斷模式)。 7 HAL_StatusTypeDef HAL_UART_AbortReceive_IT(UART_HandleTypeDef *huart); //中止正在進行的接收傳輸(中斷模式)。
4、中斷處理及回調函數
1 void HAL_UART_IRQHandler(UART_HandleTypeDef *huart); //函數處理UART中斷請求。 2 void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart); //Tx傳輸完成回調函數。 3 void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart); //Tx半傳輸完成回調函數。 4 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart); //Rx傳輸完成回調函數。 5 void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart); //Rx完成一半傳輸回調函數。 6 void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart); //UART錯誤回調函數。 7 void HAL_UART_AbortCpltCallback(UART_HandleTypeDef *huart); //UART中止完成回調函數。 8 void HAL_UART_AbortTransmitCpltCallback(UART_HandleTypeDef *huart); //UART中止完成回調函數。 9 void HAL_UART_AbortReceiveCpltCallback(UART_HandleTypeDef *huart); //UART中止接收完整的回調函數。
五、結尾
1、總結
這篇博客主要是講解一下UART串口通信協議的時序、功能以及工作原理,還有使用STM32CubeMX來配置USART。而還未講到有關HAL庫函數的函數調用,有了STM32CubeMX生成的這個HAL庫函數,我們基本不用管協議上的事情了,可以直接調用里面的發送或接收函數來實現UART通信。而我也會在后續繼續編寫有關HAL庫的調用說明,詳細說一下HAL庫是如何使用的。
2、后續
1)UART發送
2)UART接收
3)待續未完……
~
~
~
~
最后~最后~最后~
歡迎大家關注我的博客,一起分享嵌入式知識~




