一.數(shù)據(jù)通信方式
1.串行與并行通信
按數(shù)據(jù)傳送的方式,通訊可分為串行通訊與并行通訊。
串行通訊:是指設(shè)備之間通過(guò)一根數(shù)據(jù)信號(hào)線,地線以及控制信號(hào)線,按數(shù)據(jù)位形式一位一位地傳輸數(shù)據(jù)的通訊方式,同一時(shí)刻只能傳輸一位(bit)數(shù)據(jù)。
并行通訊:是指使用 8、16、32 及 64 根或更多的數(shù)據(jù)線(有多少信號(hào)為就需要多少信號(hào)位)進(jìn)行傳輸?shù)耐ㄓ嵎绞剑梢酝粫r(shí)刻傳輸多個(gè)數(shù)據(jù)位的數(shù)據(jù)。
串行通訊與并行通訊的特性對(duì)比:
并行可以同時(shí)發(fā)送多位數(shù)據(jù)所以速度比串行的速度要快很多,但并行要的數(shù)據(jù)線也更多相對(duì)成本會(huì)更高,而且并行傳輸對(duì)同步要求較高,且隨著通訊速率的提高,信號(hào)干擾的問(wèn)題會(huì)顯著影響通訊性能。
2.全雙工、半雙工及單工通訊
單工通信:信息只能單方向傳輸?shù)墓ぷ鞣绞剑粋€(gè)固定為發(fā)送設(shè)備,另一個(gè)固定為接收設(shè)備,發(fā)送端只能發(fā)送信息不能接收信息,接收端只能接收信息不能發(fā)送信息,只需一根信號(hào)線
半雙工通信:可以實(shí)現(xiàn)雙向的通信,但不能在兩個(gè)方向上同時(shí)進(jìn)行,必須輪流交替進(jìn)行,其實(shí)也可以理解成一種可以切換方向的單工通信,同一時(shí)刻必須只能一個(gè)方向傳輸,只需一根數(shù)據(jù)線
全雙工通信:在同一時(shí)刻,兩個(gè)設(shè)備之間可以同時(shí)收發(fā)數(shù)據(jù),全雙工方式無(wú)需進(jìn)行方向的切換,這種方式要求通訊雙方均有發(fā)送器和接收器,同時(shí),需要2根數(shù)據(jù)線。
常見(jiàn)串口通信接口:
3.同步通訊與異步通訊
同步通訊:收發(fā)設(shè)備雙方會(huì)使用一根信號(hào)線表示時(shí)鐘信號(hào),在時(shí)鐘信號(hào)的驅(qū)動(dòng)下雙方進(jìn)行協(xié)調(diào),同步數(shù)據(jù),通訊中通常雙方會(huì)統(tǒng)一規(guī)定在時(shí)鐘信號(hào)的上升沿或下降沿對(duì)數(shù)據(jù)線進(jìn)行采樣,對(duì)應(yīng)時(shí)鐘極性與時(shí)鐘相位。
SPI 的同步通信:
異步通訊:不需要時(shí)鐘信號(hào)進(jìn)行數(shù)據(jù)同步,它們直接在數(shù)據(jù)信號(hào)中穿插一些同步用的信號(hào)位,或者把主體數(shù)據(jù)進(jìn)行打包,以數(shù)據(jù)幀(串口:起始位 數(shù)據(jù) 校驗(yàn)位(可以沒(méi)有) 停止位)的格式傳輸數(shù)據(jù),某些通訊中還需要雙方約定數(shù)據(jù)的傳輸速率(波特率),以便更好地同步。
二.串口通訊協(xié)議
通訊協(xié)議:分為物理層和協(xié)議層。物理層規(guī)定通訊系統(tǒng)中具有機(jī)械、電子功能部分的特性,確保原始數(shù)據(jù)在物理媒體的傳輸(通俗一點(diǎn)就是硬件部分)。協(xié)議層主要規(guī)定通訊邏輯,統(tǒng)一收發(fā)雙方的數(shù)據(jù)打包、解包標(biāo)準(zhǔn)(軟件)。
STM32串口簡(jiǎn)介
USART-通用同步異步收發(fā)器(Universal Synchronous Asynchronous Receiver and Transmitter)是一個(gè)串行通信設(shè)備,可以靈活地與外部設(shè)備進(jìn)行全雙工數(shù)據(jù)交換。有別于 USART 還有一個(gè)UART(Universal Asynchronous Receiver and Transmitter),它是在 USART 基礎(chǔ)上裁剪掉了同步通信功能(時(shí)鐘同步),只有異步通信。簡(jiǎn)單區(qū)分同步和異步就是看通信時(shí)需不需要對(duì)外提供時(shí)鐘輸出,我們平時(shí)用的串口通信基本都是 UART。
串行通信一般是以幀格式傳輸數(shù)據(jù),即是一幀一幀的傳輸,每幀包含有起始信號(hào)、數(shù)據(jù)信息、校驗(yàn)信息(由我們自己設(shè)置)、停止信號(hào)。
1.物理層
1)RS232標(biāo)準(zhǔn)
很多單片機(jī)內(nèi)部例如我們所用的STM32,以及一些傳感器一般都是TTL電平。
RS232是一種串行數(shù)據(jù)傳輸形式,稱其為串行連接,最經(jīng)典的標(biāo)志就是 9 針孔的 DB9 電纜RS232電壓表示邏輯 1 ,0的范圍大極大的增強(qiáng)了容錯(cuò)率,主要用于工業(yè)設(shè)備直接通信。
由上圖可知,TLL與RS-232標(biāo)準(zhǔn)邏輯相反,而且電平也大不相同,若單片機(jī)與單片機(jī)或其他設(shè)備TLL設(shè)備通信采用RS-232通信(DB9),肯定先要進(jìn)行電平的轉(zhuǎn)化TLL->RS232 RS232->TTL
兩個(gè)通訊設(shè)備的“DB9 接口”之間通過(guò)串口信號(hào)線建立起連接,串口信號(hào)線中使用“RS-232 標(biāo)準(zhǔn)”傳輸數(shù)據(jù)信號(hào)。由于 RS-232 電平標(biāo)準(zhǔn)的信號(hào)不能直接被控制器直接識(shí)別,所以這些信號(hào)會(huì)經(jīng)過(guò)一個(gè)“電平轉(zhuǎn)換芯片”轉(zhuǎn)換成控制器能識(shí)別的“TTL 標(biāo)準(zhǔn)”的電平信號(hào),才能實(shí)現(xiàn)通訊。
BD9串口線:
2)USB轉(zhuǎn)串口(重點(diǎn))
至于為什么是重點(diǎn)因?yàn)檫@是我實(shí)驗(yàn)用的方式重點(diǎn)介紹:
USB轉(zhuǎn)串口:主要用于設(shè)備(STM32)與電腦通信
電平轉(zhuǎn)換芯片一般有CH340、PL2303、CP2102、FT232
使用的時(shí)候電腦要按照電平轉(zhuǎn)換芯片的驅(qū)動(dòng)(虛擬出一個(gè)串口)我這里裝的是CH340
原理圖:一定要搞懂下面這張圖
這里是拿的野火的原理圖,因?yàn)槲矣X(jué)得原子的圖畫的不好,不過(guò)原理是一致的。
3原生的串口到串口
原生的串口通信主要是控制器跟串口的設(shè)備或者傳感器通信他們但是TLL電平,不需要經(jīng)過(guò)電平轉(zhuǎn)換芯片來(lái)轉(zhuǎn)換電平,直接就用TTL電平通信,GPS模塊、GSM模塊、串口轉(zhuǎn)WIFI模塊、HC04藍(lán)牙模塊
2.協(xié)議層
串口通訊的協(xié)議層中,規(guī)定了數(shù)據(jù)包的內(nèi)容,它由啟始位、主體數(shù)據(jù)、校驗(yàn)位以及停止位組成,通訊雙方的數(shù)據(jù)包格式要約定一致(一樣的起始位 數(shù)據(jù) 校驗(yàn)位 停止位)才能正常收發(fā)數(shù)據(jù)
1)通訊的起始和停止信號(hào)
串口通訊的一個(gè)數(shù)據(jù)包從起始信號(hào)開(kāi)始,直到停止信號(hào)結(jié)束。數(shù)據(jù)包的起始信號(hào)由一個(gè)邏輯 0 的數(shù)據(jù)位表示,而數(shù)據(jù)包的停止信號(hào)可由 0.5、1、1.5 或 2 個(gè)邏輯 1 的數(shù)據(jù)位表示
1個(gè)停止位:停止位位數(shù)的默認(rèn)值。
2個(gè)停止位:可用于常規(guī)USART模式、單線模式以及調(diào)制解調(diào)器模式。
0.5個(gè)停止位:在智能卡模式下接收數(shù)據(jù)時(shí)使用。
1.5個(gè)停止位:在智能卡模式下發(fā)送和接收數(shù)據(jù)時(shí)使用。
2)有效數(shù)據(jù)
在數(shù)據(jù)包的起始位之后緊接著的就是要傳輸?shù)闹黧w數(shù)據(jù)內(nèi)容,也稱為有效數(shù)據(jù),有效數(shù)據(jù)的長(zhǎng)度常被約定為 5、6、7 或 8 位長(zhǎng)
3)數(shù)據(jù)校驗(yàn)
偶校驗(yàn):校驗(yàn)位使得一幀中的7或8個(gè)LSB數(shù)據(jù)以及校驗(yàn)位中’1’的個(gè)數(shù)為偶數(shù)。
例如:數(shù)據(jù)=00110101,有4個(gè)’1’,如果選擇偶校驗(yàn)(在USART_CR1中的PS=0),校驗(yàn)位將是’0’,最后數(shù)據(jù)檢驗(yàn)如果數(shù)據(jù)有偶數(shù)個(gè)1則數(shù)據(jù)傳輸沒(méi)有出錯(cuò)(但不是絕對(duì)的,如果同時(shí)兩個(gè)數(shù)據(jù)為發(fā)送錯(cuò)誤(0變成1)則還是偶數(shù)個(gè)1)
奇校驗(yàn):此校驗(yàn)位使得一幀中的7或8個(gè)LSB數(shù)據(jù)以及校驗(yàn)位中’1’的個(gè)數(shù)為奇數(shù)。
例如:數(shù)據(jù)=00110101,有4個(gè)’1’,如果選擇奇校驗(yàn)(在USART_CR1中的PS=1),校驗(yàn)位將是’1’,最后數(shù)據(jù)檢驗(yàn)如果數(shù)據(jù)有奇數(shù)個(gè)1則數(shù)據(jù)傳輸沒(méi)有出錯(cuò),但同樣不是絕對(duì)的(同時(shí)兩個(gè)1變成0)
傳輸模式:如果USART_CR1的PCE位被置位,如果奇偶校驗(yàn)失敗USART_SR寄存器中的PE標(biāo)志被置’1’,并且如果USART_CR1寄存器的PEIE在被預(yù)先設(shè)置的話,中斷產(chǎn)生(我們可以在相應(yīng)的中斷服務(wù)函數(shù)中,寫處理校驗(yàn)失敗的代碼)
三.USART 功能框圖(超級(jí)重要)
只要把功能框圖分析透徹,寫代碼不就是信手拈來(lái),一定一定要掌握!!!
1.功能引腳:
2.數(shù)據(jù)寄存器(重點(diǎn))
下面這張圖也非常重要理解理解!!
3.控制單元(重點(diǎn))
發(fā)送器
發(fā)送器根據(jù)M位的狀態(tài)發(fā)送8位或9位的數(shù)據(jù)字。當(dāng)發(fā)送使能位(TE)被設(shè)置時(shí),發(fā)送移位寄存器中的數(shù)據(jù)在TX腳上輸出,相應(yīng)的時(shí)鐘脈沖在CK腳上輸出。
一個(gè)字符幀發(fā)送需要三個(gè)部分:起始位+數(shù)據(jù)幀(可能有校驗(yàn)位)+停止位。每個(gè)字符(一個(gè)數(shù)據(jù)幀)之前都有一個(gè)低電平的起始位,之后跟著的停止位,其數(shù)目可配置,數(shù)據(jù)幀就是我們要發(fā)送的 8 位或 9 位數(shù)據(jù),數(shù)據(jù)是從最低位開(kāi)始傳輸?shù)?停止位是一定時(shí)間周期的高電平。
配置步驟:
1.通過(guò)在USART_CR1寄存器上置位UE位來(lái)激活USART
2.編程USART_CR1的M位來(lái)定義字長(zhǎng)。
3.在USART_CR2中編程停止位的位數(shù)。
4.如果采用多緩沖器通信,配置USART_CR3中的DMA使能位(DMAT)。按多緩沖器通信中的描述配置DMA寄存器,關(guān)于DMA下期再詳細(xì)講解。
5.利用USART_BRR寄存器選擇要求的波特率。
發(fā)送和接收由一共用的波特率發(fā)生器驅(qū)動(dòng),當(dāng)發(fā)送器和接收器的使能位分別置位時(shí),分別為其產(chǎn)生時(shí)鐘。
這里舉個(gè)例子:以115200波特率
6.設(shè)置USART_CR1中的TE位,發(fā)送一個(gè)空閑幀幀(一個(gè)數(shù)據(jù)幀長(zhǎng)度的高電平)作為第一次數(shù)據(jù)發(fā)送。
7.把要發(fā)送的數(shù)據(jù)寫進(jìn)USART_DR寄存器(此動(dòng)作清除TXE位)。在只有一個(gè)緩沖器的情況下,對(duì)每個(gè)待發(fā)送的數(shù)據(jù)重復(fù)步驟7。
8.在USART_DR寄存器中寫入最后一個(gè)數(shù)據(jù)字后,要等待TC=1,它表示最后一個(gè)數(shù)據(jù)幀的傳輸結(jié)束(移位寄存器中的數(shù)據(jù)全部發(fā)送完畢)。當(dāng)需要關(guān)閉USART或需要進(jìn)入停機(jī)模式之前,需要確認(rèn)傳輸結(jié)束,避免破壞最后一次傳輸。
深入理解TXE位與TC位:
清零TXE位總是通過(guò)對(duì)數(shù)據(jù)寄存器的寫操作(CPU 或 DMA)來(lái)完成的,當(dāng)TXE位已經(jīng)被硬件置1它表明:
● 數(shù)據(jù)已經(jīng)從TDR移送到移位寄存器,數(shù)據(jù)發(fā)送已經(jīng)開(kāi)始(發(fā)送移位寄存器正在一位一位向外傳輸數(shù)據(jù))
● TDR寄存器被清空
● 下一個(gè)數(shù)據(jù)可以被寫進(jìn)USART_DR寄存器而不會(huì)覆蓋先前的數(shù)據(jù)如果TXEIE位被設(shè)置,此標(biāo)志將產(chǎn)生一個(gè)中斷。
如果此時(shí)USART正在發(fā)送數(shù)據(jù)(發(fā)送移位寄存器正在一位一位向外傳輸數(shù)據(jù)),對(duì)USART_DR寄存器的寫操作把數(shù)據(jù)存進(jìn)TDR寄存器,并在當(dāng)前傳輸結(jié)束時(shí)把該數(shù)據(jù)復(fù)制進(jìn)移位寄存器,也就是說(shuō)移位寄存器里面的數(shù)據(jù)并不會(huì)被覆蓋,所以我覺(jué)得只要你發(fā)送一幀數(shù)據(jù)等待TXE置1,就算是發(fā)送多幀數(shù)據(jù)時(shí)最后也不用等待TC=1。
如果此時(shí)USART沒(méi)有在發(fā)送數(shù)據(jù),處于空閑狀態(tài),對(duì)USART_DR寄存器的寫操作直接把數(shù)據(jù)放進(jìn)移位寄存器,數(shù)據(jù)傳輸開(kāi)始,TXE位立即被置起。
當(dāng)一幀發(fā)送完成時(shí)(停止位發(fā)送后)并且設(shè)置了TXE位,TC位被置起,如果USART_CR1寄存器中的TCIE位被置起時(shí),則會(huì)產(chǎn)生中斷
使用下列軟件過(guò)程清除TC位:
1.讀一次USART_SR寄存器;
2.寫一次USART_DR寄存器。
TC位也可以通過(guò)軟件對(duì)它寫’0’來(lái)清除。此清零方式只推薦在多緩沖器通信模式下使用
接收器
如果將 USART_CR1 寄存器的 RE 位置 1,使能 USART 接收,使得接收器在 RX 線開(kāi)始搜索起始位。在確定到起始位后就根據(jù) RX 線電平狀態(tài)把數(shù)據(jù)存放在接收移位寄存器內(nèi)。接收完成后就把接收移位寄存器數(shù)據(jù)移到 RDR 內(nèi),并把 USART_SR 寄存器的 RXNE 位置1,同時(shí)如果 USART_CR2 寄存器的 RXNEIE 置 1 的話可以產(chǎn)生中斷。
當(dāng)一字符被接收到時(shí),
● RXNE位被置1。它表明移位寄存器的內(nèi)容被轉(zhuǎn)移到RDR。換句話說(shuō),數(shù)據(jù)已經(jīng)被接收并且可以被讀出。
● 如果RXNEIE位被設(shè)置,產(chǎn)生中斷。
● 在多緩沖器通信時(shí),RXNE在每個(gè)字節(jié)接收后被置起,并由DMA對(duì)數(shù)據(jù)寄存器的讀操作而清零。
● 在單緩沖器模式里,由軟件讀USART_DR寄存器完成對(duì)RXNE位清除,RXNE標(biāo)志也可以通過(guò)對(duì)它寫0來(lái)清除。RXNE位必須在下一字符接收結(jié)束前(接收移位寄存器接收滿)被清零(要將數(shù)據(jù)讀出),以避免溢出錯(cuò)誤(移位寄存器的數(shù)據(jù)會(huì)被覆蓋)。
溢出錯(cuò)誤
如果RXNE還沒(méi)有被復(fù)位(還沒(méi)有讀出DR寄存器的數(shù)據(jù)),又接收到一個(gè)字符,則發(fā)生溢出錯(cuò)誤,數(shù)據(jù)只有當(dāng)RXNE位被清零后才能從移位寄存器轉(zhuǎn)移到RDR寄存器。RXNE標(biāo)記是接收到每個(gè)字節(jié)后被置位的。如果下一個(gè)數(shù)據(jù)已被收到或先前DMA請(qǐng)求還沒(méi)被服務(wù)時(shí),RXNE標(biāo)志仍是1,溢出錯(cuò)誤產(chǎn)生。
當(dāng)溢出錯(cuò)誤產(chǎn)生時(shí):
● ORE位被置位。
● RDR內(nèi)容將不會(huì)丟失。讀USART_DR寄存器仍能得到先前的數(shù)據(jù)。
● 移位寄存器中以前的內(nèi)容將被覆蓋。隨后接收到的數(shù)據(jù)都將丟失。
● 如果RXNEIE位被設(shè)置或EIE和DMAR位都被設(shè)置,中斷產(chǎn)生。
● 順序執(zhí)行對(duì)USART_SR和USART_DR寄存器的讀操作,可復(fù)位ORE位
USART相關(guān)中斷:
4. USART初始化結(jié)構(gòu)體
上面結(jié)構(gòu)體成員要配置的哪個(gè)寄存器哪一位前面基本都講了這里不在贅述。
1) USART_BaudRate:波特率設(shè)置。一般設(shè)置為 2400、9600、19200、115200。標(biāo)準(zhǔn)庫(kù)函數(shù)會(huì)自己計(jì)算計(jì)算得到 USARTDIV 值,從而寫入U(xiǎn)SART_BRR 寄存器。
2) USART_WordLength:數(shù)據(jù)幀字長(zhǎng),可選 8 位或 9 位。它設(shè)置了USART_CR1 寄存器的 M 位的值。如果沒(méi)有使能奇偶校驗(yàn)位,一般使用 8 數(shù)據(jù)位;如果使能了奇偶校驗(yàn)則一般設(shè)置為 9 數(shù)據(jù)位,最后一位是奇偶校驗(yàn)位。
3) USART_StopBits:停止位設(shè)置,可選 0.5 個(gè)、1 個(gè)、1.5 個(gè)和 2 個(gè)停止位,它設(shè)定USART_CR2 STOP位,一般我們選擇 1 個(gè)停止位。
4) USART_Parity :奇 偶 校 驗(yàn) 控 制 選 擇 ,USART_CR1 寄存器的 PCE 位和 PS 位的值。
5) USART_Mode:USART 模式選擇,有 USART_Mode_Rx 和 USART_Mode_Tx,允許使用邏輯或運(yùn)算選擇兩個(gè),USART_CR1 寄存器的 RE 位和 TE 位。
6) USART_HardwareFlowControl:硬件流控制選擇,只有在硬件流控制模式才有效,可選有⑴使能 RTS、⑵使能 CTS、⑶同時(shí)使能 RTS 和 CTS、⑷不使能硬件流。
四.USART1收發(fā)通信實(shí)驗(yàn)
編程要點(diǎn): 1) 使能 RX 和 TX 引腳 GPIO 時(shí)鐘和 USART 時(shí)鐘; 2) 初始化 GPIO,并將 GPIO 復(fù)用到 USART 上; 3) 配置 USART 參數(shù)初始化結(jié)構(gòu)體; 4) 配置中斷控制器并使能 USART 接收中斷; 5) 使能 USART; 6) 在 USART 接收中斷服務(wù)函數(shù)實(shí)現(xiàn)數(shù)據(jù)接收和發(fā)送。
usart.h
相關(guān)宏定義與函聲明: #ifndef _USART_H #define _USART_H #include "stm32f10x.h" #include
usart.c
#include "usart.h" #include "led.h" static void NVIC_Configuration(void) { NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); NVIC_InitStructure.NVIC_IRQChannel =DEBUG_USART_IRQ; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =0x01; NVIC_InitStructure.NVIC_IRQChannelSubPriority =0x01; NVIC_InitStructure.NVIC_IRQChannelCmd =ENABLE; NVIC_Init(&NVIC_InitStructure); } void USART_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; // 打開(kāi)串口GPIO的時(shí)鐘 DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);
// 打開(kāi)串口外設(shè)的時(shí)鐘 DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE); // 將USART Tx的GPIO配置為推挽復(fù)用模式 GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure); // 將USART Rx的GPIO配置為浮空輸入模式 GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
// 配置串口的工作參數(shù) // 配置波特率 USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE; // 配置 針數(shù)據(jù)字長(zhǎng) USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 配置停止位 USART_InitStructure.USART_StopBits = USART_StopBits_1; // 配置校驗(yàn)位 USART_InitStructure.USART_Parity = USART_Parity_No ; // 配置硬件流控制 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 配置工作模式,收發(fā)一起 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; // 完成串口的初始化配置 USART_Init(DEBUG_USARTx, &USART_InitStructure); //中斷配置 NVIC_Configuration(); //開(kāi)啟串口接收中斷 USART_ITConfig(DEBUG_USARTx,USART_IT_RXNE, ENABLE); //使能串口 USART_Cmd(DEBUG_USARTx, ENABLE); } //發(fā)送一個(gè)字節(jié) void Usart_SendByte(USART_TypeDef * pUSARTx,uint8_t date) { USART_SendData(pUSARTx,date); while( USART_GetFlagStatus(pUSARTx,USART_FLAG_TXE)== RESET); } //發(fā)送一個(gè)16位的數(shù)據(jù) void Usart_SendHalfWord(USART_TypeDef * pUSARTx,uint16_t date) { uint16_t tmp_h; uint16_t tmp_l; tmp_h =date>>0x08; tmp_l =date & 0xff; Usart_SendByte(pUSARTx,tmp_h); Usart_SendByte(pUSARTx,tmp_l); } //發(fā)送一個(gè)8位的數(shù)組 void Usart_SendArray(USART_TypeDef * pUSARTx,uint8_t *arr,uint16_t num) { while(num--) { Usart_SendByte( pUSARTx ,*arr++); } while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TC)== RESET); } //發(fā)送字符串 void Usart_SendString( USART_TypeDef * pUSARTx, char *str) { while( *str!='?' ) { Usart_SendByte( pUSARTx, *str++); } while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TC)== RESET); } ///重定向c庫(kù)函數(shù)printf到串口,重定向后可使用printf函數(shù) int fputc(int ch, FILE *f) { /* 發(fā)送一個(gè)字節(jié)數(shù)據(jù)到串口 */ USART_SendData(DEBUG_USARTx, (uint8_t) ch);
/* 等待發(fā)送完畢 */ while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);
return (ch); } ///重定向c庫(kù)函數(shù)scanf到串口,重寫向后可使用scanf、getchar等函數(shù) int fgetc(FILE *f) { /* 等待串口輸入數(shù)據(jù) */ while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) == RESET); return (int)USART_ReceiveData(DEBUG_USARTx); } //中斷服務(wù)函數(shù) void DEBUG_USART_IRQHandler(void) { uint16_t tmp; if(USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) != RESET) { tmp=USART_ReceiveData(DEBUG_USARTx); USART_SendData(DEBUG_USARTx,tmp); while( USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE)== RESET);
} }
main.c
#include "stm32f10x.h" #include "led.h" #include "usart.h" #include
uint8_t arr[10]={1,2,3,4,5,6,7,8,9,10}; /* LED 端口初始化 */ LED_GPIO_Config(); /*初始化USART 配置模式為 115200 8-N-1,中斷接收*/ USART_Config(); //發(fā)送一個(gè)字符 printf("發(fā)送一個(gè)字節(jié): "); Usart_SendByte(DEBUG_USARTx ,97); printf(" "); //發(fā)送一個(gè)16位數(shù)據(jù) Usart_SendHalfWord(DEBUG_USARTx,0xffee); //發(fā)送一個(gè)數(shù)組 Usart_SendArray(DEBUG_USARTx, arr,10); //發(fā)送一個(gè)字符串 printf("發(fā)送一個(gè)字符串: "); Usart_SendString( DEBUG_USARTx, "hello world "); while(1); }
關(guān)于printf函數(shù),scanf函數(shù) 重定向問(wèn)題
MicroLib是缺省c庫(kù)的備選庫(kù),它可裝入少量?jī)?nèi)存中,與嵌入式應(yīng)用程序配合使用,且這些應(yīng)用程序不在操作系統(tǒng)中運(yùn)行。
如果要使用printf函數(shù)輸出數(shù)據(jù)到串口,printf函數(shù)默認(rèn)是輸出到屏幕(標(biāo)準(zhǔn)輸出流—stdout),所以要重定把輸出流改成USART1串口1
當(dāng)使用 printf 函數(shù)時(shí),自動(dòng)會(huì)調(diào)用 fputc 函數(shù),而 fputc 函數(shù)內(nèi)又將輸出 設(shè)備重定義為 STM32 的 USART1,所以要輸出的數(shù)據(jù)就會(huì)在串口 1 上輸出
scanf函數(shù)(默認(rèn)鍵盤輸入,我們要重定向到串口接收)類似我就不說(shuō)了。
實(shí)驗(yàn)效果
五.向單片機(jī)發(fā)送指令點(diǎn)亮LED
main.c
#include "stm32f10x.h" #include "led.h" #include "usart.h" #include
審核編輯:湯梓紅
-
接口
+關(guān)注
關(guān)注
33文章
8691瀏覽量
151917 -
STM32
+關(guān)注
關(guān)注
2272文章
10923瀏覽量
357568 -
SPI
+關(guān)注
關(guān)注
17文章
1721瀏覽量
92125 -
串口通信
+關(guān)注
關(guān)注
34文章
1627瀏覽量
55729 -
串行通訊
+關(guān)注
關(guān)注
2文章
77瀏覽量
16417
原文標(biāo)題:STM32串口通信詳解
文章出處:【微信號(hào):mcu168,微信公眾號(hào):硬件攻城獅】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論