作者:junziyang
(注:如非特別聲明,以下筆記內(nèi)容均針對STM32F103ZET6而言。不同型號,細(xì)節(jié)可能存在差別。)
6.1 USART簡介
USART全稱為Universal synchronous asynchronous receiver transmitter,意為通用同步異步收發(fā)器。顧名思義,該模塊可以同步或異步方式,實現(xiàn)數(shù)據(jù)的接收或發(fā)送。USART是一種常用的串行(數(shù)據(jù)按一定的格式按位排隊發(fā)送)通信接口,堪稱萬能接口。主要功能和特點如下:
- 采用NRZ(none return zero)行業(yè)標(biāo)準(zhǔn)
- 支持全雙工異步通信
- 支持單線半雙工通信
- 支持IrDA串行紅外(SIR)編解碼器,常規(guī)模式支持3/16位長度
- 支持LIN(local interconnection network),具備主同步斷開發(fā)送能力和從斷開檢測能力。當(dāng)USART硬件配置位LIN時,可生成13位斷開符和10/11為斷開檢測符
- 具備智能卡模擬功能。支持ISO 7816-3標(biāo)準(zhǔn)定義的異步協(xié)議智能卡,支持0.5和1.5停止位。
- 通過DMA可配置多緩沖器通信。采用集中式DMA,可在SRAM中預(yù)留接收/發(fā)送緩沖字節(jié)
- 采用分?jǐn)?shù)波特率發(fā)生系統(tǒng),可編程傳輸和接收波特率高達(dá)460800(4.5M bits/s)
- 數(shù)據(jù)字長可編程(8位或9位)
- 停止位可配置,支持1個或2個停止位
- 發(fā)射器為同步傳輸提供時鐘
- 接收器和發(fā)射器使能位獨立
- 支持以下傳輸檢查標(biāo)志:
- 接收緩沖器慢
- 發(fā)射緩沖器孔
- 傳輸結(jié)束標(biāo)志
- 校驗控制:發(fā)送校驗位;對接收到的數(shù)據(jù)字節(jié)進(jìn)行校驗
- 支持4個錯誤檢查標(biāo)志:溢出錯誤;噪聲錯誤;幀錯誤;校驗錯誤
- 支持10個帶標(biāo)志中斷源:CTS改變;LIN斷開;傳輸數(shù)據(jù)寄存器空;傳輸完成;接收數(shù)據(jù)寄存器滿;傳輸線空閑檢測;溢出錯誤;噪聲錯誤;幀錯誤;校驗錯誤
- 支持多處理器通信 – 如果地址不匹配,進(jìn)入靜默模式
- 從靜默模式喚醒(通過空閑總線檢測或地址標(biāo)準(zhǔn)檢測)
- 具備2種接收器喚醒模式:地址位(MSB第9位),總線空閑
STM32F103ZET6共有3個USART和2個UART,UART功能與USART類似,只是僅支持異步通信。同步通信和異步通信的本質(zhì)區(qū)別在于,通信時是否需要時鐘同步。平時常用的串口通訊基本都是UART。
6.2 USART工作原理
6.2.1 USART原理框圖
圖1. USART 框圖
圖1所示為USART的框圖。左下角是波特率發(fā)生器,通過配置BRR寄存器,設(shè)置波特率分頻系數(shù),對PCLKx進(jìn)行分頻,產(chǎn)生接收器時鐘,再經(jīng)16分頻,產(chǎn)生發(fā)送控制器時鐘。兩路時鐘分別送往接收控制器(Receiver control)和發(fā)送控制器(Transmit control)。兩個控制器匯總中部5個寄存器中的設(shè)置,將控制信號分別發(fā)往兩個移位寄存器和中斷控制器。
6.2.2 功能引腳
USART共有6個功能引腳,雙向通信時至少需要2個引腳(RX和TX)。各引腳功能簡述如下:
- RX為接收數(shù)據(jù)輸入端。接收器通過過采樣技術(shù)來辨別數(shù)據(jù)和噪聲,從而恢復(fù)數(shù)據(jù)。
- TX為發(fā)送數(shù)據(jù)輸出端。當(dāng)發(fā)射器被禁用時,此引腳恢復(fù)為IO端口。當(dāng)發(fā)射器被開啟且無數(shù)據(jù)待發(fā)送時,此引腳處于高電平。在單線和智能卡模式下,此IO同時擔(dān)負(fù)發(fā)送和接收任務(wù)。
- SW_RX為單線輸入引腳,這是一個內(nèi)部引腳,在單線半雙工模式下,RX和TX同時切換到SW_RX內(nèi)部引腳。
- nCTS為停止發(fā)送(Cease To Send)引腳。該引腳為高電平時,當(dāng)前傳輸結(jié)束后會阻斷下一次數(shù)據(jù)傳輸。
- nRTS為請求發(fā)送(Request To Send)引腳。該引腳為低電平時,指示USART已經(jīng)準(zhǔn)備接收數(shù)據(jù)。
- CK為發(fā)送器時鐘輸出(Transmitter ClocK output)引腳。該引腳將發(fā)射器時鐘輸出,用于實現(xiàn)同步傳輸。時鐘的相位和極性可以通過軟件控制。在智能卡模式下,CK可為智能卡提供時鐘。
6.2.3 USART數(shù)據(jù)格式
USART通信是一種串行通信,數(shù)據(jù)以幀(Frame)為單元,按位依次發(fā)送,低位優(yōu)先。USART通信過程中共涉及3種幀結(jié)構(gòu):
- 數(shù)據(jù)幀(Data frame) 包含數(shù)據(jù)的幀。每個數(shù)據(jù)幀發(fā)送1個字節(jié)的數(shù)據(jù)(8個比特),除了數(shù)據(jù)位,每個數(shù)據(jù)幀包括1個起始位(Start bit)、1個可選校驗位(Parity bit)和0.5-2個停止位(Stop bit)。數(shù)據(jù)位和校驗位的總長度稱為字長(Word length),所以根據(jù)有無校驗位USART的可能字長為9或8。 很顯然,起始位和停止位是為了區(qū)分相繼傳遞的兩個數(shù)據(jù)的。數(shù)據(jù)幀也稱為數(shù)據(jù)包。
- 空閑幀(Idle frame) 一個全為“1”的幀??臻e幀長度包含停止位。在發(fā)送數(shù)據(jù)幀之前,USART的發(fā)送器會先發(fā)出一個空閑幀??臻e幀主要是用來同步的,如果接收端處于睡眠模式,收到空閑幀后會被喚醒,從空閑幀以后開始解析數(shù)據(jù),這是USART通信協(xié)議的一部分??臻e幀發(fā)送出去的字符稱為空閑字符。
- 斷開幀(Break frame) 一個全為“0”的幀。斷開幀包含1或2個停止位,即斷開幀是長度為10或11位的低電平。斷開幀之后發(fā)送器會插入1或2個停止位(“1”)來確認(rèn)下一幀的起始位。斷開幀也是用于同步的,是USART通信協(xié)議的一部分。斷開幀發(fā)送出去的字符稱為斷開字符。
圖2所示為9位字長和1位停止位的幀結(jié)構(gòu)和時序,8位字長時不包括Bit8。時鐘信號來自波特率發(fā)生器,一個時鐘周期發(fā)送1個bit的數(shù)據(jù)。顯然,為了正確解析信息,收發(fā)雙方必須采用相同的波特率,波特率越高數(shù)據(jù)發(fā)送速度越快。
圖2. USART的幀結(jié)構(gòu)與時序
從圖中可以看出,起始位期間TX引腳為低電平,而停止位期間PX引腳為高電平。停止位后是下一幀的起始位,依此次序按幀將數(shù)據(jù)發(fā)送到TX引腳。
發(fā)送和接收受同一個波特率發(fā)生器驅(qū)動,通過將接收器或發(fā)送器的使能位置1,來產(chǎn)生各自的時鐘。異步通信并不是不需要同步,只是通過發(fā)送同步信號和約定波特率,收發(fā)雙方可以使用各自的本地時鐘,不需要一個共同的時鐘來進(jìn)行同步。
6.2.4 發(fā)送器 (Transmitter)
根據(jù)CR1寄存器中M位的設(shè)置,發(fā)送器可以發(fā)送8位或9位字長的數(shù)據(jù)。發(fā)送使能位(CR1的TE位)被設(shè)置后,發(fā)送移位寄存器中的數(shù)據(jù)被依次輸出到TX引腳,相應(yīng)的時鐘脈沖被輸出到CK引腳。每個數(shù)據(jù)包包含一個字節(jié),低位優(yōu)先,每個字節(jié)前有一個起始位(長度為1個位周期的低電平)來作為前導(dǎo),其后用一個停止位來結(jié)尾。
1. 發(fā)送端停止位的設(shè)置
停止位的長度可以在CR2寄存器中(STOP[1:0])進(jìn)行配置,USART支持長度為0.5,1,1.5和2個周期的停止位。整數(shù)對應(yīng)正常模式,小數(shù)對應(yīng)智能卡模式。詳情如下:
- 0.5 – 用于智能卡模式接收數(shù)據(jù)
- 1 – 默認(rèn)停止位位數(shù)
- 1.5 – 用于智能卡模式收發(fā)數(shù)據(jù)
- 2 – 常規(guī)USART、單線模式、調(diào)制解調(diào)器模式
2. 發(fā)送器的配置步驟
下面來看一下常規(guī)USART模式下,發(fā)送數(shù)據(jù)的基本過程:
- 向CR1寄存器的UE(USART enable)位寫入1來使能USART;
- 設(shè)置CR1的M位來定義字長;
- 設(shè)置CR2的STOP[1:0]來配置停止位的個數(shù);
- 如果采用多緩沖器通信,設(shè)置CR3的DMAT使能DMA。按多緩沖器通信要求配置DMA寄存器;
- 設(shè)置BRR(Baud rate register)寄存器來選擇所需的波特率;
- 向CR1的TE位寫入1,使能發(fā)送器并發(fā)送一個空閑幀作為第一幀;
- 將待發(fā)送數(shù)據(jù)依次寫入DR寄存器(此操作會清除SR寄存器中的TXE位);
- 在向DR寄存器寫入最后一個數(shù)據(jù)后,等待SR寄存器中的TC位(Transfer complete)被置1。在關(guān)閉USART或進(jìn)入宕機(jī)模式時都要進(jìn)行這種檢查,以避免破壞最后一次傳輸。
數(shù)據(jù)從總線傳入,依次經(jīng)TDR和移位寄存器被發(fā)送出去。當(dāng)向DR寄存器寫入數(shù)據(jù)時,如果有數(shù)據(jù)正在傳輸,數(shù)據(jù)會被寫入TDR緩存,在當(dāng)前數(shù)據(jù)傳輸完畢,數(shù)據(jù)會被復(fù)制到移位寄存器。TDR與移位寄存器間數(shù)據(jù)是并行傳輸?shù)摹H魧懭霐?shù)據(jù)時沒有數(shù)據(jù)正在傳輸,則數(shù)據(jù)將會被直接寫入移位寄存器。數(shù)據(jù)的傳輸狀態(tài)可以通過查詢相關(guān)的寄存器來獲知。
3. 數(shù)據(jù)的發(fā)送
與發(fā)送過程密切相關(guān)的寄存器位有4個:TXE(Transmit data register empty)、TC(Transmision complete)、TXEIE(TXT interrupt enable)、TCIE(TC interrupt enable)。
- SR寄存器中的TXE位為1時,表明前一個數(shù)據(jù)已從TDR被移入移位寄存器并開始發(fā)送了,TDR寄存器已空。因此,此時向TDR寫入下一個數(shù)據(jù)已不會覆蓋前一個數(shù)據(jù)。
- 如果CR1寄存器中的TXEIE位開啟,TXE被置1時會產(chǎn)生中斷。此中斷可以用來通知軟件,將下一個數(shù)據(jù)寫入TDR。
- 在數(shù)據(jù)傳輸過程中,SR寄存器的TC位處于低電平。如果一幀數(shù)據(jù)傳輸完畢(stop bit之后)且TXE位為1,TC位變?yōu)楦唠娖剑绻鸆R1寄存器中的TCIE位開啟,則會產(chǎn)生中斷。因為數(shù)據(jù)從移位寄存器發(fā)送出去需要一定的時間,因此在將最后一個數(shù)據(jù)寫入DR寄存器后,必須等待TC=1。在此之前不可以關(guān)閉USART或讓MCU進(jìn)入低功耗模式,否則會破壞最后一個數(shù)據(jù)。顯然,開啟TCIE,在中斷回調(diào)函數(shù)中執(zhí)行后續(xù)這些操作,可以避免破壞數(shù)據(jù)。
圖3. 數(shù)據(jù)發(fā)送過程中相關(guān)寄存器的時序變化
圖3所示為數(shù)據(jù)發(fā)送過程中相關(guān)寄存器的時序變化:軟件使能USART時,TXE為高電平,第一個數(shù)據(jù)被軟件寫入DR寄存器,TEX被拉低;空閑幀發(fā)送完畢,stop bit下降沿觸發(fā)第一幀數(shù)據(jù)F1被移入移位寄存器;因DR為空,TXE被拉高,軟件檢測到TXE=1將第二幀F(xiàn)2迅速寫入DR,TEX又被拉低;重復(fù)此過程直到最后一個數(shù)據(jù)包被寫入DR;軟件開始等待TC=1;最后一個數(shù)據(jù)包被移入移位寄存器后,TXE開始持續(xù)為高電平;最后一幀發(fā)送完畢,在其stop bit下降沿因TXE=1,硬件將TC置1,傳輸過程結(jié)束。
從上述工作過程可以看出:
- 整個工作過程中,TXE和TC寄存器都是通過硬件置1,軟件置0的。軟件向DR寫入數(shù)據(jù),TXE和TC即被置0。在stop bit下降沿,TDR中的數(shù)據(jù)被移走后,TXE被硬件置1。
- 硬件在stop bit的下降沿通過檢測TXE是否為1來判斷數(shù)據(jù)傳輸是否結(jié)束。由于從TDR移走數(shù)據(jù)需要一定的時間,如果不是最后一個數(shù)據(jù),TXE的置1有所滯后。stop bit下降沿TXE仍為0,所以TC保持低電平。而最后一個數(shù)據(jù)被移入移位寄存器后,TXE即持續(xù)為高電平,它被發(fā)送完畢后,在其stop bit下降沿會檢測到TXE=1,因此硬件會將TC置1。數(shù)據(jù)發(fā)送完畢。
- 數(shù)據(jù)發(fā)送結(jié)束后,TX、TXE、TC均為高電平。
- 軟件等待TC=1的時長至少為2個數(shù)據(jù)包的發(fā)送周期,即從最后一個數(shù)據(jù)包寫入TDR開始,至TC=1結(jié)束。
空閑字符和斷開字符的發(fā)送通過軟件設(shè)置寄存器來實現(xiàn)。向CR1寄存器的SBK位寫入1,會在完成當(dāng)前傳輸后在TX發(fā)送一個斷開字符。在斷開字符的stop bit,硬件會將SBK位重置為0。USART會在最后一個斷開字符的尾部添加一個邏輯1位,來確保對下一幀start bit的正確識別。空閑字符的發(fā)送通過設(shè)置CR1寄存器的TE位實現(xiàn),發(fā)送第一個數(shù)據(jù)幀之前需要發(fā)送給一個空閑幀,來實現(xiàn)接收器的喚醒或同步。
6.2.5 接收器(Receiver)
接收器接收的數(shù)據(jù)字長可以為8位或9位,也是由CR1寄存器中M位進(jìn)行設(shè)置。異步通信模式下,收發(fā)雙方的波特率、字長、停止位必須一致。
1. 接收器的配置步驟
接收器配置過程的前5步與發(fā)送器配置過程完全一致。
- 向CR1寄存器的UE(USART enable)位寫入1來使能USART;
- 設(shè)置CR1的M位來定義字長;
- 設(shè)置CR2的STOP[1:0]來配置停止位的個數(shù);
- 如果采用多緩沖器通信,設(shè)置CR3的DMAT使能DMA。按多緩沖器通信要求配置DMA寄存器;
- 設(shè)置BRR(Baud rate register)寄存器來選擇所需的波特率;
- 向CR1寄存器的RE(Receiver enable)位寫入1,使能接收器,使其開始尋找起始位。
2. 起始位的檢測原理
如前所述,每個數(shù)據(jù)包是以起始位(低電平)開始和停止位(高電平)結(jié)束的,識別起始位是正確接收和解析數(shù)據(jù)的前提。
圖4. 起始位檢測原理
起始位的檢測原理如圖4所示。USART接收器的采樣頻率是發(fā)送器波特率的16倍(參見圖1)。自前一個包(數(shù)據(jù)幀或空閑幀)下降沿,到下一個包起始位結(jié)束,共有16次采用。為了避免噪聲干擾,從接收到下降沿開始,分別判斷此后第3、5、7和8、9、10次采用的值。如果兩組采樣全為0,則確認(rèn)找到起始位,并將SR寄存器中的RXNE(Receiver data register not empty)置1,如果開啟了RXNEIE,則會產(chǎn)生相應(yīng)的中斷;如果兩組采樣中,有非0值,但每組的3個采樣值都至少有2個為0,仍判為有效起始位(RXNE置1,如果開啟了中斷則觸發(fā)),但同時會將SR寄存器中的NE(Noise error)位置1,標(biāo)明檢測到噪聲;如果非前兩種情況,則停止檢測,接收器恢復(fù)空閑狀態(tài),繼續(xù)等待下一個下降沿。
3. 數(shù)據(jù)的接收
如圖1所示,接收數(shù)據(jù)時數(shù)據(jù)先是存入接收移位寄存器(Receive Shift Register),然后再轉(zhuǎn)入接收數(shù)據(jù)寄存器(RDR,receive data register)的,低位優(yōu)先。移位寄存器與RDR間數(shù)據(jù)是并行傳輸?shù)?。與接收過程相關(guān)的關(guān)鍵寄存器位有2個:RXNE和RXNEIE。
- SR寄存器中的RXNE位為1時,表明移位寄存器的內(nèi)容已被轉(zhuǎn)移到RDR,可以被讀取了。
- 如果CR1寄存器中的RXNEIE位開啟,RXNE被置1時會產(chǎn)生中斷。此中斷可以用來通知軟件,及時將RDR中的數(shù)據(jù)讀取。
- 在單緩存模式(非DMA)中,軟件讀取DR寄存器時會將RXNE位清0。在下一個字符接收完成之前(移位寄存器被填滿),RXNE必須被清0,否則會導(dǎo)致溢出錯誤。多緩存模式下,DMA讀取DR寄存器也會將RXNE位清0。
- 數(shù)據(jù)位的值是根據(jù)第8,9,10三個采樣點的值來確定的。詳細(xì)情況見下面的噪聲錯誤部分。
空閑字符會被當(dāng)作正常字符來接收,如果設(shè)置了IDLEIE中斷,接收到空閑字符時會觸發(fā)該中斷。斷開字符則會被當(dāng)作幀錯誤來處理。USART可以識別3種接收錯誤并根據(jù)設(shè)置觸發(fā)相應(yīng)的中斷。
4. 噪聲錯誤
為了區(qū)分有效的輸入數(shù)據(jù)和噪聲,異步USART接收器中采用了過采樣技術(shù)。RX線上的輸入電平會被以波特率的16倍進(jìn)行采樣。這樣1個數(shù)據(jù)位中會有16個采樣點。USART會用每個位中間的3次(第8,9,10次)采樣值確定數(shù)據(jù)位的電平并判斷數(shù)據(jù)是否有效。
圖5. 取樣數(shù)據(jù)的噪聲檢測
如前所述,在找到有效起始位時會設(shè)置RXNE為1,在RNXE的上升沿會同時會設(shè)置NE位。如圖5所示,如果NE為0,即起始位無噪聲時,后續(xù)各位的取樣中只有中間3次取樣值全部相同才會被判定為有效數(shù)據(jù)。如果NE=1,接收到的位的值會根據(jù)中間3次取樣的值按照少數(shù)服從多少的原則確定,并判定為無效數(shù)據(jù)。無效數(shù)據(jù)也會被從移位寄存器轉(zhuǎn)入DR寄存器。在單緩沖器通訊情況下,噪聲錯誤不會參數(shù)中斷,但由于NE和RXNE是被同時設(shè)置的,RXNE可以觸發(fā)中斷。如果需要檢查噪聲錯誤,可以在該中斷中實現(xiàn)。在多緩沖器通信情況下,如果已經(jīng)設(shè)置了CR3寄存器中的EIE(Error interrupt enable)位,將產(chǎn)生一個錯誤中斷。
通過讀取SR寄存器,接著讀取DR寄存器,可以復(fù)位NE標(biāo)志位。
5. 溢出錯誤(Overrun error)
RDR每次收到數(shù)據(jù)硬件會將RXNE置1,數(shù)據(jù)被讀取后RXNE被復(fù)位為0。如果數(shù)據(jù)沒有被及時讀?。≧XNE=1),移位寄存器被充滿后無法將數(shù)據(jù)轉(zhuǎn)移到RDR,就會觸發(fā)溢出錯誤。錯誤出現(xiàn)后:
- SR寄存器的ORE位會被置1;
- 如果開啟了RXNEIE或同時開啟了EIE和DMAR,會觸發(fā)中斷;
- 溢出錯誤期間,RDR中的數(shù)據(jù)不會被破壞,但移位寄存器中收到的數(shù)據(jù)會因被重寫而丟失;
通過讀取SR寄存器,接著讀取DR寄存器,可以復(fù)位ORE標(biāo)志位。
6. 幀錯誤
由于同步出錯或因噪聲太多,導(dǎo)致在預(yù)期的時間沒有識別到停止位,就會產(chǎn)生幀錯誤。如前所述,當(dāng)接收到斷開幀時也會當(dāng)作幀錯誤來處理。當(dāng)檢測到幀錯誤時:硬件會將SR寄存器的FE(Frame error)位置1。后續(xù)處理與噪聲錯誤類似,但字節(jié)通信時也可以在RXNE相關(guān)的中斷中進(jìn)行檢查。
通過讀取SR寄存器,接著讀取DR寄存器,可以復(fù)位FE標(biāo)志位。
7. 接收端對停止位的處理
接收端停止位設(shè)置與發(fā)送端相同,也是通過CR2寄存器中STOP[1:0]位來設(shè)置。但由于接收端是過采樣,要分情況處理:
- 0.5個停止位(智能卡接收) 因為在0.5個停止位的位置(第8和第9次采樣中間)沒有采樣,導(dǎo)致這種情況下無法檢測幀錯誤和斷開幀。
- 1個停止位 用第8,9,10個采樣點的值來確定停止位。
- 1.5個停止位(智能卡收發(fā)) 前0.5個周期不采樣,對后一個時鐘周期的中間3個取樣點取樣。如果從停止位上升沿開始計數(shù),對應(yīng)第16,17,18個采樣點。詳情查閱智能卡相關(guān)章節(jié)。
- 2個停止位 對第一個停止位的第8,9,10個采樣點采用。
6.2.6 分?jǐn)?shù)波特率的產(chǎn)生
1. 計算公式
USART的接收器和發(fā)送器的波特率是通過對外設(shè)總線的時鐘頻率分頻得到的,計算公式如下:
其中fCK為USART所在外設(shè)總線的時鐘頻率,USARTDIV為分頻系數(shù),由USART_BRR寄存器進(jìn)行設(shè)置。從上述公式可以看出,USART的最高波特率為外設(shè)總線APBx頻率的1/16,原因在于接收端要16倍過采樣來接收數(shù)據(jù),采樣頻率不可能高于APBx頻率。如圖1右下角所示,USART的接收器和發(fā)射器的波特率是通過同一個寄存器進(jìn)行配置的。為了支持分?jǐn)?shù)波特率,BRR寄存器的低16位被分成了兩部分:0-3位設(shè)置分?jǐn)?shù)部分,4-15位設(shè)置整數(shù)部分。二者共同定義分配因子USARTDIV。
根據(jù)BRR寄存器的設(shè)置,USARTDIV的計算規(guī)則如下:
- 4-15位轉(zhuǎn)為10進(jìn)制,作為整數(shù)部分。整數(shù)部分的取值范圍為0-4095;
- 0-3位轉(zhuǎn)為10進(jìn)制再除以16即為小數(shù)部分。之所以是16,是因為小數(shù)部分在寄存器中只占4位,所以能精確表示的小數(shù)只能是N/16,其中N的取值范圍為0-15。
反之,根據(jù)系統(tǒng)時鐘頻率和要求的波特率,BRR寄存器的整數(shù)和分?jǐn)?shù)部分分別按下列公式計算:
- UrtDIV = fCK/(16 baudrate)
- 整數(shù)部分:IntDIV = (u16)UrtDIV
- 分?jǐn)?shù)部分:FrcDIV = (u16)[(UrtDIV-IntDIV)*16+0.5]
例如:APB2總線頻率72MHz,要求波特率115200。計算結(jié)果:UrtDIV=39.0625,IntDIV=0d39(0x27),F(xiàn)rcDIV=0d01(0x01)。
受USARTDIV取值的限制,不是所有的波特率都可以精確的配置出來。波特率設(shè)置值與實際值之間有時會存在誤差。圖6所示即為常用波特率設(shè)置值與實際值之間的相對誤差情況。
圖6. 波特率誤差分析
對STM32F1系列芯片而言,APB1總線的最高頻率為36MHz,APB2總線的最高頻率為72MHz。除了USART1掛載在APB2總線上外,其余USART/UART均掛載與APB1總線。從圖1可以看出,常用的波特率設(shè)置115200,在36MHz情況下就會有0.15%的相對誤差。通常時鐘頻率越低,具體波特率的精度也會越低。USART1的最高波特率可達(dá)4.5M bps。
2. 接收器時鐘公差
異步通訊中,只有整個時鐘系統(tǒng)的誤差小于USART接收器容許的公差時數(shù)據(jù)才能被正確接收。誤差的主要來源包括:
- DTRA:發(fā)送端引入的誤差,例如發(fā)送端時鐘的漂移
- DQUANT:接收端波特率量化誤差
- DREC:接收端本地時鐘的漂移
- DTCL:傳輸線引入的漂移,通常來源于收發(fā)器高-低、低-高時序切換間的不同步
為保證數(shù)據(jù)能被正確接收,上述4種誤差總和必須小于USART接收器的公差。而公差又與三個因素有關(guān):字長,即CR1寄存器的M=0或1;分?jǐn)?shù)波特率,即BRR寄存器的低4位是否全為0;噪聲幀的處理,忽略還是當(dāng)作錯誤。根據(jù)這三個因素的不同,公差表分別如圖7所示:
圖7. 接收器時鐘公差
6.2.7 靜默與喚醒
通過USART可以實現(xiàn)多處理器通信。為了減少USART的服務(wù)開銷,可以讓空閑的USART進(jìn)入靜默模式(mute mode),在需要與某個USART進(jìn)行通信時,可以將其定向喚醒,而其余空閑USART不受影響。即使是兩個USART之間的通信,在無數(shù)據(jù)傳輸時雙方也可以進(jìn)入靜默模式,有數(shù)據(jù)傳輸需求時,提出需求的一方(軟件喚醒)通過發(fā)送喚醒信號,激活對方。
USART的靜默與喚醒共涉及3個寄存器功能位:CR1寄存器的WAKE和RWU、CR2的ADD[3:0]。WAKE位設(shè)置喚醒方式,根據(jù)WAKE位的不同,使USART進(jìn)入或退出靜默模式有兩種方法:空閑總線檢測(WAKE=0)和地址標(biāo)記檢測(WAKE=1)。
1. 空閑總線檢測
圖8. 空閑總線檢測靜默-喚醒示意圖
空閑總線檢測靜默-喚醒示意圖如圖8所示。當(dāng)WAKE=0時,通過向RWU(Receiver wakeup)位寫入1可使USART進(jìn)入靜默模式。進(jìn)入靜默模式后,接收器停止接收數(shù)據(jù),但仍會檢測RX引腳上的輸入信號,如果檢測到空閑幀,硬件會清除RWU,USART被喚醒開始正常接收數(shù)據(jù)(RXNE位開始變化)。
- 在靜默模式下收到的空閑幀不會觸發(fā)IDLEIE中斷,因為硬件不會設(shè)置SR寄存器中的IDLE位。
- 這種方式適合于同時需要喚醒多個USART的情形。只需發(fā)送一個空閑幀,所有WAKE=0且RWU=0的USART收到后都會被喚醒。
2. 地址標(biāo)記檢測
圖9. 地址標(biāo)記總線檢測靜默-喚醒示意圖
地址標(biāo)記檢測靜默-喚醒示意圖如圖9所示。這種模式下通常將字長設(shè)置為9,最高位(MSB)用來作為數(shù)據(jù)和地址的標(biāo)識符。當(dāng)MSB=1時,數(shù)據(jù)包被解析為地址;而當(dāng)MSB=0時,則解析為數(shù)據(jù)。地址包的低4位存儲一個地址標(biāo)記,USART收到地址包后會與CR2寄存器的ADD[3:0]中的地址進(jìn)行比較。如果地址不匹配,硬件將RWU置1,進(jìn)入/保持靜默模式,RXNE不會被設(shè)置,也不會有中斷產(chǎn)生;如果地址匹配,硬件將RWU置0,喚醒USART,在地址包中Stop bit的下降硬件會設(shè)置RXNE,后續(xù)字符會被正常接收。
- 地址包也會被接收,喚醒后收到的第一個字符是地址。
- 這種模式需要提前配置每個USART的ADD[3:0],為其分配一個地址(不一定唯一)。
- 這種方式是一種以地址包為前導(dǎo)的定向通信,通信對象更明確。每次只喚醒地址匹配的USART,如果有多個同地址的會被同時喚醒。
6.2.8 數(shù)據(jù)校驗
奇偶校驗是一種校驗代碼傳輸正確性的方法。根據(jù)被傳輸?shù)囊唤M二進(jìn)制代碼中“1”的個數(shù)是奇數(shù)還是偶數(shù)來進(jìn)行校驗。采用奇數(shù)的稱為奇校驗,反之,稱為偶校驗。校驗方式是通信雙方提前約定好的。通過在數(shù)據(jù)包中的校驗位來進(jìn)行校驗。發(fā)送方根據(jù)數(shù)據(jù)設(shè)置校驗位,接收方接收數(shù)據(jù)后對校驗位進(jìn)行檢查,從而確定傳輸代碼的正確性。
通過將CR1寄存器的PCE(Parity control enable)位置1來使能奇偶校驗,校驗方式通過PS(Parity selection)位來設(shè)置:PS=0,偶校驗;PS=1,奇校驗。
需要說明的是,如果開啟了奇偶校驗,USART的字長包含1個校驗位;如果同時開啟了地址標(biāo)記喚醒,數(shù)據(jù)位的最高位會被用作地址標(biāo)記,這種情況下實際數(shù)據(jù)的位數(shù)比所設(shè)字長會少2位。注意合理設(shè)置,防止數(shù)據(jù)被修改或誤用(比如數(shù)據(jù)包被解析為地址包)。
舉例來說:如果設(shè)置字長9位,停止位1位,同時開啟奇偶校驗和地址標(biāo)記喚醒,則最高位被校驗位占據(jù),剩余數(shù)據(jù)為的最高位會被當(dāng)作地址標(biāo)記位。實際數(shù)據(jù)占7位,設(shè)為1011011,如果選擇偶校驗,則校驗位為0。整個數(shù)據(jù)包的內(nèi)容為:10010110110,從左到右依次為停止位1、奇偶校驗位0、地址標(biāo)記0(這是數(shù)據(jù)幀)、數(shù)據(jù)位1011011、起始位0(數(shù)據(jù)傳輸?shù)臀粌?yōu)先)。
接收器收到數(shù)據(jù)后,會檢查數(shù)據(jù)位中“1”的個數(shù)是奇數(shù)還是偶數(shù),并按校驗規(guī)則與校驗位核對。如果不符表明傳輸出錯(比如噪聲干擾等),SR寄存器中的PE(Parity error)位會被置1,如果CR1中的PEIE(Parity error interrupt enable)開啟,則會產(chǎn)生中斷。
6.2.9 USART同步模式
USART可以以同步模式工作。向CR2寄存器的CLKEN(Clock enable)寫入1即可開啟同步模式。同步模式下,數(shù)據(jù)在TX引腳輸出的同時,發(fā)送器時鐘從CK引腳輸出,但在數(shù)據(jù)包的起始位和停止位CK引腳上無時鐘脈沖。
- 通過配置CR2寄存器的LBCL位,可以設(shè)置最后一個有效數(shù)據(jù)位(地址標(biāo)記)是否輸出時鐘脈沖;
- 通過CR2寄存器的CPOL(Clock polarity)可以設(shè)置時鐘的極性,即在傳輸窗口外CK引腳的電平是高(CPOL=1)還是低(CPOL=0);
- 通過CR2的CPHA位可以設(shè)置時鐘的相位,即在時鐘的第一個邊緣進(jìn)行數(shù)據(jù)捕獲(CPHA=0),還是在時鐘的第二個邊沿進(jìn)行數(shù)據(jù)捕獲(CPHA=1)。CPOL和CPHA一起配合來產(chǎn)生需要的時鐘/數(shù)據(jù)采樣關(guān)系。
發(fā)射器的運作在同步模式下和異步模式下完全相同。只是TX引腳上的數(shù)據(jù)是與CK引腳上的時鐘同步發(fā)出的。
接收器的運作在同步模式下與異步模式下不同。由于有同步時鐘,因此不需要不需要進(jìn)行過采樣。而是在RE=1使能接收器后,數(shù)據(jù)在CK的上升沿或下降沿被直接采樣。但必須重視建立時間(setup time)和保持時間(hold time)。
- 建立時間是指,采樣時鐘邊沿到來之前,數(shù)據(jù)提前保持不變的時間;保持時間是指,采樣時鐘邊沿到來之后,數(shù)據(jù)必須繼續(xù)保持不變的時間。這兩個時間與波特率有關(guān),通常要求這兩個時間不低于1/16個bit的時長。
- USART只支持主模式,即只能由它來輸出時鐘同步其他設(shè)備,而不能反過來。CK引腳永遠(yuǎn)都是輸出端。
- 同步模式下CR2寄存器的LINEN位、CR3寄存器的SCEN,HDSEL和IREN位必須清零。相關(guān)寄存器位(包括LBCL、CPOL、CPHA)的設(shè)置都必須在TE和RE使能前完成,發(fā)送器和接收器使能后不能再修改這些位,否則可能會導(dǎo)致時鐘工作不正常。
- CK和TX引腳一起運作,因此只有TE=1且數(shù)據(jù)已開始傳輸時才能提供時鐘。在發(fā)送數(shù)據(jù)前是無法向異步模式中那樣,提前發(fā)送一個數(shù)據(jù)進(jìn)行同步的。
圖10所示是USART同步通信的時序示意圖。圖示是M=1,即9位字長的情況,8位字長與此類似。
圖10. USART同步通信時序圖
從圖10可以看出,CPOL=0時,閑時電平為低電平,而CPOL=1時,閑時電平為高電平;CPHA=0時,第一個時鐘沿采樣,而CPHA=1時,第二個時鐘沿采樣。LBCL(Last bit clock)控制的是最后一個數(shù)據(jù)是否產(chǎn)生輸出時鐘脈沖。
6.2.10 單線半雙工通信
單線通信的最大好處是只占一根線,通過分時收發(fā)(半雙工)來實現(xiàn)通信。通過將CR3寄存器的HDSEL(half-duplex selection)位置1來選擇半雙工模式。在此模式下,CR2寄存器的LINKEN位、CLKEN位,CR3寄存器的SCEN和IREN位必須清零。
單線半雙工模式下,TX和RX引腳在芯片內(nèi)部被連通。HDSEL被寫入1后,RX引腳被停用;在無數(shù)據(jù)發(fā)送時,TX引腳被釋放。TX引腳在空閑或接收數(shù)據(jù)時跟一個標(biāo)準(zhǔn)的I/O口一樣。所以在不被USART驅(qū)動時,TX引腳必須配置位浮空輸入(或輸出高開漏)。除此以外,通信與正常USART模式相似。由于只有一條線路,要由軟件來負(fù)責(zé)避免出現(xiàn)線上沖突。特別需要說明的是,發(fā)送永遠(yuǎn)不會被硬件阻斷,當(dāng)TE=1時,只要有數(shù)據(jù)被寫到DR寄存器,就會被發(fā)送出去。
6.2.11 硬件流控制
圖11. 硬件流控制工作原理
所謂硬件流控制,是指通過硬件發(fā)送控制信號來控制數(shù)據(jù)流的一種方式,相當(dāng)于一種握手協(xié)議。主要是為了避免因雙方處理速度不匹配或USART網(wǎng)絡(luò)中多個發(fā)送器同時向一個接收器發(fā)送數(shù)據(jù)導(dǎo)致接收端溢出錯誤和數(shù)據(jù)丟失。硬件流控制的基本原理圖如圖11所示,在兩個USART間增加了兩條控制信號線,一個USART的nRTS連到另一個的nCTS(n表示低電平有效)。當(dāng)接收端數(shù)據(jù)處理即將完畢時,通過nRTS端口向發(fā)送端發(fā)送RTS(Request to send)請求發(fā)送信號。而發(fā)送端的nCTS端口收到信號后,將其解讀為CTS(Clear to send)允許發(fā)送信號,進(jìn)而允許發(fā)送器繼續(xù)發(fā)送數(shù)據(jù)。
RTS和CTS可以通過向CR3寄存器的RTSE(RTS enable)和CTSE(CTS enable)位寫入1來獨立開啟。
圖12. RTS流控過程
圖12所示為RTS流控過程示意圖。如前所述,接收器接收數(shù)據(jù)時,數(shù)據(jù)先通過移位寄存器接收,當(dāng)接收到Stop bit后,數(shù)據(jù)會被存入緩存RDR,RXNE=1。如果使能了RTS,在RXNE=1期間,接收器停止接收數(shù)據(jù),nRTS輸出高電平1,向發(fā)送器發(fā)出停止發(fā)送請求,發(fā)送器應(yīng)當(dāng)在當(dāng)前幀發(fā)送結(jié)束后會暫停發(fā)送,直至收到新的發(fā)送請求。
數(shù)據(jù)被從RDR讀取后,RXNE=0。如果使能了RTS,nRTS輸出低電平0,向發(fā)送器發(fā)出新的發(fā)送請求。如果數(shù)據(jù)傳輸通暢,RXNE=1的時間很短,數(shù)據(jù)幾乎是連續(xù)發(fā)送。如果發(fā)生特殊情況耽誤了RDR中數(shù)據(jù)的讀?。ū热绨l(fā)生中斷),nRTS=1,停止發(fā)送,防止丟失數(shù)據(jù)。
圖13. CTS流控過程 圖13. CTS流控過程
圖13所示為CTS流控過程示意圖。使能CTS后,發(fā)送器在發(fā)送下一幀前會檢查nCTS輸入端口的電平。如果nCTS有效(低電平)且TXE=0(TDR非空),則下一幀被發(fā)送;反之,則不會進(jìn)行發(fā)送。如果nCTS在數(shù)據(jù)發(fā)送期間失效(變?yōu)榱烁唠娖剑?,?dāng)前幀傳輸完成后會停止發(fā)送。如圖13中所示,Data2發(fā)送期間CTS失效,Data3雖已被移入TDR,但Data2發(fā)送后會停止發(fā)送,等待CTS=0再開始發(fā)送Data3。從圖13還可以看到,在Stop bit后,Data2被移入移位寄存器,TDR中有個短暫的empty期,即TXE=0的間隙。
使能CTS后,只要nCTS電平發(fā)生躍變,硬件就會自動將SR寄存器中的CTS狀態(tài)位置1。如果設(shè)置了CR3寄存器的CTSIE位,則會產(chǎn)生中斷。
6.3 USART模式配置與中斷
6.3.1 模式配置
STM32F103ZET6共有3個USART和2個UART。3個USART支持所有的模式,但2個UART只支持部分模式,而且兩個UART支持的模式也存在差別。具體配置如圖14所示。
圖14. USART模式配置
6.3.2 事件與中斷
圖15. USART相關(guān)中斷
圖15所示為USART相關(guān)中斷事件和標(biāo)志位。共有11個中斷標(biāo)志和8個相關(guān)中斷,其中前3個為發(fā)送器相關(guān)中斷,其余為接收器相關(guān)中斷。通過設(shè)置相關(guān)的控制位使能中斷。USART的所有中斷都連接到同一個中斷向量。
6.4 USART寄存器
STM32F103ZET6中與USART相關(guān)的寄存器共有7個,地址映射與復(fù)位值表如圖16所示。可以看出,這些寄存器雖然都是32bit寄存器,但功能位沒有超過16bit的。所以這些寄存器允許按半字或全字訪問。
圖16. 寄存器地址映射與復(fù)位值
6.4.1 USART_SR 狀態(tài)寄存器
USART_SR為狀態(tài)寄存器(Status Register),用以管理USART相關(guān)的狀態(tài)標(biāo)志。
位置 | 名稱 | 功能說明 |
9 | CTS | CTS flag nCTS引腳輸入電平跳變(上升/下降)時,硬件將此位置1。軟件寫入0清除。若CR3寄存器中的CTSIE=1,會觸發(fā)中斷。USART4&5無此功能。 |
8 | LBD | LIN break detection flag LIN模式下檢測到斷開幀時,硬件將此位置1。軟件寫入0清除。若CR2寄存器中的LBDIE=1,會觸發(fā)中斷。 |
7 | TXE | TDR empty TDR寄存器中的數(shù)據(jù)被移入移位寄存器后,硬件將此位置1。向TDR寫入數(shù)據(jù)會清0。若CR1寄存器中的TXEIE=1,會觸發(fā)中斷。 TXE=1,說明TDR已空,數(shù)據(jù)已轉(zhuǎn)讓發(fā)送移位寄存器,可緩存下一個待發(fā)送數(shù)據(jù)了。 注意:此位在單緩存發(fā)生時可用。不適用于DMA。 |
6 | TC | Transmission complete 數(shù)據(jù)幀傳輸完畢且TXE=1時,硬件將此位置1。軟件序列清零。也可以直接向TC寫入0來清除(僅DMA模式推薦)。若CR1寄存器中的TCIE=1,會觸發(fā)中斷。 |
5 | RXNE | RDR not empty 當(dāng)發(fā)送移位寄存器中的數(shù)據(jù)被轉(zhuǎn)入RDR時,硬件將此位置1。讀取RDR或向此位寫入0可清除(只寫法僅DMA模式推薦)。若CR1寄存器中的RXNEIE=1,會觸發(fā)中斷。 RXNE=1,說明RDR非空,接收移位寄存器中的數(shù)據(jù)被移出,可接收下一個數(shù)據(jù)了。 |
4 | IDLE | IDLE line detected 當(dāng)檢測到空閑幀時,硬件將此位置1。軟件序列清零。若CR1寄存器中的IDLEIE=1,會觸發(fā)中斷。 |
3 | ORE | Overrun error 接收移位寄存器已滿但RXNE=1(RDR非空)時,硬件將此位置1。軟件序列清零:先讀USART_SR,接著寫入USART_DR。若CR1寄存器中的RXNEIE=1,會觸發(fā)中斷。 注意:RDR中的內(nèi)容無恙,但移位寄存器中的數(shù)據(jù)被覆蓋。多緩存通信時若EIE=1,會觸發(fā)中斷。 |
2 | NE | Noise error 接收到的幀中檢測到噪聲時,硬件將此位置1。軟件序列清除。 注意:NE不會產(chǎn)生中斷,因為它與RXNE同時出現(xiàn),RXNE自己會產(chǎn)生中斷。多緩存通信時若EIE=1,NE發(fā)生會觸發(fā)中斷。 |
1 | FE | Framing error 當(dāng)檢測到同步錯誤、噪聲過多或端口字符時,硬件將此位置1。軟件序列清除。 注意:FE不會產(chǎn)生中斷,因為它與RXNE同時出現(xiàn),RXNE自己會產(chǎn)生中斷。若FE和ORE同時發(fā)生,引發(fā)錯誤的幀仍會被傳輸,只有ORE位被設(shè)置。多緩存通信時若EIE=1,F(xiàn)E發(fā)生會觸發(fā)中斷。 |
0 | PE | Parity error 當(dāng)接收端出現(xiàn)奇偶校驗錯誤時,硬件將此位置1。軟件序列清除。清零前必須等待RXNE被置1(有新數(shù)據(jù)緩存如RDR)。若CR1寄存器中的PEIE=1,會觸發(fā)中斷。 |
注:軟件序列清零是指,軟件先讀USART_SR,接著寫入USART_DR。
6.4.2 USART_DR 數(shù)據(jù)寄存器
USART_DR為數(shù)據(jù)寄存器(Data Register),用以容納接收或發(fā)送的數(shù)據(jù)。該寄存器由兩個寄存器構(gòu)成:TDR和RDR。二者均為9位,共用地址(軟件讀取時用RDR、寫入時用TDR),與配套的寄存器間并行通信。若開啟了奇偶校驗,MSB位會被校驗位取代。
6.4.3 USART_BRR 波特率寄存器
USART_BRR為波特率寄存器(Baud Rate Register),用以配置分?jǐn)?shù)波特率發(fā)生器的分頻系數(shù)USARTDIV。該寄存器共占用16位,分為兩個功能區(qū):
DIV_Mantissa[15:4]:配置USARTDIV整數(shù)部分;
DIV_Fraction[3:0]:配置USARTDIV分?jǐn)?shù)部分。
6.4.4 USART_CR1 控制寄存器1
USART_CR1為控制寄存器(Control Register)。USART共有3個控制寄存器,CR1主要用來設(shè)置收/發(fā)過程相關(guān)的參數(shù),包括字長、校驗位設(shè)置、喚醒方式、收/發(fā)器使能、靜默模式、及收/發(fā)過程相關(guān)的5個中斷。
位置 | 名稱 | 功能說明 |
13 | UE | USART enable 0: USART分頻器和輸出關(guān)閉; 1: USART開啟 。 |
12 | M | Word length 0: 停止位1,數(shù)據(jù)位 8,,停止位n (n=0.5,1,1.5,2) 1: 停止位1,數(shù)據(jù)位 9,停止位n 注意:傳輸過程中不要修改 |
11 | WAKE | Wakeup method 0: 空閑幀喚醒; 1: 地址標(biāo)記喚醒 |
10 | PCE | Parity control enable 0: 關(guān)閉奇偶校驗; 1: 開啟奇偶校驗 |
9 | PS | Parity selection 0: 偶校驗; 1: 奇校驗 |
8 | PEIE | PE interrupt enable 0: 禁用PE(奇偶校驗錯誤)中斷; 1: 開啟PE中斷 |
7 | TXEIR | TXE interrupt enable 0: 禁用TXE(TDR空)中斷; 1: 開啟TXE中斷 |
6 | TCIE | TC interrupt enable 0: 禁用TC(傳輸完成)斷; 1: 開啟TC中斷 |
5 | RXNEIE | RXNE interrupt enable 0: 禁用RXNE(RDR非空)中斷 1: 開啟RXNE中斷 |
4 | IDLEIE | IDLE interrupt enable 0: 禁用IDLE(空閑幀)中斷 1: 開啟IDLEL中斷 |
3 | TE | Transmitter enable 0: 關(guān)閉發(fā)送器;1: 使能發(fā)送器 注意:除了智能卡模式,若在傳輸過程中TE位上有0脈沖,會在當(dāng)前幀傳輸結(jié)束發(fā)送一個前導(dǎo)符(空閑幀);TE設(shè)1后要延遲1個bit才開始傳輸。 |
2 | RE | Receiver enable 0: 關(guān)閉接收器;1: 使能接收器,并開始查找起始位 |
1 | RWU | Receiver wakeup 0: 退出靜默模式;1: 進(jìn)入靜默模式 |
0 | SBK | Send break 該位寫入1會發(fā)生一個斷開符。 |
6.4.5 USART_CR2 控制寄存器2
CR2主要用來設(shè)置CK引腳的同步時鐘、LIN模式、停止位以及USART地址。
位置 | 名稱 | 功能說明 |
14 | LINEN | LIN mode enable 0: 關(guān)閉LIN模式; 1: 開啟LIN模式 |
13:12 | STOP | STOP bits 00: 1; 01: 0.5; 10: 2; 11: 1.5; UART4 & 5 不支持0.5和1.5個停止位 |
11 | CLKEN | Clock enable 0: 停止CK時鐘輸出; 1: 使能CK時鐘輸出 |
10 | CPOL | Clock pority 0: 閑時低電平; 1: 閑時高電平 UART4 & 5 不支持 |
9 | CPHA | Clock phase 0: 第1個始終沿捕獲數(shù)據(jù); 1:第2個時鐘沿捕獲數(shù)據(jù) UART4 & 5 不支持 |
8 | LBCL | Last bit clock pulse 0: Last bit不輸出時鐘脈沖; 1:輸出 UART4 & 5 不支持 |
6 | LBDIE | LIN break detection interrupt enable 0: 禁止LIN斷開幀中的; 1: 開啟 |
5 | LBDL | LIN break detection length 0: 10bit斷開符檢測; 1:11位斷開符檢測 |
3:0 | ADD | USART address 為USART分配地址。此位在多處理器通信時用于通過地址標(biāo)記定向喚醒。 |
注意:CPOL,CPHA,LBCL在傳輸過程中禁止修改。
6.4.6 USART_CR3 控制寄存器3
CR3主要用來設(shè)置硬件流控制、DMA收發(fā)、智能卡和IrDA模式,以及FE/ORE/NE錯誤中斷。
位置 | 名稱 | 功能說明 |
10 | CTSIE | CTS interrupt enable 1: 使能CTS中斷; UART4 & 5 不支持 |
9 | CTSE | CTS enable 1: 使能CTS硬件流控制; UART4 & 5 不支持 |
8 | RTSE | RTS enable 1: 使能RTS硬件流控制; UART4 & 5 不支持 |
7 | DMAT | DMA enable transmitter 1: 使能DMA模式發(fā)送; UART4 & 5 不支持 |
6 | DMAR | DMA enable receiver 1: 使能DMA模式接收; UART4 & 5 不支持 |
5 | SCEN | Smartcard mode enable 1: 使能智能卡模式; UART4 & 5 不支持 |
4 | NACK | Smartcard NACK enable 1: 出現(xiàn)奇偶校驗錯誤時使能NACK; UART4 & 5 不支持 |
3 | HDSEL | Half-duplex selection 1: 選擇半雙工模式 |
2 | IRLP | IrDA low-power 0: 正常模式;1: 低功耗模式 |
1 | IREN | IrDA mode enable 1: 使能IrDA紅外模式 |
0 | EIE | Error interrupt enable 1: 多緩沖區(qū)模式下,使能FE、ORE、NE中斷 |
6.4.7 USART_GTPR保護(hù)時間和預(yù)分頻寄存器
USART_GTPR為保護(hù)時間和預(yù)分頻寄存器(Guard Time and Prescaler Register)。該寄存器共占16位,分為兩個功能區(qū):
GT[15:8]:用于設(shè)置智能卡模式下的保護(hù)時間,單位為波特率時鐘個數(shù),保護(hù)時間過后才會設(shè)置TC標(biāo)志位。
PSC[7:0]:用于設(shè)置智能卡和IrDA低功耗模式下的波特率預(yù)分頻系數(shù)。IrDA低功耗模式下,
6.5 USART功能設(shè)置
初始化USART的基本步驟如下:
6.5.1 寄存器操作
為了便于寄存器操作,頭文件stm32f10x.h中定義了與USART寄存器相關(guān)的宏,對地址進(jìn)行了映射。以USART1為例,相關(guān)宏定義和地址映射如下:
#define PERIPH_BASE ((uint32_t)0x40000000)#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)#define ADC3_BASE (APB2PERIPH_BASE + 0x3C00)#define USART1 (USART_TypeDef *) USART1_BASE)typedef struct{ __IO uint16_t SR; uint16_t RESERVED0; __IO uint16_t DR; uint16_t RESERVED1; __IO uint16_t BRR; uint16_t RESERVED2; __IO uint16_t CR1; uint16_t RESERVED3; __IO uint16_t CR2; uint16_t RESERVED4; __IO uint16_t CR3; uint16_t RESERVED5; __IO uint16_t GTPR; uint16_t RESERVED6;} USART_TypeDef;
通過上述宏名稱,可以對USART相關(guān)寄存器中的功能位進(jìn)行設(shè)置。
//波特率115200,數(shù)據(jù)位8,停止位1,RX+TX,無奇偶校驗,無硬件流控usart1_int(void){uint32_t temp/* 1 使能時鐘 */RCC->APB2EN |= 0x00004004;//使能GPIOA和USART1的時鐘/* 2 配置引腳 */temp = GPIOA->CRH;temp &= 0xFFFFF00F; //resettemp |= 0x000004B0; //PA9:50MHz,復(fù)用推挽;PA10:浮空輸入GPIOA->CRH = temp;/* 3 配置USART參數(shù) */USART1->BRR = 0x2701; //72MHz,115200 =>39.0625temp = USART1->CR1;temp &= 0xFFFFE9F3;//Clear M/PCE/PS/TE/REtemp |= 0x000C;//數(shù)據(jù)位8、無奇偶校驗、收發(fā)均開啟USART1->CR1 = temp;USART1->CR2 &= 0xFFFFCFFF;//停止位1USART1->CR2 &= 0xFFFFCFFF;//硬件流控制nCTS,nRTS均不開啟/* 4 配置USART中斷 */ 待補(bǔ)充2021.9.7/* 5 使能USART */USART1->CR1 |= 0x01<<13; }
6.5.2 標(biāo)準(zhǔn)庫相關(guān)函數(shù)
標(biāo)準(zhǔn)庫中USART相關(guān)的庫函數(shù)共29個,在stm32f10x_usart.h中聲明,stm32f10x_usart.c中定義。按函數(shù)功能大體分類,簡述如下:
1. 初始化函數(shù)
- USART_DeInit(); 復(fù)位USART外設(shè)總線時鐘。該函數(shù)實際訪問的是RCC_APBxRSTR寄存器,先ENABLE接著DISABLE(為何要多此一舉?)。
- USART_StructInit(); USART_Init( ); 這個兩個函數(shù)用來初始化USART參數(shù)??梢韵扔肬SART_StructInit()用默認(rèn)參數(shù)初始化一個USART_InitTypeDef結(jié)構(gòu)體。默認(rèn)參數(shù)為:波特率9600,字長8bit,停止位1,奇偶校驗none,模式RX+TX,硬件流控None。執(zhí)行此函數(shù)后,修改必要參數(shù),再調(diào)用USART_Init()完成初始化。不用USART_StructInit(),需要逐字段輸入。
typedef struct{ uint32_t USART_BaudRate; uint16_t USART_WordLength; uint16_t USART_StopBits; uint16_t USART_Parity; uint16_t USART_Mode; uint16_t USART_HardwareFlowControl;} USART_InitTypeDef;USART_StructInit(){ /* USART_InitStruct members default value */ USART_InitStruct->USART_BaudRate = 9600; USART_InitStruct->USART_WordLength = USART_WordLength_8b; USART_InitStruct->USART_StopBits = USART_StopBits_1; USART_InitStruct->USART_Parity = USART_Parity_No ; USART_InitStruct->USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_InitStruct->USART_HardwareFlowControl = USART_HardwareFlowControl_None; }
USART_Init()中設(shè)置的是CR1-3和BRR寄存器。波特率設(shè)置時,總線時鐘是根據(jù)時鐘系統(tǒng)設(shè)置進(jìn)行計算,進(jìn)而計算和設(shè)置BRR的整數(shù)和分?jǐn)?shù)功能區(qū)的值。
- USART_ClockStructInit(); USART_ClockInit(); 與前述兩個函數(shù)類似。這兩個函數(shù)用來初始化CK引腳的時鐘??上日{(diào)用USART_ClockStructInit(),生成一個用默認(rèn)參數(shù)初始化的USART_ClockInitTypeDef結(jié)構(gòu)體,進(jìn)行必要修改后傳個USART_ClockInit()完成初始化。默認(rèn)參數(shù)為:CK時鐘關(guān)閉,極性low,相位第1邊沿,最后bit無時鐘脈沖。
typedef struct{ uint16_t USART_Clock; uint16_t USART_CPOL; uint16_t USART_CPHA; uint16_t USART_LastBit;} USART_ClockInitTypeDef;USART_ClockStructInit(USART_ClockInitTypeDef* USART_ClockInitStruct){ /* USART_ClockInitStruct members default value */ USART_ClockInitStruct->USART_Clock = USART_Clock_Disable; USART_ClockInitStruct->USART_CPOL = USART_CPOL_Low; USART_ClockInitStruct->USART_CPHA = USART_CPHA_1Edge; USART_ClockInitStruct->USART_LastBit = USART_LastBit_Disable;}
2. 功能管理
- USART_Cmd(); 使能/禁用USART。設(shè)置CR1寄存器的UE位。
- USART_SetAddress(); 為USART分配地址。設(shè)置CR2寄存器的ADD[3:0]位。
- USART_WakeUpConfig(); 設(shè)置USART喚醒模式。設(shè)置CR1寄存器的WAKE位。
- USART_ReceiverWakeUpCmd(); 使能/禁用靜默模式。設(shè)置CR1寄存器的RWU位。
- USART_DMACmd(); 使能/禁用DMA接收/發(fā)送。設(shè)置CR3寄存器的DMAR或DMAT位。
- USART_HalfDuplexCmd(); 使能/禁用半雙工模式。設(shè)置CR3的HDSEL位。
- USART_OverSampling8Cmd(); 接收器一般都是16倍過采樣。只有STM32F100xx系列支持8倍過采樣,因為該系列最高頻率只有24MHz,降低過采樣可以提高波特率。
- USART_OneBitMethodCmd(); 只有低端芯片才支持的功能。
3. 接收和發(fā)送函數(shù)
- USART_SendData(); 發(fā)送數(shù)據(jù),即將數(shù)據(jù)寫入DR寄存器。雖然輸入的Data為16位,但只有低9位有效。這個函數(shù)核心代碼只有一行,這也是寄存器操作發(fā)送數(shù)據(jù)的典型代碼:
USARTx->DR = (Data & (uint16_t)0x01FF); //取低9位
- USART_ReceiveData(); 接收數(shù)據(jù),即將數(shù)據(jù)從DR寄存器返回。與SendData函數(shù)類似,該函數(shù)只取DR的低9位。
return (uint16_t)(USARTx->DR & (uint16_t)0x01FF);
4. 中斷管理函數(shù)
- USART_ITConfig(); 配置USART中斷。設(shè)置寄存器中與中斷相關(guān)的8個位(前8個)。
// 所有11個中斷別名#define USART_IT_PE ((uint16_t)0x0028)#define USART_IT_TXE ((uint16_t)0x0727)#define USART_IT_TC ((uint16_t)0x0626)#define USART_IT_RXNE ((uint16_t)0x0525)#define USART_IT_IDLE ((uint16_t)0x0424)#define USART_IT_LBD ((uint16_t)0x0846)#define USART_IT_CTS ((uint16_t)0x096A)#define USART_IT_ERR ((uint16_t)0x0060)#define USART_IT_ORE ((uint16_t)0x0360)#define USART_IT_NE ((uint16_t)0x0260)#define USART_IT_FE ((uint16_t)0x0160)
- USART_GetITStatus(); 可分別查詢10個中斷(除了ERR)相關(guān)位的值,借以判別中斷狀態(tài)。
- USART_ClearITPendingBit(); 該函數(shù)用于清除CTS/LBD/TC/RXNE中斷的中斷狀態(tài)位。其他中斷狀態(tài)位的清除方法:
- TXEIE – 讀DR寄存器可清除。
- PEIE/FE/NE/ORE/IDLEIE中斷狀態(tài)位需要軟件序列清除:先用USART_GetITStatus()讀SR寄存器,接著用USART_ReceiveData()讀DR寄存器。
- TC中斷狀態(tài)位需要軟件序列清除:先用USART_GetITStatus()讀SR寄存器,接著用USART_SendData()寫DR寄存器。
- USART_GetFlagStatus(); 功能同USART_GetITStatus。
- USART_ClearFlag(); 功能同USART_ClearITPendingBit。
5. LIN模式相關(guān)函數(shù)
- USART_LINCmd(); 使能/禁用LIN模式。設(shè)置CR2寄存器的LINEN位。
- USART_LINBreakDetectLengthConfig(); 配置LIN模式下斷開符檢測時的幀長度,10或11bit。設(shè)置CR2寄存器的LBDL位。
- USART_SendBreak(); 向USARTx發(fā)送一個斷開符。設(shè)置CR1寄存器的SBK位。
6. SmartCard模式相關(guān)函數(shù)
- USART_SmartCardCmd(); 使能或禁用智能卡模式。設(shè)置CR3寄存器的SCEN位。
- USART_SetGuardTime(); 設(shè)置智能卡保護(hù)時間,GTPR寄存器的高8位GT[15:8]。
- USART_SetPrescaler(); 設(shè)置智能卡分頻系數(shù),GTPR寄存器的低8位PSC[7:0]。
- USART_SmartCardNACKCmd(); 使能/禁用NACK傳輸。設(shè)置CR3寄存器的NACK位。
7. IrDA紅外模式相關(guān)函數(shù)
- USART_IrDAConfig(); 配置紅外模式。設(shè)置CR3寄存器的IRLP位。
- USART_IrDACmd(); 使能/退出紅外模式。設(shè)置CR3寄存器的IREN位。
6.5.3 HAL庫相關(guān)函數(shù)
HAL庫中USART相關(guān)的常規(guī)庫函數(shù)有40多個,還有多個宏函數(shù),在stm32f1xx_hal_usart.h中聲明,stm32f1xx_hal_usart.c中定義。只是比STD庫多了些函數(shù),換了個名稱,功能分的更細(xì)一些而已。歸根結(jié)底,也是設(shè)置的各個寄存器。僅將函數(shù)名稱羅列如下,大多可以從名稱看出功能。
/* 宏函數(shù) _HANDLE_是外設(shè)參數(shù)對應(yīng)的結(jié)構(gòu)體,HAL庫中稱為外設(shè)句柄 */__HAL_UART_RESET_HANDLE_STATE()__HAL_UART_FLUSH_DRREGISTER()__HAL_UART_GET_FLAG()__HAL_UART_CLEAR_FLAG()__HAL_UART_CLEAR_PEFLAG()__HAL_UART_CLEAR_FEFLAG()__HAL_UART_CLEAR_NEFLAG()__HAL_UART_CLEAR_OREFLAG()__HAL_UART_CLEAR_IDLEFLAG()__HAL_UART_ENABLE_IT()__HAL_UART_DISABLE_IT()__HAL_UART_GET_IT_SOURCE()__HAL_UART_HWCONTROL_CTS_ENABLE()__HAL_UART_HWCONTROL_CTS_DISABLE()__HAL_UART_HWCONTROL_RTS_ENABLE()__HAL_UART_HWCONTROL_RTS_DISABLE()__HAL_UART_ENABLE()__HAL_UART_DISABLE()/* Initialization/de-initialization functions **/HAL_UART_Init();HAL_HalfDuplex_Init();HAL_LIN_Init();HAL_MultiProcessor_Init();HAL_UART_DeInit();HAL_UART_MspInit();HAL_UART_MspDeInit();/* IO operation functions **/HAL_UART_Transmit();HAL_UART_Receive();HAL_UART_Transmit_IT();HAL_UART_Receive_IT();HAL_UART_Transmit_DMA();HAL_UART_Receive_DMA();HAL_UART_DMAPause();HAL_UART_DMAResume();HAL_UART_DMAStop();HAL_UARTEx_ReceiveToIdle();HAL_UARTEx_ReceiveToIdle_IT();HAL_UARTEx_ReceiveToIdle_DMA();/* Transfer Abort functions */HAL_UART_Abort();HAL_UART_AbortTransmit();HAL_UART_AbortReceive();HAL_UART_Abort_IT();HAL_UART_AbortTransmit_IT();HAL_UART_AbortReceive_IT();/* 中斷與回調(diào)函數(shù) */HAL_UART_IRQHandler();HAL_UART_TxCpltCallback();HAL_UART_TxHalfCpltCallback();HAL_UART_RxCpltCallback();HAL_UART_RxHalfCpltCallback();HAL_UART_ErrorCallback();HAL_UART_AbortCpltCallback();HAL_UART_AbortTransmitCpltCallback();HAL_UART_AbortReceiveCpltCallback();HAL_UARTEx_RxEventCallback();/* Peripheral Control functions **/HAL_LIN_SendBreak();HAL_MultiProcessor_EnterMuteMode();HAL_MultiProcessor_ExitMuteMode();HAL_HalfDuplex_EnableTransmitter();HAL_HalfDuplex_EnableReceiver();/* Peripheral State functions **/HAL_UART_GetState();HAL_UART_GetError();
typedef enum{ HAL_OK = 0x00U, HAL_ERROR = 0x01U, HAL_BUSY = 0x02U, HAL_TIMEOUT = 0x03U} HAL_StatusTypeDef;
HAL庫中將外設(shè)所有的參數(shù)和回調(diào)函數(shù)整合到一個結(jié)構(gòu)體之中,稱為外設(shè)的句柄,命名規(guī)則PPPP_HandleTypeDef。具體到USART,UART_HandleTypeDef的定義如下:
/* UART handle Structure definition */typedef struct __UART_HandleTypeDef{ USART_TypeDef *Instance; /*!< UART registers base address */ UART_InitTypeDef Init; /*!< UART communication parameters */ uint8_t *pTxBuffPtr; /*!< Pointer to UART Tx transfer Buffer */ uint16_t TxXferSize; /*!< UART Tx Transfer size */ __IO uint16_t TxXferCount; /*!< UART Tx Transfer Counter */ uint8_t *pRxBuffPtr; /*!< Pointer to UART Rx transfer Buffer */ uint16_t RxXferSize; /*!< UART Rx Transfer size */ __IO uint16_t RxXferCount; /*!< UART Rx Transfer Counter */ __IO HAL_UART_RxTypeTypeDef ReceptionType; /*!< Type of ongoing reception */ DMA_HandleTypeDef *hdmatx; /*!< UART Tx DMA Handle parameters */ DMA_HandleTypeDef *hdmarx; /*!< UART Rx DMA Handle parameters */ HAL_LockTypeDef Lock; /*!< Locking object */ __IO HAL_UART_StateTypeDef gState; /*!< UART state information related to global Handle management and also related to Tx operations. This parameter can be a value of @ref HAL_UART_StateTypeDef */ __IO HAL_UART_StateTypeDef RxState; /*!< UART state information related to Rx operations. This parameter can be a value of @ref HAL_UART_StateTypeDef */ __IO uint32_t ErrorCode; /*!< UART Error code */#if (USE_HAL_UART_REGISTER_CALLBACKS == 1) (* TxHalfCpltCallback)(struct __); /*!< UART Tx Half Complete Callback */ (* TxCpltCallback)(struct __); /*!< UART Tx Complete Callback */ (* RxHalfCpltCallback)(struct __); /*!< UART Rx Half Complete Callback */ (* RxCpltCallback)(struct __); /*!< UART Rx Complete Callback */ (* ErrorCallback)(struct __); /*!< UART Error Callback */ (* AbortCpltCallback)(struct __); /*!< UART Abort Complete Callback */ (* AbortTransmitCpltCallback)(struct __); /*!< UART Abort Transmit Complete Callback */ (* AbortReceiveCpltCallback)(struct __); /*!< UART Abort Receive Complete Callback */ (* WakeupCallback)(struct __); /*!< UART Wakeup Callback */ (* RxEventCallback)(struct __, uint16_t Pos); /*!< UART Reception Event Callback */ (* MspInitCallback)(struct __); /*!< UART Msp Init callback */ (* MspDeInitCallback)(struct __); /*!< UART Msp DeInit callback */#endif /* USE_HAL_UART_REGISTER_CALLBACKS */} UART_HandleTypeDef;
有些屬性本身有是一個結(jié)構(gòu)體。句柄的概念與MATLAB中的handle非常像。通過一個句柄可以管理外設(shè)對象的所有屬性。
USART在STM32CubeIDE中的配置過程如下面幾幅圖所示
TODO:LIN模式、智能卡模式、IrDA模式暫時不深究,用到時再學(xué)習(xí);USART利用DMA連續(xù)通信,留待學(xué)習(xí)DMA時一并學(xué)習(xí)。