串列埠通訊協議
串列埠通訊協議
2018年03月02日 10:02:47 guankaer 閱讀數:3199更多 個人分類: 微控制器文章轉載自http://www.cnblogs.com/firege/p/5805753.html
20.1 串列埠通訊協議簡介
串列埠通訊(Serial Communication)是一種裝置間非常常用的序列通訊方式,因為它簡單便捷,大部分電子裝置都支援該通訊方式,電子工程師在除錯裝置時也經常使用該通訊方式輸出除錯資訊。
在計算機科學裡,大部分複雜的問題都可以通過分層來簡化。如晶片被分為核心層和片上外設;STM32標準庫則是在暫存器與使用者程式碼之間的軟體層。對於通訊協議,我們也以分層的方式來理解,最基本的是把它分為物理層和協議層。物理層規定通訊系統中具有機械、電子功能部分的特性,確保原始資料在物理媒體的傳輸。協議層主要規定通訊邏輯,統一收發雙方的資料打包、解包標準。簡單來說物理層規定我們用嘴巴還是用肢體來交流,協議層則規定我們用中文還是英文來交流。
下面我們分別對串列埠通訊協議的物理層及協議層進行講解。
20.1.1 物理層
串列埠通訊的物理層有很多標準及變種,我們主要講解RS-232標準,RS-232標準主要規定了訊號的用途、通訊介面以及訊號的電平標準。
使用RS-232標準的串列埠裝置間常見的通訊結構見圖 201。
圖 201 串列埠通訊結構圖
在上面的通訊方式中,兩個通訊裝置的"DB9介面"之間通過串列埠訊號線建立起連線,串列埠訊號線中使用"RS-232標準"傳輸資料訊號。由於RS-232電平標準的訊號不能直接被控制器直接識別,所以這些訊號會經過一個"電平轉換晶片"轉換成控制器能識別的"TTL校準"的電平訊號,才能實現通訊。
1. 電平標準
根據通訊使用的電平標準不同,串列埠通訊可分為TTL標準及RS-232標準,見表 201。
表 201 TTL電平標準與RS232電平標準
通訊標準 |
電平標準(傳送端) |
5V TTL |
邏輯1:2.4V-5V 邏輯0:0~0.5V |
RS-232 |
邏輯1:-15V~-3V 邏輯0:+3V~+15V |
我們知道常見的電子電路中常使用TTL的電平標準,理想狀態下,使用5V表示二進位制邏輯1,使用0V表示邏輯0;而為了增加串列埠通訊的遠距離傳輸及抗干擾能力,它使用-15V表示邏輯1,+15V表示邏輯0。使用RS232與TTL電平校準表示同一個訊號時的對比見圖 202。
圖 202 RS-232與TTL電平標準下表示同一個訊號
因為控制器一般使用TTL電平標準,所以常常會使用MA3232晶片對TTL及RS-232電平的訊號進行互相轉換。
2. RS-232訊號線
在最初的應用中,RS-232串列埠標準常用於計算機、路由與調製調解器(MODEN,俗稱"貓")之間的通訊 ,在這種通訊系統中,裝置被分為資料終端裝置DTE(計算機、路由)和資料通訊裝置DCE(調製調解器)。我們以這種通訊模型講解它們的訊號線連線方式及各個訊號線的作用。
在舊式的臺式計算機中一般會有RS-232標準的COM口(也稱DB9介面),見圖 203。
圖 203 電腦主機板上的COM口及串列埠線
其中接線口以針式引出訊號線的稱為公頭,以孔式引出訊號線的稱為母頭。在計算機中一般引出公頭介面,而在調製調解器裝置中引出的一般為母頭,使用上圖中的串列埠線即可把它與計算機連線起來。通訊時,串列埠線中傳輸的訊號就是使用前面講解的RS-232標準調製的。
在這種應用場合下,DB9介面中的公頭及母頭的各個引腳的標準訊號線接法見圖 204及表 202。
圖 204 DB9標準的公頭及母頭接法
表 202 DB9訊號線說明(公頭,為方便理解,可把DTE理解為計算機,DCE理解為調製調解器)
序號 |
名稱 |
符號 |
資料方向 |
說明 |
1 |
載波檢測 |
DCD |
DTEàDCE |
Data Carrier Detect,資料載波檢測,用於DTE告知對方,本機是否收到對方的載波訊號 |
2 |
接收資料 |
RXD |
DTEßDCE |
Receive Data,資料接收訊號,即輸入。 |
3 |
傳送資料 |
TXD |
DTEàDCE |
Transmit Data,資料傳送訊號,即輸出。兩個裝置之間的TXD與RXD應交叉相連 |
4 |
資料終端(DTE) 就緒 |
DTR |
DTEàDCE |
Data Terminal Ready,資料終端就緒,用於DTE向對方告知本機是否已準備好 |
5 |
訊號地 |
GND |
- |
地線,兩個通訊裝置之間的地電位可能不一樣,這會影響收發雙方的電平訊號,所以兩個串列埠裝置之間必須要使用地線連線,即共地。 |
6 |
資料裝置(DCE)就緒 |
DSR |
DTEßDCE |
Data Set Ready,資料傳送就緒,用於DCE告知對方本機是否處於待命狀態 |
7 |
請求傳送 |
RTS |
DTEàDCE |
Request To Send,請求傳送, DTE 請求 DCE 本裝置向DCE端傳送資料 |
8 |
允許傳送 |
CTS |
DTEßDCE |
Clear To Send,允許傳送,DCE迴應對方的RTS傳送請求,告知對方是否可以傳送資料 |
9 |
響鈴指示 |
RI |
DTEßDCE |
Ring Indicator,響鈴指示,表示DCE端與線路已接通 |
上表中的是計算機端的DB9公頭標準接法,由於兩個通訊裝置之間的收發訊號(RXD與TXD)應交叉相連,所以調製調解器端的DB9母頭的收發訊號接法一般與公頭的相反,兩個裝置之間連線時,只要使用"直通型"的串列埠線連線起來即可,見圖 205。
圖 205 計算機與調製調解器的訊號線連線
串列埠線中的RTS、CTS、DSR、DTR及DCD訊號,使用邏輯 1表示訊號有效,邏輯0表示訊號無效。例如,當計算機端控制DTR訊號線表示為邏輯1時,它是為了告知遠端的調製調解器,本機已準備好接收資料,0則表示還沒準備就緒。
在目前的其它工業控制使用的串列埠通訊中,一般只使用RXD、TXD以及GND三條訊號線,直接傳輸資料訊號。而RTS、CTS、DSR、DTR及DCD訊號都被裁剪掉了,如果您在前面被這些訊號弄得暈頭轉向,那就直接忽略它們吧。
20.1.2 協議層
串列埠通訊的資料包由傳送裝置通過自身的TXD介面傳輸到接收裝置的RXD介面。在串列埠通訊的協議層中,規定了資料包的內容,它由啟始位、主體資料、校驗位以及停止位組成,通訊雙方的資料包格式要約定一致才能正常收發資料,其組成見圖 206。
圖 206 串列埠資料包的基本組成
1. 波特率
本章中主要講解的是串列埠非同步通訊,非同步通訊中由於沒有時鐘訊號(如前面講解的DB9介面中是沒有時鐘訊號的),所以兩個通訊裝置之間需要約定好波特率,即每個碼元的長度,以便對訊號進行解碼,圖 206中用虛線分開的每一格就是代表一個碼元。常見的波特率為4800、9600、115200等。
2. 通訊的起始和停止訊號
串列埠通訊的一個數據包從起始訊號開始,直到停止訊號結束。資料包的起始訊號由一個邏輯0的資料位表示,而資料包的停止訊號可由0.5、1、1.5或2個邏輯1的資料位表示,只要雙方約定一致即可。
3. 有效資料
在資料包的起始位之後緊接著的就是要傳輸的主體資料內容,也稱為有效資料,有效資料的長度常被約定為5、6、7或8位長。
4. 資料校驗
在有效資料之後,有一個可選的資料校驗位。由於資料通訊相對更容易受到外部干擾導致傳輸資料出現偏差,可以在傳輸過程加上校驗位來解決這個問題。校驗方法有奇校驗(odd)、偶校驗(even)、0校驗(space)、1校驗(mark)以及無校驗(noparity),它們介紹如下:
奇校驗要求有效資料和校驗位中"1"的個數為奇數,比如一個8位長的有效資料為:01101001,此時總共有4個"1",為達到奇校驗效果,校驗位為"1",最後傳輸的資料將是8位的有效資料加上1位的校驗位總共9位。
偶校驗與奇校驗要求剛好相反,要求幀資料和校驗位中"1"的個數為偶數,比如資料幀:11001010,此時資料幀"1"的個數為4個,所以偶校驗位為"0"。
0校驗是不管有效資料中的內容是什麼,校驗位總為"0",1校驗是校驗位總為"1"。
在無校驗的情況下,資料包中不包含校驗位。
20.2 STM32的USART簡介
STM32晶片具有多個USART外設用於串列埠通訊,它是 Universal Synchronous Asynchronous Receiver and Transmitter的縮寫,即通用同步非同步收發器可以靈活地與外部裝置進行全雙工資料交換。有別於USART,它還有具有UART外設(Universal Asynchronous Receiver and Transmitter),它是在USART基礎上裁剪掉了同步通訊功能,只有非同步通訊。簡單區分同步和非同步就是看通訊時需不需要對外提供時鐘輸出,我們平時用的串列埠通訊基本都是UART。
USART滿足外部裝置對工業標準NRZ非同步序列資料格式的要求,並且使用了小數波特率發生器,可以提供多種波特率,使得它的應用更加廣泛。USART支援同步單向通訊和半雙工單線通訊;還支援局域互連網路LIN、智慧卡(SmartCard)協議與lrDA(紅外線資料協會) SIR ENDEC規範。
USART支援使用DMA,可實現高速資料通訊,有關DMA具體應用將在DMA章節作具體講解。
USART在STM32應用最多莫過於"列印"程式資訊,一般在硬體設計時都會預留一個USART通訊介面連線電腦,用於在除錯程式是可以把一些除錯資訊"列印"在電腦端的串列埠除錯助手工具上,從而瞭解程式執行是否正確、指出執行出錯位置等等。
STM32的USART輸出的是TTL電平訊號,若需要RS-232標準的訊號可使用MAX3232晶片進行轉換。
20.3 USART功能框圖
STM32的USART功能框圖包含了USART最核心內容,掌握了功能框圖,對USART就有一個整體的把握,在程式設計時就思路就非常清晰,見圖 207。
圖 207 USART功能框圖
1. ①功能引腳
TX:傳送資料輸出引腳。
RX:接收資料輸入引腳。
SW_RX:資料接收引腳,只用於單線和智慧卡模式,屬於內部引腳,沒有具體外部引腳。
nRTS:請求以傳送(Request To Send),n表示低電平有效。如果使能RTS流控制,當USART接收器準備好接收新資料時就會將nRTS變成低電平;當接收暫存器已滿時,nRTS將被設定為高電平。該引腳只適用於硬體流控制。
nCTS:清除以傳送(Clear To Send),n表示低電平有效。如果使能CTS流控制,傳送器在傳送下一幀資料之前會檢測nCTS引腳,如果為低電平,表示可以傳送資料,如果為高電平則在傳送完當前資料幀之後停止傳送。該引腳只適用於硬體流控制。
SCLK:傳送器時鐘輸出引腳。這個引腳僅適用於同步模式。
USART引腳在STM32F429IGT6晶片具體釋出見表 203。
表 203 STM32F429IGT6晶片的USART引腳
|
APB2(最高90MHz) |
APB1(最高45MHz) |
||||||
USART1 |
USART6 |
USART2 |
USART3 |
UART4 |
UART5 |
UART7 |
UART8 |
|
TX |
PA9/PB6 |
PC6/PG14 |
PA2/PD5 |
PB10/PD8 |
PA0/PC10 |
PC12 |
PF7/PE8 |
PE1 |
RX |
PA10/PB7 |
PC7/PG9 |
PA3/PD6 |
PB11/PD9 |
PA1/PC11 |
PD2 |
PF6/PE7 |
PE0 |
SCLK |
PA8 |
PG7/PC8 |
PA4/PD7 |
PB12/PD10 |
|
|
|
|
nCTS |
PA11 |
PG13/PG15 |
PA0/PD3 |
PB13/PD11 |
|
|
|
|
nRTS |
PA12 |
PG8/PG12 |
PA1/PD4 |
PB14/PD12 |
|
|
|
|
STM32F42xxx系統控制器有四個USART和四個UART,其中USART1和USART6的時鐘來源於APB2匯流排時鐘,其最大頻率為90MHz,其他六個的時鐘來源於APB1匯流排時鐘,其最大頻率為45MHz。
UART只是非同步傳輸功能,所以沒有SCLK、nCTS和nRTS功能引腳。
觀察表 203可發現很多USART的功能引腳有多個引腳可選,這非常方便硬體設計,只要在程式程式設計時軟體繫結引腳即可。
2. ②資料暫存器
USART資料暫存器(USART_DR)只有低9位有效,並且第9位資料是否有效要取決於USART控制暫存器1(USART_CR1)的M位設定,當M位為0時表示8位資料字長,當M位為1表示9位資料字長,我們一般使用8位資料字長。
USART_DR包含了已傳送的資料或者接收到的資料。USART_DR實際是包含了兩個暫存器,一個專門用於傳送的可寫TDR,一個專門用於接收的可讀RDR。當進行傳送操作時,往USART_DR寫入資料會自動儲存在TDR內;當進行讀取操作時,向USART_DR讀取資料會自動提取RDR資料。
TDR和RDR都是介於系統匯流排和移位暫存器之間。序列通訊是一個位一個位傳輸的,傳送時把TDR內容轉移到傳送移位暫存器,然後把移位暫存器資料每一位傳送出去,接收時把接收到的每一位順序儲存在接收移位暫存器內然後才轉移到RDR。
USART支援DMA傳輸,可以實現高速資料傳輸,具體DMA使用將在DMA章節講解。
3. ③控制器
USART有專門控制傳送的傳送器、控制接收的接收器,還有喚醒單元、中斷控制等等。使用USART之前需要向USART_CR1暫存器的UE位置1使能USART。傳送或者接收資料字長可選8位或9位,由USART_CR1的M位控制。
傳送器
當USART_CR1暫存器的傳送使能位TE置1時,啟動資料傳送,傳送移位暫存器的資料會在TX引腳輸出,如果是同步模式SCLK也輸出時鐘訊號。
一個字元幀傳送需要三個部分:起始位+資料幀+停止位。起始位是一個位週期的低電平,位週期就是每一位佔用的時間;資料幀就是我們要傳送的8位或9位資料,資料是從最低位開始傳輸的;停止位是一定時間週期的高電平。
停止位時間長短是可以通過USART控制暫存器2(USART_CR2)的STOP[1:0]位控制,可選0.5個、1個、1.5個和2個停止位。預設使用1個停止位。2個停止位適用於正常USART模式、單線模式和調變解調器模式。0.5個和1.5個停止位用於智慧卡模式。
當選擇8位字長,使用1個停止位時,具體傳送字元時序圖見圖 208。
圖 208 字元傳送時序圖
當傳送使能位TE置1之後,傳送器開始會先發送一個空閒幀(一個數據幀長度的高電平),接下來就可以往USART_DR暫存器寫入要傳送的資料。在寫入最後一個數據後,需要等待USART狀態暫存器(USART_SR)的TC位為1,表示資料傳輸完成,如果USART_CR1暫存器的TCIE位置1,將產生中斷。
在傳送資料時,程式設計的時候有幾個比較重要的標誌位我們來總結下。
名稱 |
描述 |
TE |
傳送使能 |
TXE |
傳送暫存器為空,傳送單個位元組的時候使用 |
TC |
傳送完成,傳送多個位元組資料的時候使用 |
TXIE |
傳送完成中斷使能 |
接收器
如果將USART_CR1暫存器的RE位置1,使能USART接收,使得接收器在RX線開始搜尋起始位。在確定到起始位後就根據RX線電平狀態把資料存放在接收移位暫存器內。接收完成後就把接收移位暫存器資料移到RDR內,並把USART_SR暫存器的RXNE位置1,同時如果USART_CR2暫存器的RXNEIE置1的話可以產生中斷。
在接收資料時,程式設計的時候有幾個比較重要的標誌位我們來總結下。
名稱 |
描述 |
RE |
接收使能 |
RXNE |
讀資料暫存器非空 |
RXNEIE |
傳送完成中斷使能 |
為得到一個訊號真實情況,需要用一個比這個訊號頻率高的取樣訊號去檢測,稱為過取樣,這個取樣訊號的頻率大小決定最後得到源訊號準確度,一般頻率越高得到的準確度越高,但為了得到越高頻率取樣訊號越也困難,運算和功耗等等也會增加,所以一般選擇合適就好。
接收器可配置為不同過取樣技術,以實現從噪聲中提取有效的資料。USART_CR1暫存器的OVER8位用來選擇不同的取樣取樣方法,如果OVER8位設定為1採用8倍過取樣,即用8個取樣訊號取樣一位資料;如果OVER8位設定為0採用16倍過取樣,即用16個取樣訊號取樣一位資料。
USART的起始位檢測需要用到特定序列。如果在RX線識別到該特定序列就認為是檢測到了起始位。起始位檢測對使用16倍或8倍過取樣的序列都是一樣的。該特定序列為:1110X0X0X0000,其中X表示電平任意,1或0皆可。
8倍過取樣速度更快,最高速度可達fPCLK/8,fPCLK為USART時鐘,取樣過程見圖 209。使用第4、5、6次脈衝的值決定該位的電平狀態。
圖 209 8倍過取樣過程
16倍過取樣速度雖然沒有8倍過取樣那麼快,但得到的資料更加精準,其最大速度為fPCLK/16,取樣過程見圖 2010。使用第8、9、10次脈衝的值決定該位的電平狀態。
圖 2010 16倍過取樣過程
4. ④小數波特率生成
波特率指資料訊號對載波的調製速率,它用單位時間內載波調製狀態改變次數來表示,單位為波特。位元率指單位時間內傳輸的位元數,單位bit/s(bps)。對於USART波特率與位元率相等,以後不區分這兩個概念。波特率越大,傳輸速率越快。
USART的傳送器和接收器使用相同的波特率。計算公式如下:
公式 201 波特率計算
其中,fPLCK為USART時鐘,參考表 203;OVER8為USART_CR1暫存器的OVER8位對應的值,USARTDIV是一個存放在波特率暫存器(USART_BRR)的一個無符號定點數。其中DIV_Mantissa[11:0]位定義USARTDIV的整數部分,DIV_Fraction[3:0]位定義USARTDIV的小數部分,DIV_Fraction[3]位只有在OVER8位為0時有效,否則必須清零。
例如,如果OVER8=0,DIV_Mantissa=24且DIV_Fraction=10,此時USART_BRR值為0x18A;那麼USARTDIV的小數位10/16=0.625;整數位24,最終USARTDIV的值為24.625。
如果OVER8=0並且知道USARTDIV值為27.68,那麼DIV_Fraction=16*0.68=10.88,最接近的正整數為11,所以DIV_Fraction[3:0]為0xB;DIV_Mantissa=整數(27.68)=27,即位0x1B。
如果OVER8=1情況類似,只是把計算用到的權值由16改為8。
波特率的常用值有2400、9600、19200、115200。下面以例項講解如何設定暫存器值得到波特率的值。
由表 203可知USART1和USART6使用APB2匯流排時鐘,最高可達90MHz,其他USART的最高頻率為45MHz。我們選取USART1作為例項講解,即fPLCK=90MHz。
當我們使用16倍過取樣時即OVER8=0,為得到115200bps的波特率,此時:
解得USARTDIV=48.825125,可算得DIV_Fraction=0xD,DIV_Mantissa=0x30,即應該設定USART_BRR的值為0x30D。
在計算DIV_Fraction時經常出現小數情況,經過我們取捨得到整數,這樣會導致最終輸出的波特率較目標值略有偏差。下面我們從USART_BRR的值為0x30D開始計算得出實際輸出的波特率大小。
由USART_BRR的值為0x30D,可得DIV_Fraction=13,DIV_Mantissa=48,所以USARTDIV=48+16*0.13=48.8125,所以實際波特率為:115237;這個值跟我們的目標波特率誤差為0.03%,這麼小的誤差在正常通訊的允許範圍內。
8倍過取樣時計算情況原理是一樣的。
5. 校驗控制
STM32F4xx系列控制器USART支援奇偶校驗。當使用校驗位時,串列埠傳輸的長度將是8位的資料幀加上1位的校驗位總共9位,此時USART_CR1暫存器的M位需要設定為1,即9資料位。將USART_CR1暫存器的PCE位置1就可以啟動奇偶校驗控制,奇偶校驗由硬體自動完成。啟動了奇偶校驗控制之後,在傳送資料幀時會自動新增校驗位,接收資料時自動驗證校驗位。接收資料時如果出現奇偶校驗位驗證失敗,會見USART_SR暫存器的PE位置1,並可以產生奇偶校驗中斷。
使能了奇偶校驗控制後,每個字元幀的格式將變成:起始位+資料幀+校驗位+停止位。
6. 中斷控制
USART有多箇中斷請求事件,具體見表 204。
表 204 USART中斷請求
中斷事件 |
事件標誌 |
使能控制位 |
傳送資料暫存器為空 |
TXE |
TXEIE |
CTS標誌 |
CTS |
CTSIE |
傳送完成 |
TC |
TCIE |
準備好讀取接收到的資料 |
RXNE |
RXNEIE |
檢測到上溢錯誤 |
ORE |
|
檢測到空閒線路 |
IDLE |
IDLEIE |
奇偶校驗錯誤 |
PE |
PEIE |
斷路標誌 |
LBD |
LBDIE |
多緩衝通訊中的噪聲標誌、 |
NF/ORE/FE |
EIE |
20.4 USART初始化結構體詳解
標準庫函式對每個外設都建立了一個初始化結構體,比如USART_InitTypeDef,結構體成員用於設定外設工作引數,並由外設初始化配置函式,比如USART_Init()呼叫,這些設定引數將會設定外設相應的暫存器,達到配置外設工作環境的目的。
初始化結構體和初始化庫函式配合使用是標準庫精髓所在,理解了初始化結構體每個成員意義基本上就可以對該外設運用自如了。初始化結構體定義在stm32f4xx_usart.h檔案中,初始化庫函式定義在stm32f4xx_usart.c檔案中,程式設計時我們可以結合這兩個檔案內註釋使用。
USART初始化結構體
1 typedef struct {
2 uint32_t USART_BaudRate; // 波特率
3 uint16_t USART_WordLength; // 字長
4 uint16_t USART_StopBits; // 停止位
5 uint16_t USART_Parity; // 校驗位
6 uint16_t USART_Mode; // USART模式
7 uint16_t USART_HardwareFlowControl; // 硬體流控制
8 } USART_InitTypeDef;
1) USART_BaudRate:波特率設定。一般設定為2400、9600、19200、115200。標準庫函式會根據設定值計算得到USARTDIV值,見公式 201,並設定USART_BRR暫存器值。
2) USART_WordLength:資料幀字長,可選8位或9位。它設定USART_CR1暫存器的M位的值。如果沒有使能奇偶校驗控制,一般使用8資料位;如果使能了奇偶校驗則一般設定為9資料位。
3) USART_StopBits:停止位設定,可選0.5個、1個、1.5個和2個停止位,它設定USART_CR2暫存器的STOP[1:0]位的值,一般我們選擇1個停止位。
4) USART_Parity:奇偶校驗控制選擇,可選USART_Parity_No(無校驗)、USART_Parity_Even(偶校驗)以及USART_Parity_Odd(奇校驗),它設定USART_CR1暫存器的PCE位和PS位的值。
5) USART_Mode:USART模式選擇,有USART_Mode_Rx和USART_Mode_Tx,允許使用邏輯或運算選擇兩個,它設定USART_CR1暫存器的RE位和TE位。
6) USART_HardwareFlowControl:硬體流控制選擇,只有在硬體流控制模式才有效,可選有⑴使能RTS、⑵使能CTS、⑶同時使能RTS和CTS、⑷不使能硬體流。
當使用同步模式時需要配置SCLK引腳輸出脈衝的屬性,標準庫使用一個時鐘初始化結構體USART_ClockInitTypeDef來設定,因此該結構體內容也只有在同步模式才需要設定。
USART時鐘初始化結構體
1 typedef struct {
2 uint16_t USART_Clock; // 時鐘使能控制
3 uint16_t USART_CPOL; // 時鐘極性
4 uint16_t USART_CPHA; // 時鐘相位
5 uint16_t USART_LastBit; // 最尾位時鐘脈衝
6 } USART_ClockInitTypeDef;
1) USART_Clock:同步模式下SCLK引腳上時鐘輸出使能控制,可選禁止時鐘輸出(USART_Clock_Disable)或開啟時鐘輸出(USART_Clock_Enable);如果使用同步模式傳送,一般都需要開啟時鐘。它設定USART_CR2暫存器的CLKEN位的值。
2) USART_CPOL:同步模式下SCLK引腳上輸出時鐘極性設定,可設定在空閒時SCLK引腳為低電平(USART_CPOL_Low)或高電平(USART_CPOL_High)。它設定USART_CR2暫存器的CPOL位的值。
3) USART_CPHA:同步模式下SCLK引腳上輸出時鐘相位設定,可設定在時鐘第一個變化沿捕獲資料(USART_CPHA_1Edge)或在時鐘第二個變化沿捕獲資料。它設定USART_CR2暫存器的CPHA位的值。USART_CPHA與USART_CPOL配合使用可以獲得多種模式時鐘關係。
4) USART_LastBit:選擇在傳送最後一個數據位的時候時鐘脈衝是否在SCLK引腳輸出,可以是不輸出脈衝(USART_LastBit_Disable)、輸出脈衝(USART_LastBit_Enable)。它設定USART_CR2暫存器的LBCL位的值。
20.5 USART1接發通訊實驗
USART只需兩根訊號線即可完成雙向通訊,對硬體要求低,使得很多模組都預留USART介面來實現與其他模組或者控制器進行資料傳輸,比如GSM模組,WIFI模組、藍芽模組等等。在硬體設計時,注意還需要一根"共地線"。
我們經常使用USART來實現控制器與電腦之間的資料傳輸。這使得我們除錯程式非常方便,比如我們可以把一些變數的值、函式的返回值、暫存器標誌位等等通過USART傳送到串列埠除錯助手,這樣我們可以非常清楚程式的執行狀態,當我們正式釋出程式時再把這些除錯資訊去除即可。
我們不僅僅可以將資料傳送到串列埠除錯助手,我們還可以在串列埠除錯助手傳送資料給控制器,控制器程式根據接收到的資料進行下一步工作。
首先,我們來編寫一個程式實現開發板與電腦通訊,在開發板上電時通過USART傳送一串字串給電腦,然後開發板進入中斷接收等待狀態,如果電腦有傳送資料過來,開發板就會產生中斷,我們在中斷服務函式接收資料,並馬上把資料返回傳送給電腦。
20.5.1 硬體設計
為利用USART實現開發板與電腦通訊,需要用到一個USB轉USART的IC,我們選擇CH340G晶片來實現這個功能,CH340G是一個USB匯流排的轉接晶片,實現USB轉USART、USB轉IrDA紅外或者USB轉印表機介面,我們使用其USB轉USART功能。具體電路設計見圖 2011。
我們將CH340G的TXD引腳與USART1的RX引腳連線,CH340G的RXD引腳與USART1的TX引腳連線。CH340G晶片整合在開發板上,其地線(GND)已與控制器的GND連通。
圖 2011 USB轉串列埠硬體設計
20.5.2 軟體設計
這裡只講解核心的部分程式碼,有些變數的設定,標頭檔案的包含等並沒有涉及到,完整的程式碼請參考本章配套的工程。我們建立了兩個檔案:bsp_debug_usart.c和bsp_debug_usart.h檔案用來存放USART驅動程式及相關巨集定義。
1. 程式設計要點
1) 使能RX和TX引腳GPIO時鐘和USART時鐘;
2) 初始化GPIO,並將GPIO複用到USART上;
3) 配置USART引數;
4) 配置中斷控制器並使能USART接收中斷;
5) 使能USART;
6) 在USART接收中斷服務函式實現資料接收和傳送。
2. 程式碼分析
GPIO和USART巨集定義
程式碼清單 201 GPIO和USART巨集定義
1 #define DEBUG_USART USART1
2 #define DEBUG_USART_CLK RCC_APB2Periph_USART1
3 #define DEBUG_USART_BAUDRATE 115200 //串列埠波特率
4
5 #define DEBUG_USART_RX_GPIO_PORT GPIOA
6 #define DEBUG_USART_RX_GPIO_CLK RCC_AHB1Periph_GPIOA
7 #define DEBUG_USART_RX_PIN GPIO_Pin_10
8 #define DEBUG_USART_RX_AF GPIO_AF_USART1
9 #define DEBUG_USART_RX_SOURCE GPIO_PinSource10
10
11 #define DEBUG_USART_TX_GPIO_PORT GPIOA
12 #define DEBUG_USART_TX_GPIO_CLK RCC_AHB1Periph_GPIOA
13 #define DEBUG_USART_TX_PIN GPIO_Pin_9
14 #define DEBUG_USART_TX_AF GPIO_AF_USART1
15 #define DEBUG_USART_TX_SOURCE GPIO_PinSource9
16
17 #define DEBUG_USART_IRQHandler USART1_IRQHandler
18 #define DEBUG_USART_IRQ USART1_IRQn
使用巨集定義方便程式移植和升級,根據圖 2011電路,我們選擇使用USART1,設定波特率為115200,一般我們會預設使用"8-N-1"引數,即8個數據位、不用校驗、一位停止位。查閱表 203可知USART1的TX線可對於PA9和PB6引腳,RX線可對於PA10和PB7引腳,這裡我們選擇PA9以及PA10引腳。最後定義中斷相關引數。
巢狀向量中斷控制器NVIC配置
程式碼清單 202 中斷控制器NVIC配置
1 static void NVIC_Configuration(void)
2 {
3 NVIC_InitTypeDef NVIC_InitStructure;
4
5 /* 巢狀向量中斷控制器組選擇 */
6 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
7
8 /* 配置USART為中斷源 */
9 NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;
10 /* 搶斷優先順序為1 */
11 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
12 /* 子優先順序為1 */
13 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
14 /* 使能中斷 */
15 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
16 /* 初始化配置NVIC */
17 NVIC_Init(&NVIC_InitStructure);
18 }
19
在中斷章節已對巢狀向量中斷控制器的工作機制做了詳細的講解,這裡我們就直接使用它,配置USART作為中斷源,因為本實驗沒有使用其他中斷,對優先順序什麼具體要求。
USART初始化配置
程式碼清單 203 USART初始化配置
1 void Debug_USART_Config(void)
2 {
3 GPIO_InitTypeDef GPIO_InitStructure;
4 USART_InitTypeDef USART_InitStructure;
5 /* 使能 USART GPIO 時鐘 */
6 RCC_AHB1PeriphClockCmd(DEBUG_USART_RX_GPIO_CLK |
7 DEBUG_USART_TX_GPIO_CLK,
8 ENABLE);
9
10 /* 使能 USART 時鐘 */
11 RCC_APB2PeriphClockCmd(DEBUG_USART_CLK, ENABLE);
12
13 /* GPIO初始化 */
14 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
15 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
16 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
17
18 /* 配置Tx引腳為複用功能 */
19 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
20 GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_PIN ;
21 GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);
22
23 /* 配置Rx引腳為複用功能 */
24 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
25 GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_PIN;
26 GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
27
28 /* 連線 PXx 到 USARTx_Tx*/
29 GPIO_PinAFConfig(DEBUG_USART_RX_GPIO_PORT,
30 DEBUG_USART_RX_SOURCE,
31 DEBUG_USART_RX_AF);
32
33 /* 連線 PXx 到 USARTx__Rx*/
34 GPIO_PinAFConfig(DEBUG_USART_TX_GPIO_PORT,
35 DEBUG_USART_TX_SOURCE,
36 DEBUG_USART_TX_AF);
37
38 /* 配置串DEBUG_USART 模式 */
39 /* 波特率設定:DEBUG_USART_BAUDRATE */
40 USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
41 /* 字長(資料位+校驗位):8 */
42 USART_InitStructure.USART_WordLength = USART_WordLength_8b;
43 /* 停止位:1個停止位 */
44 USART_InitStructure.USART_StopBits = USART_StopBits_1;
45 /* 校驗位選擇:不使用校驗 */
46 USART_InitStructure.USART_Parity = USART_Parity_No;
47 /* 硬體流控制:不使用硬體流 */
48 USART_InitStructure.USART_HardwareFlowControl =
49 USART_HardwareFlowControl_None;
50 /* USART模式控制:同時使能接收和傳送 */
51 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
52 /* 完成USART初始化配置 */
53 USART_Init(DEBUG_USART, &USART_InitStructure);
54
55 /* 巢狀向量中斷控制器NVIC配置 */
56 NVIC_Configuration();
57
58 /* 使能串列埠接收中斷 */
59 USART_ITConfig(DEBUG_USART, USART_IT_RXNE, ENABLE);
60
61 /* 使能串列埠 */
62 USART_Cmd(DEBUG_USART, ENABLE);
63 }
64
使用GPIO_InitTypeDef和USART_InitTypeDef結構體定義一個GPIO初始化變數以及一個USART初始化變數,這兩個結構體內容我們之前已經有詳細講解。
呼叫RCC_AHB1PeriphClockCmd函式開啟GPIO埠時鐘,使用GPIO之前必須開啟對應埠的時鐘。使用RCC_APB2PeriphClockCmd函式開啟USART時鐘。
使用GPIO之前都需要初始化配置它,並且還要新增特殊設定,因為我們使用它作為外設的引腳,一般都有特殊功能。我們在初始化時需要把它的模式設定為複用功能。
每個GPIO都可以作為多個外設的特殊功能引腳,比如PA10這個引腳不僅僅可以作為普通的輸入\輸出引腳,還可以作為USART1的RX線引腳(USART1_RX)、定時器1通道3引腳(TIM1_CH3)、全速OTG的ID引腳(OTG_FS_ID)以及DCMI的資料1引腳(DCMI_D1)這四個外設的功能引腳,我們只能從中選擇一個使用,這時就通過GPIO引腳複用功能配置(GPIO_PinAFConfig)函式實現複用功能引腳的連線。
這時我們可能會想如果程式把PA10用於TIM1_CH3,此時USART1_RX就沒辦法使用了,那豈不是不能使用USART1了,實際上情況沒有這麼糟糕的,查閱表 203我們可以看到USART1_RX不僅僅只有PA10,還可以是PB7。所以此時我們可以PB7這個引腳來實現USART1通訊。那要是PB7也是被其他外設佔用了呢?那就沒辦法了,只能使用其他USART。
GPIO_PinAFConfig函式接收三個引數,第一個引數為GPIO埠,比如GPIOA;第二個引數是指定要複用的引腳號,比如GPIO_PinSource10;第三個引數是選擇複用外設,比如GPIO_AF_USART1。該函式最終操作的是GPIO複用功能暫存器GPIO_AFRH和GPIO_AFRL,分高低兩個。
接下來,我們配置USART1通訊引數並呼叫USART初始化函式完成配置。
程式用到USART接收中斷,需要配置NVIC,這裡呼叫NVIC_Configuration函式完成配置。配置NVIC就可以呼叫USART_ITConfig函式使能USART接收中斷。
最後呼叫USART_Cmd函式使能USART。
字元傳送
程式碼清單 204 字元傳送函式
1 /***************** 傳送一個字元 **********************/
2 void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
3 {
4 /* 傳送一個位元組資料到USART */
5 USART_SendData(pUSARTx,ch);
6
7 /* 等待發送資料暫存器為空 */
8 while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
9 }
10
11 /***************** 傳送字串 **********************/
12 void Usart_SendString( USART_TypeDef * pUSARTx, char *str)
13 {
14 unsigned int k=0;
15 do {
16 Usart_SendByte( pUSARTx, *(str + k) );
17 k++;
18 } while (*(str + k)!='\0');
19
20 /* 等待發送完成 */
21 while (USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET) {
22 }
23 }
Usart_SendByte函式用來在指定USART傳送一個ASCLL碼值字元,它有兩個形參,第一個為USART,第二個為待發送的字元。它是通過呼叫庫函式USART_SendData來實現的,並且增加了等待發送完成功能。通過使用USART_GetFlagStatus函式來獲取USART事件標誌來實現傳送完成功能等待,它接收兩個引數,一個是USART,一個是事件標誌。這裡我們迴圈檢測傳送資料暫存器為空這個標誌,當跳出while迴圈時說明發送資料暫存器為空這個事實。
Usart_SendString函式用來發送一個字串,它實際是呼叫Usart_SendByte函式傳送每個字元,直到遇到空字元才停止傳送。最後使用迴圈檢測傳送完成的事件標誌來實現保證資料傳送完成後才退出函式。
USART中斷服務函式
程式碼清單 205 USART中斷服務函式
1 void DEBUG_USART_IRQHandler(void)
2 {
3 uint8_t ucTemp;
4 if (USART_GetITStatus(DEBUG_USART,USART_IT_RXNE)!=RESET) {
5 ucTemp = USART_ReceiveData( DEBUG_USART );
6 USART_SendData(DEBUG_USART,ucTemp);
7 }
8
9 }
這段程式碼是存放在stm32f4xx_it.c檔案中的,該檔案用來集中存放外設中斷服務函式。當我們使能了中斷並且中斷髮生時就會執行中斷服務函式。
我們在程式碼清單 203使能了USART接收中斷,當USART有接收到資料就會執行DEBUG_USART_IRQHandler函式。USART_GetITStatus函式與USART_GetFlagStatus函式類似用來獲取標誌位狀態,但USART_GetITStatus函式是專門用來獲取中斷事件標誌的,並返回該標誌位狀態。使用if語句來判斷是否是真的產生USART資料接收這個中斷事件,如果是真的就使用USART資料讀取函式USART_ReceiveData讀取資料到指定儲存區。然後再呼叫USART資料傳送函式USART_SendData把資料又傳送給源裝置。
主函式
程式碼清單 206 主函式
1 int main(void)
2 {
3 /*初始化USART 配置模式為 115200 8-N-1,中斷接收*/
4 Debug_USART_Config();
5
6 Usart_SendString( DEBUG_USART,"這是一個串列埠中斷接收回顯實驗\n");
7
8 while (1) {
9
10 }
11 }
首先我們需要呼叫Debug_USART_Config函式完成USART初始化配置,包括GPIO配置,USART配置,接收中斷使用等等資訊。
接下來就可以呼叫字元傳送函式把資料傳送給串列埠除錯助手了。
最後主函式什麼都不做,只是靜靜地等待USART接收中斷的產生,並在中斷服務函式把資料回傳。
20.5.3 下載驗證
保證開發板相關硬體連線正確,用USB線連線開發板"USB TO UART"介面跟電腦,在電腦端開啟串列埠除錯助手,把編譯好的程式下載到開發板,此時串列埠除錯助手即可收到開發板發過來的資料。我們在串列埠除錯助手傳送區域輸入任意字元,點擊發送按鈕,馬上在串列埠除錯助手接收區即可看到相同的字元。
圖 2012 實驗現象
20.6 USART1指令控制RGB彩燈實驗
在學習C語言時我們經常使用C語言標準函式庫輸入輸出函式,比如printf、scanf、getchar等等。為讓開發板也支援這些函式需要把USART傳送和接收函式新增到這些函式的內部函式內。
正如之前所講,可以在串列埠除錯助手輸入指令,讓開發板根據這些指令執行一些任務,現在我們編寫讓程式接收USART資料,根據資料內容控制RGB彩燈的顏色。
20.6.1 硬體設計
硬體設計同第一個實驗。
20.6.2 軟體設計
這裡只講解核心的部分程式碼,有些變數的設定,標頭檔案的包含等並沒有涉及到,完整的程式碼請參考本章配套的工程。我們建立了兩個檔案:bsp _usart.c和bsp _usart.h檔案用來存放USART驅動程式及相關巨集定義。
1. 程式設計要點
1) 初始化配置RGB彩色燈GPIO;
2) 使能RX和TX引腳GPIO時鐘和USART時鐘;
3) 初始化GPIO,並將GPIO複用到USART上;
4) 配置USART引數;
5) 使能USART;
6) 獲取指令輸入,根據指令控制RGB彩色燈。
2. 程式碼分析
GPIO和USART巨集定義
程式碼清單 207 GPIO和USART巨集定義
- 1 //引腳定義
2 /*******************************************************/
3 #define USARTx USART1
4
5 /* 不同的串列埠掛載的匯流排不一樣,時鐘使能函式也不一樣,移植時要注意
6 * 串列埠1和6是 RCC_APB2PeriphClockCmd
7 * 串列埠2/3/4/5/7是 RCC_APB1PeriphClockCmd
8 */
9 #define USARTx_CLK RCC_APB2Periph_USART1
10 #define USARTx_CLOCKCMD RCC_APB2PeriphClockCmd
11 #define USARTx_BAUDRATE 115200 //串列埠波特率
12
13 #define USARTx_RX_GPIO_PORT GPIOA
14 #define USARTx_RX_GPIO_CLK RCC_AHB1Periph_GPIOA
15 #define USARTx_RX_PIN GPIO_Pin_10
16 #define USARTx_RX_AF GPIO_AF_USART1
17 #define USARTx_RX_SOURCE GPIO_PinSource10
18
19 #define USARTx_TX_GPIO_PORT GPIOA
20 #define USARTx_TX_GPIO_CLK RCC_AHB1Periph_GPIOA
21 #define USARTx_TX_PIN GPIO_Pin_9
22 #define USARTx_TX_AF GPIO_AF_USART1
23 #define USARTx_TX_SOURCE GPIO_PinSource9
24
25 /************************************************************/
使用巨集定義方便程式移植和升級,這裡我們可以USART1,設定波特率為115200。
USART初始化配置
程式碼清單 208 USART初始化配置
1 void USARTx_Config(void)
2 {
3 GPIO_InitTypeDef GPIO_InitStructure;
4 USART_InitTypeDef USART_InitStructure;
5
6 RCC_AHB1PeriphClockCmd(USARTx_RX_GPIO_CLK|USARTx_TX_GPIO_CLK,ENABLE);
7
8 /* 使能 USART 時鐘 */
9 USARTx_CLOCKCMD(USARTx_CLK, ENABLE);
10
11 /* GPIO初始化 */
12 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
13 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
14 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
15
16 /* 配置Tx引腳為複用功能 */
17 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
18 GPIO_InitStructure.GPIO_Pin = USARTx_TX_PIN ;
19 GPIO_Init(USARTx_TX_GPIO_PORT, &GPIO_InitStructure);
20
21 /* 配置Rx引腳為複用功能 */
22 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
23 GPIO_InitStructure.GPIO_Pin = USARTx_RX_PIN;
24 GPIO_Init(USARTx_RX_GPIO_PORT, &GPIO_InitStructure);
25
26 /* 連線 PXx 到 USARTx_Tx*/
27 GPIO_PinAFConfig(USARTx_RX_GPIO_PORT,USARTx_RX_SOURCE,USARTx_RX_AF);
28
29 /* 連線 PXx 到 USARTx__Rx*/
30 GPIO_PinAFConfig(USARTx_TX_GPIO_PORT,USARTx_TX_SOURCE,USARTx_TX_AF);
31
32 /* 配置串DEBUG_USART 模式 */
33 /* 波特率設定:DEBUG_USART_BAUDRATE */
34 USART_InitStructure.USART_BaudRate = USARTx_BAUDRATE;
35 /* 字長(資料位+校驗位):8 */
36 USART_InitStructure.USART_WordLength = USART_WordLength_8b;
37 /* 停止位:1個停止位 */
38 USART_InitStructure.USART_StopBits = USART_StopBits_1;
39 /* 校驗位選擇:偶校驗 */
40 USART_InitStructure.USART_Parity = USART_Parity_No;
41 /* 硬體流控制:不使用硬體流 */
42 USART_InitStructure.USART_HardwareFlowControl =
43 USART_HardwareFlowControl_None;
44 /* USART模式控制:同時使能接收和傳送 */
45 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
46 /* 完成USART初始化配置 */
47 USART_Init(USARTx, &USART_InitStructure);
48
49 /* 使能串列埠 */
50 USART_Cmd(USARTx, ENABLE);
51 }
使用GPIO_InitTypeDef和USART_InitTypeDef結構體定義一個GPIO初始化變數以及一個USART初始化變數,這兩個結構體內容我們之前已經有詳細講解。
呼叫RCC_AHB1PeriphClockCmd函式開啟GPIO埠時鐘,使用GPIO之前必須開啟對應埠的時鐘。
初始化配置RX線和TX線引腳為複用功能,並將指定的GPIO連線至USART1,然後配置串列埠的工作引數為115200-8-N-1。最後呼叫USART_Cmd函式使能USART。
重定向prinft和scanf函式
程式碼清單 209 重定向輸入輸出函式
1 ///重定向c庫函式printf到串列埠,重定向後可使用printf函式
2 int fputc(int ch, FILE *f)
3 {
4 /* 傳送一個位元組資料到串列埠 */
5 USART_SendData(USARTx, (uint8_t) ch);
6
7 /* 等待發送完畢 */
8 while (USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET);
9
10 return (ch);
11 }
12
13 ///重定向c庫函式scanf到串列埠,重寫向後可使用scanf、getchar等函式
14 int fgetc(FILE *f)
15 {
16 /* 等待串列埠輸入資料 */
17 while (USART_GetFlagStatus(USARTx, USART_FLAG_RXNE) == RESET);
18
19 return (int)USART_ReceiveData(USARTx);
20 }
在C語言標準庫中,fputc函式是printf函式內部的一個函式,功能是將字元ch寫入到檔案指標f所指向檔案的當前寫指標位置,簡單理解就是把字元寫入到特定檔案中。我們使用USART函式重新修改fputc函式內容,達到類似"寫入"的功能。
fgetc函式與fputc函式非常相似,實現字元讀取功能。在使用scanf函式時需要注意字元輸入格式。
還有一點需要注意的,使用fput和fgetc函式達到重定向C語言標準庫輸入輸出函式必須在MDK的工程選項把"Use MicroLIB"勾選上,MicoroLIB是預設C庫的備選庫,它對標準C庫進行了高度優化使程式碼更少,佔用更少資源。
為使用printf、scanf函式需要在檔案中包含stdio.h標頭檔案。
輸出提示資訊
程式碼清單 2010 輸出提示資訊
1 static void Show_Message(void)
2 {
3 printf("\r\n這是一個通過串列埠通訊指令控制RGB彩燈實驗 \n");
4 printf("使用 USART1 引數為:%d 8-N-1 \n",USARTx_BAUDRATE);
5 printf("開發板接到指令後控制RGB彩燈顏色,指令對應如下:\n");
6 printf(" 指令 ------ 彩燈顏色 \n");
7 printf(" 1 ------ 紅 \n");
8 printf(" 2 ------ 綠 \n");
9 printf(" 3 ------ 藍 \n");
10 printf(" 4 ------ 黃 \n");
11 printf(" 5 ------ 紫 \n");
12 printf(" 6 ------ 青 \n");
13 printf(" 7 ------ 白 \n");
14 printf(" 8 ------ 滅 \n");
15 }
Show_Message函式全部是呼叫printf函式,"列印"實驗操作資訊到串列埠除錯助手。
主函式
程式碼清單 2011 主函式
1 int main(void)
2 {
3 char ch;
4
5 /* 初始化RGB彩燈 */
6 LED_GPIO_Config();
7
8 /* 初始化USART 配置模式為 115200 8-N-1 */
9 USARTx_Config();
10
11 /* 列印指令輸入提示資訊 */
12 Show_Message();
13 while (1)
14 {
15 /* 獲取字元指令 */
16 ch=getchar();
17 printf("接收到字元:%c\n",ch);
18
19 /* 根據字元指令控制RGB彩燈顏色 */
20 switch (ch)
21 {
22 case '1':
23 LED_RED;
24 break;
25 case '2':
26 LED_GREEN;
27 break;
28 case '3':
29 LED_BLUE;
30 break;
31 case '4':
32 LED_YELLOW;
33 break;
34 case '5':
35 LED_PURPLE;
36 break;
37 case '6':
38 LED_CYAN;
39 break;
40 case '7':
41 LED_WHITE;
42 break;
43 case '8':
44 LED_RGBOFF;
45 break;
46 default:
47 /* 如果不是指定指令字元,列印提示資訊 */
48 Show_Message();
49 break;
50 }
51 }
52 }
首先我們定義一個字元變數來存放接收到的字元。
接下來呼叫LED_GPIO_Config函式完成RGB彩色GPIO初始化配置,該函式定義在bsp_led.c檔案內。
呼叫USARTx_Config函完成USART初始化配置。
Show_Message函式使用printf函式列印實驗指令說明資訊。
getchar函式用於等待獲取一個字元,並返回字元。我們使用ch變數保持返回的字元,接下來判斷ch內容執行對應的程式了。
我們使用switch語句判斷ch變數內容,並執行對應的功能程式。
20.6.3 下載驗證
保證開發板相關硬體連線正確,用USB線連線開發板"USB TO UART"介面跟電腦,在電腦端開啟串列埠除錯助手,把編譯好的程式下載到開發板,此時串列埠除錯助手即可收到開發板發過來的資料。我們在串列埠除錯