国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

stm32學(xué)習(xí)筆記-9 USART串口

這篇具有很好參考價(jià)值的文章主要介紹了stm32學(xué)習(xí)筆記-9 USART串口。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

9 USART串口

注:筆記主要參考B站 江科大自化協(xié) 教學(xué)視頻“STM32入門教程-2023持續(xù)更新中”。
注:工程及代碼文件放在了本人的Github倉(cāng)庫(kù)。


9.1 串口通信協(xié)議

從本節(jié)開(kāi)始,將逐一學(xué)習(xí)STM32的通信接口。首先介紹以下stm32都集成了什么通信外設(shè)。

為了控制或讀取外掛模塊,stm32需要與外掛模塊進(jìn)行通信,來(lái)擴(kuò)展硬件系統(tǒng)。而這個(gè)“通信”的過(guò)程就需要遵守相應(yīng)的“通信協(xié)議”,也就是通信雙方需要按照協(xié)議規(guī)則進(jìn)行數(shù)據(jù)收發(fā)。不同外掛模塊的會(huì)采用不同的通信協(xié)議,如下表:

表9-1 stm32片上集成的通信模塊外設(shè)
名稱 引腳 雙工 時(shí)鐘 電平 設(shè)備
USART TX/TXD、RX/RXD 全雙工 異步 單端 點(diǎn)對(duì)點(diǎn)
I2C SCL、SDA 半雙工 同步 單端 多設(shè)備
SPI SCLK、MOSI、MISO、CS 全雙工 同步 單端 多設(shè)備
CAN CAN_H、CAN_L 半雙工 異步 差分 多設(shè)備
USB DP/D+、DM/D- 半雙工 異步 差分 點(diǎn)對(duì)點(diǎn)

下面介紹一下引腳的全稱:

  • USART:TX(Transmit Exchange)數(shù)據(jù)發(fā)送腳、RX(Receive Exchange)數(shù)據(jù)接收腳。
  • IIC:SCL(Serial Clock)時(shí)鐘線、SDA(Serial Data)數(shù)據(jù)線。
  • SPI:MOSI(Master Output Slave Input)主機(jī)輸出數(shù)據(jù)腳、MISO(Master Input Slave Output)主機(jī)輸入數(shù)據(jù)腳、CS(Chip Select)片選
  • USB:DP(Data Postive)差分線正、DM(Data Minus)差分線負(fù)

注:上述協(xié)議中,單端電平都需要共地。
注:使用差分信號(hào)可以抑制共模噪聲,可以極大的提高信號(hào)的抗干擾特性,所以一般差分信號(hào)的傳輸速度和傳輸距離都非常高。

本節(jié)將介紹串口。串口是一種應(yīng)用十分廣泛的通訊接口,串口成本低、容易使用、通信線路簡(jiǎn)單,可實(shí)現(xiàn)兩個(gè)設(shè)備的互相通信。單片機(jī)的串口可以使單片機(jī)與單片機(jī)、單片機(jī)與電腦、單片機(jī)與各式各樣的模塊互相通信,極大地?cái)U(kuò)展了單片機(jī)的應(yīng)用范圍,增強(qiáng)了單片機(jī)系統(tǒng)的硬件實(shí)力。

一般單片機(jī)中都會(huì)有串口的通信外設(shè)。在單片機(jī)領(lǐng)域中,相比于IIC、SPI等協(xié)議,串口是一種非常簡(jiǎn)單的通信接口,只支持點(diǎn)對(duì)點(diǎn)的通信單片機(jī)與電腦通信,是串口的一大優(yōu)勢(shì),可以外接電腦屏幕,非常適合調(diào)試程序、打印信息……IIC或SPI協(xié)議一般都是芯片之間的通信,有片選引腳所以支持總線通信,而不會(huì)直接外接在電腦上。

stm32有幾個(gè)usart,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖9-1 串口模塊實(shí)例
  1. USB轉(zhuǎn)串口模塊:使用CH340芯片,可以將串口協(xié)議轉(zhuǎn)換成USB協(xié)議。使用此模塊可以實(shí)現(xiàn)單片機(jī)與電腦的通信。
  2. 陀螺儀模塊:左側(cè)是串口引腳,右側(cè)是IIC引腳??梢杂糜跍y(cè)量角速度、角速度等姿態(tài)參數(shù)。
  3. 藍(lán)牙串口模塊:上面的芯片可以和手機(jī)互聯(lián),下面四個(gè)引腳是串口引腳。此芯片可以實(shí)現(xiàn)手機(jī)遙控單片機(jī)的功能。
stm32有幾個(gè)usart,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖9-2 串口引腳接線圖

下面介紹一些串口引腳的注意事項(xiàng):

  • TX與RX:簡(jiǎn)單雙向串口通信有兩根通信線(發(fā)送端TX和接收端RX),要交叉連接。不過(guò),若僅單向的數(shù)據(jù)傳輸,可以只接一根通信線。
  • GND:一定要共地。由于TX和RX的高低電平都是相對(duì)于GND來(lái)說(shuō)的,所以GND嚴(yán)格來(lái)說(shuō)也算是通信線。
  • VCC:相同的電平才能通信,如果兩設(shè)備都有單獨(dú)的供電,VCC就可以不接在一起。但如果某個(gè)模塊沒(méi)有供電,就需要連接VCC,注意供電電壓要按照模塊要求來(lái),必要時(shí)需要添加電壓轉(zhuǎn)換電路。

電平標(biāo)準(zhǔn)是數(shù)據(jù)1和數(shù)據(jù)0的表達(dá)方式,是傳輸線纜中人為規(guī)定的電壓與數(shù)據(jù)的對(duì)應(yīng)關(guān)系,串口常用的電平標(biāo)準(zhǔn)有如下三種:

  1. TTL電平【單片機(jī)】:+3.3V或+5V表示1,0V表示0。一般低壓小型設(shè)備,使用的都是TTL電平。傳輸范圍幾十米。
  2. RS232電平:-3~-15V表示1,+3~+15V表示0。一般在大型機(jī)器上使用,由于環(huán)境比較惡劣,靜電干擾比較大,所以通信電壓都很大,并且允許波動(dòng)的范圍也很大。傳輸范圍幾十米。
  3. RS485電平:兩線壓差+2~+6V表示1,-2~-6V表示0(差分信號(hào))??垢蓴_能力極強(qiáng),通信距離可達(dá)上千米。

注:不同電平標(biāo)準(zhǔn)之間的轉(zhuǎn)換只需要加電壓轉(zhuǎn)換芯片即可,并不需要修改相應(yīng)的軟件代碼。

上面介紹了串口協(xié)議的硬件部分(如何表示1/0),下面來(lái)介紹串口協(xié)議的軟件部分(如何使用1/0組成字節(jié)數(shù)據(jù))。

stm32有幾個(gè)usart,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖9-3 串口的單字節(jié)發(fā)送格式

下面介紹串口的參數(shù):

  • 波特率:串口通信的速率(bit/s),也就是通信雙方所約定的通信速率(異步通信)。
  • 空閑狀態(tài):固定為高電平。
  • 起始位:固定為低電平,標(biāo)志一個(gè)數(shù)據(jù)幀的開(kāi)始。
  • 數(shù)據(jù)位:低位先行,數(shù)據(jù)幀的有效載荷,1為高電平,0為低電平。
  • 校驗(yàn)位(選填):用于數(shù)據(jù)驗(yàn)證,根據(jù)數(shù)據(jù)位計(jì)算得來(lái)。
  • 停止位:固定為高電平,用于表示數(shù)據(jù)幀的間隔,同時(shí)也可以使得通信線回歸到空閑狀態(tài)。可以配置停止位是1位/2位。
stm32有幾個(gè)usart,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖9-4 串口時(shí)序

上圖給出了幾個(gè)例子,來(lái)展示串口通信的時(shí)序圖:

  • 右側(cè)最后兩個(gè)圖展示了不同長(zhǎng)度停止位的現(xiàn)象。

注:在stm32中,根據(jù)發(fā)送數(shù)據(jù)自動(dòng)轉(zhuǎn)換發(fā)送波形、或根據(jù)波形自動(dòng)讀取數(shù)據(jù),都是由USART外設(shè)自動(dòng)完成的,無(wú)需軟件控制每一位的發(fā)送或讀取。

9.2 stm32的片上外設(shè)-USART

USART(Universal Synchronous/Asynchronous Receiver/Transmitter)通用同步/異步收發(fā)器 是STM32內(nèi)部集成的硬件外設(shè),可根據(jù)數(shù)據(jù)寄存器的一個(gè)字節(jié)數(shù)據(jù) 自動(dòng)生成數(shù)據(jù)幀時(shí)序,從TX引腳發(fā)送出去,也可 自動(dòng)接收RX引腳的數(shù)據(jù)幀時(shí)序,拼接為一個(gè)字節(jié)數(shù)據(jù),存放在數(shù)據(jù)寄存器里。USART中的“S”表示同步,只支持時(shí)鐘輸出,不支持時(shí)鐘輸入,是為了兼容別的協(xié)議或特殊用途而設(shè)計(jì)的,并不支持兩個(gè)USART之間進(jìn)行同步通信,所以這個(gè)功能幾乎不會(huì)用到,一般更常使用的是UART同步異步收發(fā)器。下面是一些參數(shù):

  • 自帶波特率發(fā)生器,最高達(dá)4.5Mbits/s,常用9600/115200。
  • 可配置數(shù)據(jù)位長(zhǎng)度(8/9)、停止位長(zhǎng)度(0.5/1/1.5/2)。
  • 可選校驗(yàn)位:無(wú)校驗(yàn)(常用)/奇校驗(yàn)/偶校驗(yàn)。
  • 支持同步模式(一般不用)、硬件流控制(指示從設(shè)備準(zhǔn)備好接收的信號(hào),一般不用)、DMA、智能卡、IrDA(手機(jī)紅外通信,但并不是紅外遙控,目前很少見(jiàn))、LIN(局域網(wǎng)的通信協(xié)議)。
  • STM32F103C8T6 USART資源:USART1(APB2)、USART2(APB1)、USART3(APB1)。
表9-2 串口引腳定義和引腳復(fù)用關(guān)系
引腳 USART1 USART2 USART3
TX PA9/PB6 PA2 PB10
RX PA10/PB7 PA3 PB11
CK PA8 PA4 PB12
CTS PA11 PA0 PB13
RTS PA12 PA1 PB14
注:斜杠后面的引腳表示重定義
stm32有幾個(gè)usart,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖9-5 USART框圖
  • 發(fā)送數(shù)據(jù)的過(guò)程:某時(shí)刻給“TDR”寫(xiě)入數(shù)據(jù)0x55,此時(shí)硬件檢測(cè)到寫(xiě)入數(shù)據(jù),就會(huì)檢查當(dāng)前“發(fā)送移位寄存器”是否 有數(shù)據(jù)正在進(jìn)行移位,若正在移位,就會(huì)等待移位完成;若沒(méi)有移位,就會(huì)將TDR中的數(shù)據(jù)立刻移動(dòng)到“發(fā)送移位寄存器”中,準(zhǔn)備發(fā)送。然后,“發(fā)送移位寄存器”就會(huì)在下面的“發(fā)送器控制”的驅(qū)動(dòng)下,向右一位一位的移位(低位先行),將數(shù)據(jù)輸出到TX發(fā)送引腳。移位完成后,新的數(shù)據(jù)會(huì)再次自動(dòng)的從TDR轉(zhuǎn)移到“發(fā)送移位寄存器”中來(lái)。有了TDR和“發(fā)送移位寄存器”的雙重緩存,可以保證連續(xù)發(fā)送數(shù)據(jù)時(shí),數(shù)據(jù)幀之間不會(huì)有空閑。
  • 寫(xiě)入數(shù)據(jù)的時(shí)機(jī):當(dāng)數(shù)據(jù)從TDR移動(dòng)到“發(fā)送移位寄存器”時(shí),標(biāo)志位TXE置位(TX Empty,發(fā)送寄存器空),此時(shí)檢測(cè)到TXE置位就可以繼續(xù)寫(xiě)入下一個(gè)數(shù)據(jù),但注意此時(shí)上一個(gè)數(shù)據(jù)實(shí)際上還沒(méi)發(fā)送出去。
  • 接收數(shù)據(jù)的過(guò)程:數(shù)據(jù)從RX引腳通向“接收移位寄存器”,在“接收器控制”的驅(qū)動(dòng)下,一位一位的讀取RX電平并放在最高位,整個(gè)過(guò)程不斷右移(低位先行),最終就可以接收1個(gè)字節(jié)。當(dāng)一個(gè)字節(jié)移位完成后,這一個(gè)字節(jié)的數(shù)據(jù)就會(huì)整體地一下子轉(zhuǎn)移到“接收數(shù)據(jù)寄存器RDR”中。然后就準(zhǔn)備繼續(xù)讀取下一幀數(shù)據(jù)。同樣,RDR和“接收移位寄存器”也組成了雙重緩存結(jié)構(gòu),可以保證連續(xù)讀取數(shù)據(jù)。
  • 讀取數(shù)據(jù)的時(shí)機(jī):接收數(shù)據(jù)從“接收移位寄存器”轉(zhuǎn)移到RDR的過(guò)程中,標(biāo)志位RXNE置位(RX Not Empty,接收數(shù)據(jù)寄存器非空)。所以當(dāng)檢測(cè)到標(biāo)志位RXNE置位時(shí),就可以將數(shù)據(jù)讀走。

下面來(lái)看看其他的硬件電路功能:

  • 發(fā)送器控制:控制“發(fā)送移位寄存器”工作。
  • 接收器控制:控制“接收移位寄存器”工作。
  • 硬件數(shù)據(jù)流控:也就是“硬件流控制”,簡(jiǎn)稱“流控”。如果主設(shè)備連續(xù)發(fā)送,導(dǎo)致從設(shè)備內(nèi)部無(wú)法及時(shí)處理接收數(shù)據(jù),就會(huì)出現(xiàn)數(shù)據(jù)丟棄或覆蓋的現(xiàn)象(注意不是UART沒(méi)接收到,而是從設(shè)備沒(méi)有及時(shí)將數(shù)據(jù)從RDR取走),此時(shí)“流控”就可以幫助從設(shè)備向主設(shè)備發(fā)信號(hào),指明自己還沒(méi)有準(zhǔn)備好接收數(shù)據(jù),主設(shè)備也就不會(huì)發(fā)送數(shù)據(jù)了。本教程不涉及。
  • nRTS(Request To Send):輸出腳,請(qǐng)求發(fā)送。也就是告訴主設(shè)備,當(dāng)前是否已經(jīng)準(zhǔn)備好接收。前方“n”表示低電平有效。
  • nCTS(Clear To Send):輸入腳,清除發(fā)送。用于接收從設(shè)備的nRTS信號(hào)。前方“n”表示低電平有效。
  • SCLK:用于產(chǎn)生“同步功能”的時(shí)鐘信號(hào),配合“發(fā)送移位寄存器”輸出,用于給從設(shè)備提供時(shí)鐘。注意沒(méi)有同步時(shí)鐘輸入,所以兩個(gè)USART之間不能同步通信。
  • 喚醒單元:實(shí)現(xiàn)串口掛載多設(shè)備。前面提到串口一般是點(diǎn)對(duì)點(diǎn)通信,但是這個(gè)模塊通過(guò)給串口分配地址“USART地址”,就可以決定是否喚醒USART工作,進(jìn)而實(shí)現(xiàn)了總線通信。
  • 狀態(tài)寄存器SR:存儲(chǔ)著串口通信的各種標(biāo)志位,其中比較重要的有發(fā)送寄存器空TXE、接收數(shù)據(jù)寄存器非空RXNE。
  • USART中斷控制:中斷輸出控制,配置中斷是否可以通向NVIC。其中斷申請(qǐng)位就是狀態(tài)寄存器SR中的各種標(biāo)志位。
  • 波特率發(fā)生器部分:其實(shí)就是分頻器,APB時(shí)鐘進(jìn)行分頻,得到發(fā)送和接收移位的時(shí)鐘。
  • fPCLKx(x=1,2):時(shí)鐘輸入。由于UASRT1掛載在APB2上,所以 時(shí)鐘輸入fPCLKx(x=1,2) 就是PCLK2的時(shí)鐘,一般為72MHz。而UASRT2、USART3都掛載在APB1上,所以 時(shí)鐘輸入fPCLKx(x=1,2) 就是PCLK1的時(shí)鐘,一般為36MHz。
  • /UASRTDIV:時(shí)鐘分頻系數(shù)。內(nèi)部結(jié)構(gòu)也就是虛線框中的“傳統(tǒng)的波特率發(fā)生器”。
  • /16:再進(jìn)行16分頻,得到最終的“發(fā)送器時(shí)鐘”、“接收器時(shí)鐘”。

注:發(fā)送時(shí)添加開(kāi)始位、停止位;接收時(shí)去除開(kāi)始位、停止位,這些工作由內(nèi)部硬件電路自動(dòng)完成。
注:更多關(guān)于控制寄存器CR、狀態(tài)寄存器SR的描述可以查閱參考手冊(cè)“25.6 USART寄存器描述”。

stm32有幾個(gè)usart,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖9-6 USART基本結(jié)構(gòu)

上圖給出USART最主要、最基本的結(jié)構(gòu):

  • 波特率發(fā)生器:用于產(chǎn)生約定的通信速率。時(shí)鐘來(lái)源是PCLK2/PCLK1,經(jīng)過(guò)波特率發(fā)生器分頻后,產(chǎn)生的時(shí)鐘通向發(fā)送控制器、接收控制器。
  • 發(fā)送控制器、接收控制器:用于控制發(fā)送移位、接收移位。
  • GPIO:發(fā)送端配置成復(fù)用推挽輸出、接收端配置成上拉輸入。
  • 標(biāo)志位:TXE置位時(shí)寫(xiě)入數(shù)據(jù)、RXNE置位時(shí)接收數(shù)據(jù)。
  • 開(kāi)關(guān)控制:用于開(kāi)啟整個(gè)USART外設(shè)。

下面來(lái)看幾個(gè)細(xì)節(jié)的問(wèn)題:
細(xì)節(jié)1:數(shù)據(jù)幀

stm32有幾個(gè)usart,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖9-7 字長(zhǎng)的配置

上圖給出了8位字長(zhǎng)(無(wú)校驗(yàn)位)、9位字長(zhǎng)(有校驗(yàn)位)的波形:

  • 時(shí)鐘上升沿:可以看到每個(gè)數(shù)據(jù)中間都有一個(gè)時(shí)鐘上升沿,所以接收端采樣時(shí)刻就是時(shí)鐘上升沿。時(shí)鐘的極性、相位等都可以通過(guò)配置寄存器配置。
  • 空閑幀、斷開(kāi)幀:用于局域網(wǎng)協(xié)議。
  • 盡量選擇9位字長(zhǎng)有校驗(yàn)、8位字長(zhǎng)無(wú)校驗(yàn)
stm32有幾個(gè)usart,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖9-8 停止位的配置

stm32串口外設(shè)的停止位長(zhǎng)度可以配置成0.5/1/1.5/1位,共四種選擇,區(qū)別就是停止位的時(shí)長(zhǎng)不一樣。

  • 一般就選擇停止位長(zhǎng)度為1位。

細(xì)節(jié)2:USART輸入數(shù)據(jù)采樣規(guī)則
串口的輸出TX只需要保持相應(yīng)時(shí)長(zhǎng)的電平即可,電路簡(jiǎn)單;但是串口輸入RX則需要判斷電平持續(xù)時(shí)間,所以電路會(huì)更加復(fù)雜,所以下面來(lái)詳細(xì)介紹stm32串口外設(shè)對(duì)于輸入數(shù)據(jù)的采樣。

stm32有幾個(gè)usart,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖9-9 對(duì)于起始位的采樣

注意到采樣時(shí)鐘是波特率的16倍,即會(huì)對(duì)某一位采樣16次。

  • 檢測(cè)下降沿:若突然檢測(cè)到下降沿,則開(kāi)始進(jìn)行檢測(cè)。
  • 檢測(cè)3、5、7位:在第3、5、7間隔采樣,采樣判斷原則為若三位全為0,則正常進(jìn)入后續(xù);若有2個(gè)0,則還是會(huì)接著檢測(cè),但噪聲標(biāo)志位NE(Noise Error)置位(告訴用戶,我這兒接收的信號(hào)有噪聲,你悠著點(diǎn)用??);若低于2個(gè)0,則認(rèn)為之前檢測(cè)到的下降沿為噪聲,忽略已經(jīng)捕獲的數(shù)據(jù),重新回到空閑狀態(tài)開(kāi)始捕捉下降沿。
  • 檢測(cè)8、9、10位:連續(xù)采樣。采樣判斷原則與上述相同。
stm32有幾個(gè)usart,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖9-10 對(duì)于數(shù)據(jù)位的采樣

由于起始位采樣已經(jīng)對(duì)齊了數(shù)據(jù)時(shí)鐘,所以數(shù)據(jù)采樣就直接在8、9、10位采樣。

  • 數(shù)據(jù)采樣的判斷原則:三個(gè)數(shù)據(jù)中,0/1哪個(gè)數(shù)據(jù)多就判斷為接收到哪個(gè)。但是如果三個(gè)數(shù)據(jù)有不一致的情況,噪聲標(biāo)志位NE(Noise Error)置位。

細(xì)節(jié)3:計(jì)算分頻系數(shù)DIV

stm32有幾個(gè)usart,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖9-11 波特比率寄存器示意圖

發(fā)送器和接收器的波特率由波特率寄存器BRR里的分頻系數(shù)DIV確定:
波特率 = f P C L K 2 / 1 16 ? D I V 波特率 = \frac{f_{PCLK2/1}}{16 * DIV} 波特率=16?DIVfPCLK2/1??

例如:若輸入時(shí)鐘為 f P C L K 2 / 1 = 72 M H z f_{PCLK2/1}= 72MHz fPCLK2/1?=72MHz,希望配置波特率為9600,則分頻系數(shù)為: D I V = 72 M 16 ? 9600 = 468.75 DIV=\frac{72M}{16*9600}=468.75 DIV=16?960072M?=468.75,轉(zhuǎn)換成二進(jìn)制為111010100.11,于是USART_BRR的值為0001_1101_0100_1100(高位補(bǔ)零、低位補(bǔ)零)。

比較方便的是,上述過(guò)程都可以使用USART的外設(shè)庫(kù)函數(shù)實(shí)現(xiàn),調(diào)用時(shí)只需輸入波特率,庫(kù)函數(shù)會(huì)自動(dòng)計(jì)算出DIV,并按照格式配置好BRR寄存器。

注:十進(jìn)制轉(zhuǎn)二進(jìn)制工具為菜鳥(niǎo)工具的 “在線進(jìn)制轉(zhuǎn)換器”。

細(xì)節(jié)4:USB轉(zhuǎn)串口模塊

stm32有幾個(gè)usart,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖9-12 USB轉(zhuǎn)串口模塊-原理圖

主要關(guān)注的是該模塊的供電情況。

  • USB插座:直接插在電腦USB端口上,注意整個(gè)模塊的供電來(lái)自于USB的VCC+5V。
  • CON6插針座:
  • 引腳2、引腳3:用于連接到stm32上進(jìn)行串口通信。
  • 引腳5【CH340_VCC】:通過(guò)跳線帽可以選擇 接入+3.3V(stm32) 或者+5V。CH340芯片的供電引腳,同時(shí)決定了TTL,所以也就是串口通信的TTL電平。神奇的是,即使不接跳線帽CH340也可以正常工作,TTL為3.3V,但是顯然接上電路以后更加穩(wěn)定。
  • 通信和供電的選擇:CON6插針座選擇引腳4/6進(jìn)行通信后,剩下的引腳可以用于給從設(shè)備供電,但是剩下的這個(gè)腳顯然與TTL電平不匹配。此時(shí)需要注意 優(yōu)先保證供電電平的正確,通信TTL電平不一致問(wèn)題不大。當(dāng)然,若從設(shè)備自己有電源,那么就不存在這個(gè)問(wèn)題了。
  • TXD指示燈、RXD指示燈:若相應(yīng)總線上有數(shù)據(jù)傳輸,那么指示燈就會(huì)閃爍。

細(xì)節(jié)5:數(shù)據(jù)模式
顯然計(jì)算機(jī)在通信過(guò)程中只能傳輸二進(jìn)制數(shù)據(jù),那么如何發(fā)送文本呢?就需要制定一個(gè)規(guī)則,來(lái)約定字符和接收數(shù)據(jù)的映射關(guān)系,即字符編碼表。不同的編碼格式有不同的映射,具體可以在網(wǎng)上隨便搜搜“字符編碼格式”,如知乎文章“字符常見(jiàn)的編碼方式”。

HEX模式/十六進(jìn)制模式/二進(jìn)制模式:以原始數(shù)據(jù)的形式顯示;
文本模式/字符模式:以原始數(shù)據(jù)編碼后的形式顯示。

stm32有幾個(gè)usart,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖9-13 ASCII碼表-UP自己做的高清版

9.3 USART收發(fā)相關(guān)實(shí)驗(yàn)

9.3.1 實(shí)驗(yàn)1:串口發(fā)送

需求:在軟件代碼中定義要發(fā)送的信息,然后通過(guò)串口發(fā)送到電腦端,使用“串口助手”小工具查看。要求依次發(fā)送單字節(jié)數(shù)據(jù)、數(shù)組、字符串、數(shù)據(jù)的每一位。
注:串口助手可以切換“文本模式”/“HEX模式”。
注:數(shù)字和字符的對(duì)應(yīng)關(guān)系可以參考ASCII碼表。

stm32有幾個(gè)usart,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖9-14 串口發(fā)送-接線圖

注:接線圖也可以不接OLED顯示屏。

stm32有幾個(gè)usart,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖9-15 串口發(fā)送-代碼調(diào)用(非庫(kù)函數(shù))

下面是代碼展示:
- main.c

#include "stm32f10x.h"                  // Device header
#include "SerialPort.h"
    
int main(void){
    uint8_t send_byte = 0x42;
    uint8_t send_array[6] = {0x30,0x31,0x32,0x33,0x34,0x35};
    //串口初始化
    SerialPort_Init();
    //發(fā)送單個(gè)字節(jié)
    SerialPort_SendByte('A');//可以直接發(fā)送字符
    SerialPort_SendByte(send_byte);
    SerialPort_SendByte('\r');
    SerialPort_SendByte('\n');
    //發(fā)送數(shù)組
    SerialPort_SendArray(send_array,6);
    SerialPort_SendByte('\r');
    SerialPort_SendByte('\n');
    //發(fā)送字符串
    SerialPort_SendString("Hello World!\r\n");
    //發(fā)送數(shù)字的每一位
    SerialPort_SendNum(65535, 5);
    SerialPort_SendString("\r\n");
    while(1){
//        //循環(huán)發(fā)送數(shù)字
//        SerialPort_SendByte(send_byte);
//        OLED_ShowHexNum(1,9,send_byte,2);
//        send_byte++;
//        Delay_ms(1000);
    };
}

- SerialPort.h

#ifndef __SERIALPORT_H
#define __SERIALPORT_H

void SerialPort_Init(void);
void SerialPort_SendByte(uint8_t send_byte);
void SerialPort_SendArray(uint8_t *send_array, uint16_t size_array);
void SerialPort_SendString(char *send_string);
void SerialPort_SendNum(uint32_t send_num, uint16_t send_len);

#endif

- SerialPort.c

#include "stm32f10x.h"                  // Device header

//串口初始化-USART1
void SerialPort_Init(void){
    //1.開(kāi)啟RCC外設(shè)時(shí)鐘
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    //2.初始化GPIO-PA9
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    //3.初始化USART結(jié)構(gòu)體
    USART_InitTypeDef USART_InitStructure;
    USART_InitStructure.USART_BaudRate = 9600;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Tx;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_Init(USART1, &USART_InitStructure);
    //4.配置中斷,開(kāi)啟NVIC(接收數(shù)據(jù)使用)
    //5.開(kāi)啟外設(shè)
    USART_Cmd(USART1, ENABLE);
}

//串口發(fā)送1字節(jié)數(shù)據(jù)
void SerialPort_SendByte(uint8_t send_byte){
    //向發(fā)送數(shù)據(jù)寄存器TDR中寫(xiě)入數(shù)據(jù)
    USART_SendData(USART1, send_byte);
    //確認(rèn)數(shù)據(jù)被轉(zhuǎn)移到發(fā)送移位寄存器(等待標(biāo)志位TXE置位)
    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE)==RESET);
}

//發(fā)送一個(gè)數(shù)組
void SerialPort_SendArray(uint8_t *send_array, uint16_t size_array){
    uint8_t i=0;
    for(i=0;i<size_array;i++){
        SerialPort_SendByte(send_array[i]);
    }
}

//發(fā)送一個(gè)字符串
void SerialPort_SendString(char *send_string){
    uint8_t i=0;
    for(i=0; send_string[i]!='\0'; i++){
        SerialPort_SendByte(send_string[i]);
    }
}

//非外部調(diào)用函數(shù)-冪次函數(shù)
uint32_t SerialPort_Pow(uint32_t X, uint32_t Y){
    uint32_t result = 1;
    while(Y--){
        result *= X;
    }
    return result;
}

//發(fā)送數(shù)字的每一位-先發(fā)高位
void SerialPort_SendNum(uint32_t send_num, uint16_t send_len){
    uint16_t i;
    for(i=0;i<send_len;i++){
        SerialPort_SendByte((send_num/SerialPort_Pow(10,send_len-i-1))%10+'0');
    }
}

編程感想:

  1. 關(guān)于接線。注意串口通信的兩個(gè)設(shè)備是交叉連接的,所以“USB轉(zhuǎn)串口模塊”的TX應(yīng)該接在stm32串口的RX(PA10)、RX應(yīng)該接在stm32串口的TX(PA9)!
  2. 關(guān)于sizeof。相信很多人也想到,在封裝發(fā)送數(shù)組的函數(shù)時(shí),為什么不直接在函數(shù)中使用sizeof函數(shù)來(lái)計(jì)算數(shù)組的大小呢?這樣能少傳遞一個(gè)參數(shù),更簡(jiǎn)潔。但實(shí)際上,這里面的水很深,這樣操作是不能得到正確結(jié)果的,具體原理可以參考CSDN博文“數(shù)組名不等于指針”。最終結(jié)論就是,數(shù)組名在傳參過(guò)程中,會(huì)退化成一個(gè)指針,此時(shí)所表示的大小不是數(shù)組的實(shí)際大小,而是這個(gè)指針的大小,所以要想在函數(shù)中使用到數(shù)組大小,最好還是多傳遞一個(gè)參數(shù)。

9.3.2 實(shí)驗(yàn)2:移植printf函數(shù)

需求:將C語(yǔ)言自帶函數(shù)printf進(jìn)行封裝,默認(rèn)成將需要打印的數(shù)據(jù)發(fā)送到串口,進(jìn)而可以顯示在電腦端串口助手上。

接線圖函數(shù)調(diào)用(非庫(kù)函數(shù)) 與上一小節(jié)實(shí)驗(yàn)“串口發(fā)送”相同。本節(jié)本人目前也不懂原理,所以下面直接給出 代碼展示

方法一:

  1. 首先點(diǎn)擊“魔術(shù)棒”,在Target界面的“Code Generation”方框中勾選“USE MicroLIB”。MicroLIB是Keil為嵌入式平臺(tái)優(yōu)化的一個(gè)精簡(jiǎn)庫(kù),要使用printf函數(shù)就會(huì)用到這個(gè)MicroLIB精簡(jiǎn)庫(kù)。
  2. 對(duì)printf函數(shù)重定向,將printf函數(shù)打印的東西輸出到串口。于是在 SerialPort.c 模塊中添加下列代碼:
#include <stdio.h>

//對(duì)printf函數(shù)重定向-將fputc函數(shù)原型重定向到串口
//注:ptintf函數(shù)本質(zhì)上就是循環(huán)調(diào)用fputc,將字符一個(gè)一個(gè)輸出
int fputc(int ch, FILE *f){
    SerialPort_SendByte(ch);
    return ch;
}

SerialPort.h 模塊中添加下列代碼:

#include <stdio.h>
  1. 于是就可以在 main.c 中調(diào)用printf函數(shù),將數(shù)據(jù)輸出到串口了。
//使用重定向的printf函數(shù)
    printf("%d\r\n",666);

但注意這個(gè)方法直接將printf函數(shù)重定向到了USART1,別的USART外設(shè)(USART2、USART3等)想用就沒(méi)辦法了。所以有如下的改進(jìn)方法。

方法二:
若多個(gè)串口都想使用printf函數(shù),那么就可以使用sprintf函數(shù)。sprintf函數(shù)可以將格式化字符輸出到一個(gè)字符串里,然后再調(diào)用相應(yīng)的“串口發(fā)送字符串”函數(shù)發(fā)送這個(gè)字符串,整個(gè)過(guò)程不涉及重定向,于是就實(shí)現(xiàn)了所有USART外設(shè)都可以打印信息到串口了。所以下面可以直接在 main.c 中定義:

char String[100];//定義一個(gè)足夠長(zhǎng)的字符串?dāng)?shù)組
sprintf(String, "Num=%d\r\n", 666);//將格式化字符串存儲(chǔ)在String中
SerialPort_SendString(String);//串口發(fā)送字符串

方法三:
方法二的sprintf函數(shù)很方便,但是直接在主函數(shù)中寫(xiě)比較麻煩,于是本方法就是來(lái)封裝“方法二”。具體方法如下:

  1. C語(yǔ)言可變參數(shù)。在串口模塊SerialPort.c中添加下面代碼:
#include <stdarg.h>

//對(duì)sprintf函數(shù)進(jìn)行封裝
void SerialPort_Printf(char *format,...){
    char String[100];//定義輸出的字符串
    va_list arg;//定義參數(shù)列表變量
    va_start(arg, format);//從format位置開(kāi)始接收參數(shù)表,放在arg里面
    vsprintf(String, format, arg);//sprintf只接收直接寫(xiě)的參數(shù),對(duì)于封裝格式改用vsprintf
    va_end(arg);//釋放參數(shù)表
    SerialPort_SendString(String);  
}
//注意上述函數(shù)要在頭文件中聲明,但頭文件就不需要再添加<stdarg.h>了。
  1. 直接在主函數(shù)中調(diào)用:
SerialPort_Printf("Num=%d\r\n", 888);

特殊說(shuō)明:顯示漢字
使用上面幾種printf函數(shù)時(shí),有可能會(huì)出現(xiàn)亂碼,要解決這個(gè)問(wèn)題,關(guān)鍵是要保持Keil編譯器(“扳手”圖標(biāo)Editor界面的Encoding下拉菜單)和“串口助手”的文本編碼一致。可以選擇以下兩種情況:

  1. 兩者都選擇UTF-8編碼。但是直接在字符串寫(xiě)漢字,編譯器有可能報(bào)錯(cuò),解決方法是點(diǎn)擊“魔術(shù)棒”–>C/C+±->最下面的Controls輸入 --no-multibyte-chars即可。
  2. 有些串口助手軟件可能不兼容UTF-8,所以兩者都需要選擇GB2312編碼。

注:更改編譯器文本編碼格式后,需要將文件全部關(guān)閉,重新打開(kāi),否則編碼方式不會(huì)改變。

9.3.3 實(shí)驗(yàn)3:串口發(fā)送+接收

需求:電腦端發(fā)送數(shù)據(jù),stm32接收到數(shù)據(jù)后,將數(shù)據(jù)在OLED顯示屏上顯示出來(lái)、并且回傳到電腦。

程序整體思路:

  1. 查詢。主函數(shù)不斷查詢RXNE標(biāo)志位,但是會(huì)占用很多的CPU資源,所以不推薦。
  2. 中斷。推薦方法,下面的演示也是基于此方法。

本實(shí)驗(yàn)的 接線圖 與前兩小節(jié)的實(shí)驗(yàn)均相同,下面給出 代碼調(diào)用

stm32有幾個(gè)usart,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖9-16 串口發(fā)送+接收-代碼調(diào)用(非庫(kù)函數(shù))

下面是 代碼展示,僅給出在串口模塊中增添的函數(shù):
- main.c

#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "SerialPort.h"

int main(void){    
    uint8_t Rx_byte = 0;//串口接收的單比特?cái)?shù)據(jù)
    
    //設(shè)置中斷分組
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    
    //OLED初始化
    OLED_Init();
    OLED_ShowString(1,1,"Rx_byte:");
    
    //串口初始化
    SerialPort_Init();

    while(1){
        if(SerialPort_GetRxFlag()==1){
            Rx_byte = SerialPort_GetRxData();
            OLED_ShowHexNum(1,9,Rx_byte,2);
            SerialPort_SendByte(Rx_byte);
        }
    };
}

- SerialPort.c

uint8_t SerialPort_RxData = 0;
uint8_t SerialPort_RxFlag = 0;

//獲取接收的狀態(tài)
uint8_t SerialPort_GetRxFlag(void){
    if(SerialPort_RxFlag==1){
        SerialPort_RxFlag = 0;
        return 1;
    }else{
        return 0;
    }
}

//獲取接收的數(shù)據(jù)
uint8_t SerialPort_GetRxData(void){
    return SerialPort_RxData;
}

//USART1_RXNE中斷函數(shù)
void USART1_IRQHandler(void){
    if(USART_GetITStatus(USART1, USART_IT_RXNE)==SET){
        SerialPort_RxFlag = 1;
        SerialPort_RxData = USART_ReceiveData(USART1);
        //讀操作可以自動(dòng)清零標(biāo)志位,但加上也沒(méi)事
        USART_ClearITPendingBit(USART1, USART_IT_RXNE);
    }
}
//不要忘了將前兩個(gè)函數(shù)在頭文件中聲明

9.4 USART串口數(shù)據(jù)包

數(shù)據(jù)包的作用是將一個(gè)個(gè)單獨(dú)的數(shù)據(jù)打包,方便進(jìn)行多字節(jié)的數(shù)據(jù)通信。因?yàn)閷?shí)際應(yīng)用中,經(jīng)常需要進(jìn)行數(shù)據(jù)打包。比如陀螺儀傳感器需要將數(shù)據(jù)發(fā)送到stm32,其中包括X軸、Y軸、Z軸三個(gè)字節(jié),循環(huán)不斷的發(fā)送;若采用一個(gè)一個(gè)進(jìn)行發(fā)送的方式,接收方就有可能分不清對(duì)應(yīng)的順序,進(jìn)而出現(xiàn)數(shù)據(jù)錯(cuò)位現(xiàn)象。此時(shí),若能將同一批數(shù)據(jù)進(jìn)行分割和打包,就可以方便接收方識(shí)別。

1. 數(shù)據(jù)包格式的定義:

stm32有幾個(gè)usart,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖9-17 HEX數(shù)據(jù)包示意圖

若載荷數(shù)據(jù)與包頭、包尾一樣怎么辦呢?有三種解決思路:

  1. 限制載荷數(shù)據(jù)的范圍。使其不會(huì)與包頭、包尾重復(fù)。
  2. 盡量使用固定長(zhǎng)度的數(shù)據(jù)包。只要數(shù)據(jù)長(zhǎng)度固定,那么就可以通過(guò)包頭、包尾定位數(shù)據(jù)。
  3. 增加包頭包尾的數(shù)量,使其盡量呈現(xiàn)出載荷數(shù)據(jù)不會(huì)出現(xiàn)的狀態(tài)。

注:包尾可以去除。但是這樣會(huì)使得載荷數(shù)據(jù)和包頭重復(fù)的問(wèn)題更加嚴(yán)重。

若想發(fā)送16位整型數(shù)據(jù)、32位整型數(shù)據(jù)、float、double、結(jié)構(gòu)體等,只需使用 uint8_t型指針 指向這些數(shù)據(jù),就可以進(jìn)行發(fā)送(將各種數(shù)據(jù)轉(zhuǎn)換成字節(jié)流)。

stm32有幾個(gè)usart,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖9-18 文本數(shù)據(jù)包示意圖

文本數(shù)據(jù)包中,每個(gè)數(shù)據(jù)都經(jīng)過(guò)了一層編碼和譯碼。
由于包頭包尾非常容易唯一確定,文本數(shù)據(jù)包基本不用擔(dān)心載荷數(shù)據(jù)和包頭包尾重復(fù)的問(wèn)題。

優(yōu)缺點(diǎn)比較:

  • HEX數(shù)據(jù)包:
  • 優(yōu)點(diǎn):傳輸最直接,解析數(shù)據(jù)非常簡(jiǎn)單,比較適合一些模塊發(fā)送最原始的數(shù)據(jù)。如使用串口通信的陀螺儀、溫濕度傳感器。
  • 缺點(diǎn):靈活性不足,載荷容易和包頭包尾重復(fù)。
  • 文本數(shù)據(jù)包:
  • 優(yōu)點(diǎn):數(shù)據(jù)直觀易理解,非常靈活,比較適合一些輸入指令進(jìn)行人機(jī)交互的場(chǎng)合。如藍(lán)牙模塊常用的AT指令、CNC和3D打印機(jī)常用的G代碼,都是文本數(shù)據(jù)包的格式。
  • 缺點(diǎn):解析效率低。

2. 數(shù)據(jù)包格式的收發(fā)流程:
數(shù)據(jù)包發(fā)送是非常簡(jiǎn)單的,直接發(fā)就完事兒了。但是接收數(shù)據(jù)包的過(guò)程比較復(fù)雜,這是就要考慮使用狀態(tài)機(jī)。

stm32有幾個(gè)usart,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖9-19 接收HEX數(shù)據(jù)包-狀態(tài)機(jī)
stm32有幾個(gè)usart,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖9-20 接收文本數(shù)據(jù)包-狀態(tài)機(jī)

9.5 USART數(shù)據(jù)包相關(guān)實(shí)驗(yàn)

9.5.1 實(shí)驗(yàn)1:串口收發(fā)HEX數(shù)據(jù)包

需求:自定義數(shù)據(jù)包格式,使用串口完成指定格式的數(shù)據(jù)包收發(fā),并將收發(fā)結(jié)果顯示在OLED上。另外按鍵的功能是將發(fā)送的當(dāng)前存儲(chǔ)的發(fā)送數(shù)據(jù)全部加1再發(fā)送出去。

  • 數(shù)據(jù)包頭:0xFF。
  • 載荷數(shù)據(jù):固定數(shù)據(jù)段長(zhǎng)度為4個(gè)字節(jié)。
  • 數(shù)據(jù)包尾:0xFE。
stm32有幾個(gè)usart,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖9-21 串口收發(fā)HEX數(shù)據(jù)包-接線圖
stm32有幾個(gè)usart,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖9-22 串口收發(fā)HEX數(shù)據(jù)包-代碼調(diào)用(非庫(kù)函數(shù))

下面是代碼展示:其中將串口的模塊的數(shù)據(jù)接收部分全部刪除,重寫(xiě)。
- main.c

#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "SerialPort.h"
#include "Key.h"

int main(void){
    //存儲(chǔ)串口接收的HEX數(shù)據(jù)包
    uint8_t *Rx_Packet = SerialPort_GetRxPacket();
    //存儲(chǔ)串口發(fā)送的HEX數(shù)據(jù)包
    uint8_t Tx_Packet[4] = {0x01,0x02,0x03,0x04};
    
    //設(shè)置中斷分組
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    
    //OLED初始化
    OLED_Init();
    OLED_ShowString(1,1,"Rx_Packet:");
    OLED_ShowString(3,1,"Tx_Packet:");
    //串口初始化
    SerialPort_Init();
    //按鍵初始化
    Key_Init();
        
    while(1){
        //顯示接收到的數(shù)據(jù)
        if(SerialPort_GetRxFlag()==1){
            OLED_ShowHexNum(2,1,*Rx_Packet,2);
            OLED_ShowHexNum(2,4,*(Rx_Packet+1),2);
            OLED_ShowHexNum(2,7,*(Rx_Packet+2),2);
            OLED_ShowHexNum(2,10,*(Rx_Packet+3),2);
        }
        
        //檢測(cè)按鍵,發(fā)送數(shù)據(jù)包到電腦
        if(Key_GetNum()==1){
            Tx_Packet[0]++;
            Tx_Packet[1]++;
            Tx_Packet[2]++;
            Tx_Packet[3]++;
            SerialPort_SendPacket(Tx_Packet);
            OLED_ShowHexNum(4,1,Tx_Packet[0],2);
            OLED_ShowHexNum(4,4,Tx_Packet[1],2);
            OLED_ShowHexNum(4,7,Tx_Packet[2],2);
            OLED_ShowHexNum(4,10,Tx_Packet[3],2);
        }
    };
}

- SerialPort.c新增函數(shù)

uint8_t SerialPort_RxPacket[4];
uint8_t SerialPort_RxPacketFlag = 0;

//獲取接收的狀態(tài)
uint8_t SerialPort_GetRxFlag(void){
    if(SerialPort_RxPacketFlag==1){
        SerialPort_RxPacketFlag = 0;
        return 1;
    }else{
        return 0;
    }
}

//獲取接收的HEX數(shù)據(jù)包
uint8_t* SerialPort_GetRxPacket(void){
    return SerialPort_RxPacket;
}

//發(fā)送HEX數(shù)據(jù)包
void SerialPort_SendPacket(uint8_t *send_array){
    SerialPort_SendByte(0xFF);
    SerialPort_SendArray(send_array, 4);
    SerialPort_SendByte(0xFE);
}

//USART1_RXNE中斷函數(shù)
void USART1_IRQHandler(void){
    uint8_t rec_byte;
    static uint8_t rx_state;
    static uint8_t rx_index;
    if(USART_GetITStatus(USART1, USART_IT_RXNE)==SET){
        rec_byte = USART_ReceiveData(USART1);
        
        //利用狀態(tài)機(jī),接收HEX數(shù)據(jù)包
        if(rx_state==0){
            if(rec_byte==0xFF){
                rx_index = 0;
                rx_state = 1;
            }
        }else if(rx_state==1){
            SerialPort_RxPacket[rx_index] = rec_byte;
            rx_index++;
            if(rx_index>=4){
                rx_state = 2;
            }
        }else if(rx_state==2){
            if(rec_byte==0xFE){
                SerialPort_RxPacketFlag = 1;
                rx_state = 0;
            }
        }
        
        //讀操作可以自動(dòng)清零標(biāo)志位,但加上也沒(méi)事
        USART_ClearITPendingBit(USART1, USART_IT_RXNE);
    }
}
//除了中斷函數(shù),其余函數(shù)還要在頭文件SerialPort.h中聲明

編程感想:

  1. 數(shù)據(jù)混疊。若電腦端連續(xù)發(fā)送數(shù)據(jù)包,而stm32處理不及時(shí),會(huì)導(dǎo)致數(shù)據(jù)錯(cuò)位。但是一般像傳感器模塊等的數(shù)據(jù)都具有連續(xù)性,所以就算數(shù)據(jù)錯(cuò)位也沒(méi)關(guān)系。
  2. 發(fā)送數(shù)據(jù)不匹配。注意發(fā)送字節(jié)數(shù)據(jù)一定要寫(xiě)成0x11的形式,而不是直接寫(xiě)一個(gè)11進(jìn)行發(fā)送。
  3. 收發(fā)數(shù)據(jù)沒(méi)反應(yīng)。注意一定要在最開(kāi)始聲明的地方賦初值,否則有可能讀不出數(shù)據(jù)。當(dāng)然,還有一種可能是串口連接不穩(wěn)定,可以重新拔插一下串口。

9.5.2 實(shí)驗(yàn)2:串口收發(fā)文本數(shù)據(jù)包

需求:使用電腦端發(fā)送指定格式的文本數(shù)據(jù)包,來(lái)控制單片機(jī)點(diǎn)亮或熄滅LED燈,單片機(jī)完成指令后再將接收的狀態(tài)回傳到電腦。

  • 數(shù)據(jù)包頭:@。
  • 數(shù)據(jù)包:有效指令為"@LED_ON\r\n"、“@LED_OFF\r\n”。(不定字長(zhǎng))
  • 數(shù)據(jù)包尾:\r\n。
stm32有幾個(gè)usart,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖9-23 串口收發(fā)文本數(shù)據(jù)包-接線圖
stm32有幾個(gè)usart,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖9-24 串口收發(fā)文本數(shù)據(jù)包-代碼調(diào)用(非庫(kù)函數(shù))

下面是代碼展示:
- main.c

#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "SerialPort.h"
#include "LED.h"
#include <string.h>

int main(void){
    //存儲(chǔ)串口接收的HEX數(shù)據(jù)包
    char *Rx_Packet = SerialPort_GetRxPacket();
    
    //設(shè)置中斷分組
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    
    //OLED初始化
    OLED_Init();
    OLED_ShowString(1,1,"Rx_Packet:");
    OLED_ShowString(3,1,"Tx_Packet:");
    //串口初始化
    SerialPort_Init();
    //LED初始化
    LED_Init();
        
    while(1){
        //對(duì)接收到的文本進(jìn)行判斷
        if(SerialPort_GetRxFlag()==1){
            //OLED顯示接收到的文本
            OLED_ShowString(2,1,"                ");
            OLED_ShowString(2,1,Rx_Packet);
            //根據(jù)接收的內(nèi)容執(zhí)行相應(yīng)的動(dòng)作
            if(strcmp(Rx_Packet, "LED_ON")==0){
                LED1_ON();
                OLED_ShowString(4,1,"                ");
                OLED_ShowString(4,1,"LED_ON_OK");
                SerialPort_SendString("LED_ON_OK\r\n");
            }else if(strcmp(Rx_Packet, "LED_OFF")==0){
                LED1_OFF();
                OLED_ShowString(4,1,"                ");
                OLED_ShowString(4,1,"LED_OFF_OK");
                SerialPort_SendString("LED_OFF_OK\r\n");
            }else{
                OLED_ShowString(4,1,"                ");
                OLED_ShowString(4,1,"ERROR_COMMAND");
                SerialPort_SendString("ERROR_COMMAND\r\n");
            }
        }
    };
}

- SerialPort.c新增函數(shù)(將上一節(jié)HEX數(shù)據(jù)包部分全部刪除)

char SerialPort_RxPacket[100];
uint8_t SerialPort_RxPacketFlag = 0;

//獲取接收的狀態(tài)
uint8_t SerialPort_GetRxFlag(void){
    if(SerialPort_RxPacketFlag==1){
        SerialPort_RxPacketFlag = 0;
        return 1;
    }else{
        return 0;
    }
}

//獲取接收的HEX數(shù)據(jù)包
char* SerialPort_GetRxPacket(void){
    return SerialPort_RxPacket;
}

//USART1_RXNE中斷函數(shù)
void USART1_IRQHandler(void){
    uint8_t rec_byte;
    static uint8_t rx_state;
    static uint8_t rx_index;
    if(USART_GetITStatus(USART1, USART_IT_RXNE)==SET){
        rec_byte = USART_ReceiveData(USART1);
        
        //利用狀態(tài)機(jī),接收HEX數(shù)據(jù)包
        if(rx_state==0){
            if(rec_byte== '@'){
                rx_index = 0;
                rx_state = 1;
            }
        }else if(rx_state==1){
            if(rec_byte != '\r'){
                SerialPort_RxPacket[rx_index] = rec_byte;
                rx_index++;
            }else{
                rx_state = 2;
            }
        }else if(rx_state==2){
            if(rec_byte == '\n'){
                SerialPort_RxPacket[rx_index] = '\0';//字符串結(jié)束標(biāo)志符
                SerialPort_RxPacketFlag = 1;
                rx_state = 0;
            }
        }
        
        //讀操作可以自動(dòng)清零標(biāo)志位,但加上也沒(méi)事
        USART_ClearITPendingBit(USART1, USART_IT_RXNE);
    }
}
//除了中斷函數(shù),其他函數(shù)還要在頭文件SerialPort.h中聲明

- LED.c新增函數(shù)

/**
  * @brief  LED1亮
  */
void LED1_ON(void){
    GPIO_ResetBits(GPIOA, GPIO_Pin_1);
}

/**
  * @brief  LED1滅
  */
void LED1_OFF(void){
    GPIO_SetBits(GPIOA, GPIO_Pin_1);
}
//注意還要在頭文件LED.h中聲明

編程感想:

  1. 數(shù)據(jù)混疊。同樣的問(wèn)題,如果電腦端發(fā)送指令太快,就有可能導(dǎo)致stm32來(lái)不及處理,導(dǎo)致錯(cuò)誤。一個(gè)解決方法是指令發(fā)慢一點(diǎn);當(dāng)然另一種方法是增加標(biāo)志位,當(dāng)LED的狀態(tài)沒(méi)有改變之前,不理會(huì)接收數(shù)據(jù),這樣會(huì)破壞當(dāng)前程序的獨(dú)立性,并且原理不復(fù)雜,我就先不寫(xiě)了。

9.6 軟件使用:FlyMcu串口下載 & STLINK Utility

  • FlyMcu可以通過(guò)串口給stm32下載程序。綠色軟件,無(wú)需安裝。
  • STLINK Utility通過(guò)STLINK給stm32下載程序。需要安裝。

以上兩款軟件類似于51單片機(jī)的程序燒錄軟件——STC-ISP,可以通過(guò)串口給51單片機(jī)下載程序。
硬件方面,接線圖本章的第一個(gè)實(shí)驗(yàn)“串口發(fā)送”相同,這是因?yàn)樵撔酒拇谙螺d只適配了USART1,所以引腳都要連接在USART1引腳上。

stm32有幾個(gè)usart,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖9-25 串口下載程序-硬件接線示意圖

下面依次介紹FlyMcu、STLINK Utility:

stm32有幾個(gè)usart,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖9-26 FlyMcu界面功能介紹

FlyMcu只能下載HEX文件,Keil生成HEX文件 的方法:

  • 點(diǎn)擊“魔術(shù)棒”–>Output選項(xiàng)卡–>勾選“Create HEX File”。編譯過(guò)后,就可以在工程目錄的“Object文件夾”下找到該工程的HEX文件——“工程名.hex”。

使用FlyMcu下載程序

  1. 配置下載串口:點(diǎn)擊菜單欄“搜索串口”,稍等一會(huì),點(diǎn)擊緊隨其后的“Port:xx”選項(xiàng),選擇對(duì)應(yīng)的串口。接著點(diǎn)擊緊隨其后的“bps:xx”選擇下載的波特率。
  2. 選擇程序文件。菜單欄下一行,點(diǎn)擊“…”按鈕,選擇HEX文件。
  3. 其他功能保持默認(rèn)。
  4. 調(diào)整啟動(dòng)位置為BootLoader程序。由于串口下載需要使得stm32的啟動(dòng)位置為BootLoader啟動(dòng)程序,而B(niǎo)ootLoader啟動(dòng)程序固定放在“系統(tǒng)存儲(chǔ)器”,所以BOOT引腳應(yīng)調(diào)整為 [BOOT1,BOOT0]=[0,1]。注意調(diào)整BOOT后,一定要按一下最小系統(tǒng)板上的復(fù)位鍵,調(diào)整才會(huì)生效。
    stm32有幾個(gè)usart,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
  5. 點(diǎn)擊FlyMcu的“開(kāi)始編程”。此時(shí)程序就會(huì)被下載到主閃存中了,但由于BOOT引腳沒(méi)有變動(dòng),所以程序下載完復(fù)位后,還是會(huì)停留在BootLoader程序中。
  6. 調(diào)整啟動(dòng)位置為主閃存。BOOT引腳應(yīng)調(diào)整為 [BOOT1,BOOT0]=[0,0],然后按下復(fù)位鍵,就可以看到程序正常運(yùn)行了。

注:關(guān)于串口下載的原理,我覺(jué)得前面將“存儲(chǔ)器映像”時(shí)已經(jīng)說(shuō)得很清楚了,就不記錄了,UP講解的地方在“P30 [9-6] FlyMcu串口下載&STLINK Utility 中的4:56~8:11”。

每次下載程序都要拔插兩邊跳線帽,太麻煩了,有什么更簡(jiǎn)單的方法嗎?

  1. 方法一:設(shè)計(jì)外圍的STM32一鍵下載電路。利用“USB轉(zhuǎn)串口模塊”上CH340的 RTS#、DTR# 兩個(gè)流控輸出引腳分別控制stm32的BOOT0引腳、復(fù)位引腳(但是不使用流控功能,而僅僅只是當(dāng)作一個(gè)普通的GPIO口),加上FlyMcu的選項(xiàng),便可以利用電路自動(dòng)切換BOOT引腳的高低電平。
  2. 方法二:軟件設(shè)置自動(dòng)跳轉(zhuǎn)(一次性功能)。勾選FlyMcu的“編程后執(zhí)行”,去除勾選“編程到FLASH時(shí)寫(xiě)選項(xiàng)字節(jié)”。然后 [BOOT1,BOOT0]=[0,1],并按下復(fù)位鍵。然后點(diǎn)擊“開(kāi)始編程”,就可以看到程序正常執(zhí)行。

方法二評(píng)價(jià):該方法原理是下載程序后,軟件設(shè)置從主閃存(0x08000000)開(kāi)始執(zhí)行程序,但是按下復(fù)位鍵后,程序又會(huì)回到“系統(tǒng)存儲(chǔ)器”執(zhí)行BootLoader程序。所以可以不斷的使用串口調(diào)試程序,最后調(diào)試成功后再將BOOT引腳切換回來(lái)即可。也就是,只需要最開(kāi)始和最后切換跳線帽而已。

讀FLASH: 讀取主閃存中的程序數(shù)據(jù),以BIN文件格式存儲(chǔ)(BIN文件不包含地址信息,HEX文件包含地址信息)。后續(xù)可以使用STLINK Utility下載,實(shí)現(xiàn)盜取他人軟件勞動(dòng)成果??。

清除芯片: 將主程序區(qū)域全部擦除(全部變成高電平)。

讀器件信息: 讀取芯片的信息。但是FLASH容量、SRAM容量等信息可能會(huì)出錯(cuò)。

設(shè)定選項(xiàng)字節(jié)等: 可以設(shè)置選項(xiàng)字節(jié)的各項(xiàng)參數(shù)。點(diǎn)擊“STM32F1選項(xiàng)設(shè)置”,彈出以下界面:
stm32有幾個(gè)usart,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)

  1. 讀保護(hù)字節(jié):是否允許讀出主閃存數(shù)據(jù)。注意如果“阻止讀出”,那么就無(wú)法使用Keil下載程序了。另外,在清除讀保護(hù)的同時(shí),同時(shí)也會(huì)清空主閃存的數(shù)據(jù)。
  2. 硬件選項(xiàng)字節(jié):有需求可以使用。
  3. 用戶數(shù)據(jù)字節(jié):有需求可以使用。那使用選項(xiàng)字節(jié)存儲(chǔ)數(shù)據(jù)有什么好處呢?
  1. 選項(xiàng)字節(jié)的數(shù)據(jù)相當(dāng)于是“世外桃源”,無(wú)論如何下載程序,選項(xiàng)字節(jié)中的數(shù)據(jù)都可以不變,可以存儲(chǔ)一些不隨程序變化的參數(shù);
  2. 用上位機(jī)(如FlyMcu、STLINK Utility)可以很方便的修改。
  1. 寫(xiě)保護(hù)字節(jié):可以對(duì)Flash的某幾頁(yè)單獨(dú)寫(xiě)保護(hù)。比如在主程序的最后幾頁(yè)寫(xiě)了一些自定的數(shù)據(jù),不希望在下載時(shí)被擦除,就可以將最后幾頁(yè)設(shè)置寫(xiě)保護(hù)鎖起來(lái)。注意,開(kāi)啟“寫(xiě)保護(hù)”后,若需要對(duì)保護(hù)區(qū)寫(xiě)入程序就會(huì)出錯(cuò)!并且該軟件不支持單獨(dú)寫(xiě)入選項(xiàng)字節(jié),只能在Flash下載時(shí)順便寫(xiě)入選項(xiàng)字節(jié),那也就是說(shuō),如果將Flash前幾頁(yè)寫(xiě)保護(hù)了,就再也無(wú)法使用FlyMcu下載程序了?。?/strong>(使用STLINK Utility可以補(bǔ)救回來(lái))
    注意配置好選項(xiàng)字節(jié)數(shù)據(jù)后,點(diǎn)擊“采用這個(gè)設(shè)置”,并在FlyMcu主界面勾選“編程到FLASH時(shí)寫(xiě)選項(xiàng)字節(jié)”。
stm32有幾個(gè)usart,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
圖9-27 STLINK Utility界面功能介紹

STLINK Utility需要安裝,安裝完成后,在桌面上存在快捷方式。STLINK Utility可以下載多種文件,包括HEX文件、BIN文件等。下面演示 下載程序的流程

  1. 硬件接線。無(wú)需連接“USB轉(zhuǎn)串口模塊”,只需連接STLINK即可。BOOT引腳設(shè)置為 [BOOT1,BOOT0]=[0,0],然后按下復(fù)位鍵。點(diǎn)擊左起第三個(gè)按鈕進(jìn)行連接。
  2. 左起第一個(gè)按鈕:打開(kāi)程序文件,支持HEX格式、BIN格式。(也可以直接跳到下一步)
  3. 左起第六個(gè)按鈕:下載程序。跳過(guò)上一步的,此時(shí)選擇程序文件。然后點(diǎn)擊“Start”下載程序。下載完成后可以發(fā)現(xiàn)程序正常運(yùn)行。

選項(xiàng)字節(jié)的配置:菜單欄“Target”–>“Option Byte…”,下面依次介紹:

stm32有幾個(gè)usart,# stm32-江科大,stm32,單片機(jī),學(xué)習(xí)
  1. 讀保護(hù)。
  2. 硬件參數(shù)?;疑倪x項(xiàng)就是本芯片不支持的選項(xiàng)。
  3. 用戶參數(shù)。
  4. 寫(xiě)保護(hù)。

注:配置好之后點(diǎn)擊“Apply”,就可以直接單獨(dú)更改選項(xiàng)字節(jié)的參數(shù)。

左起第二個(gè)按鈕:讀芯片數(shù)據(jù),格式可以選為HEX格式、BIN格式。
左起第四個(gè)按鈕:斷開(kāi)連接。
左起第五個(gè)按鈕:擦除芯片。
STLINK固件更新:菜單欄“ST-LINK”–>Firmware update–>重新拔插STLINK–>點(diǎn)擊“Device Connect”–>“Yes>>>>”。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-633964.html

到了這里,關(guān)于stm32學(xué)習(xí)筆記-9 USART串口的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 嵌入式學(xué)習(xí)筆記——STM32的USART收發(fā)字符串及串口中斷

    嵌入式學(xué)習(xí)筆記——STM32的USART收發(fā)字符串及串口中斷

    上一篇中,介紹了串口收發(fā)相關(guān)的寄存器,通過(guò)代碼實(shí)現(xiàn)了一個(gè)字節(jié)的收發(fā),本文接著上面的內(nèi)容,通過(guò)功能函數(shù)實(shí)現(xiàn)字符串的收發(fā),然后引入中斷解決收發(fā)過(guò)程中while()死等的問(wèn)題。 根據(jù)昨天的字符發(fā)送函數(shù),只需要稍作修改即可實(shí)現(xiàn)發(fā)送函數(shù)了,一個(gè)字符串的結(jié)尾會(huì)有一

    2024年02月03日
    瀏覽(36)
  • 江科大32——USART串口發(fā)送&串口發(fā)送+接收代碼

    江科大32——USART串口發(fā)送&串口發(fā)送+接收代碼

    ?1.程序初始化流程 1)開(kāi)啟USART和GPIO時(shí)鐘。 2)GPIO初始化,把TX配置成復(fù)用輸出,RX配置成輸入。 3)使用結(jié)構(gòu)體配置USART。 如果只需發(fā)送功能,直接開(kāi)啟USART就行了。 如果需要發(fā)送和接收,需要在開(kāi)啟USART之前加上 ITConfig 和 NVIC 的代碼。 初始化完成,只需調(diào)用特定函數(shù)就能完

    2024年02月12日
    瀏覽(23)
  • 【STM32筆記】STM32的串口數(shù)據(jù)收發(fā)基礎(chǔ)(四)(USART DMA模式)

    【STM32筆記】STM32的串口數(shù)據(jù)收發(fā)基礎(chǔ)(四)(USART DMA模式)

    ? ?? 在STM32中編寫(xiě)串口通信數(shù)據(jù)收發(fā)有三種方式: 輪詢模式 (阻塞方式), 中斷模式 (非阻塞方式)以及 DMA模式 。 ? ?? 打開(kāi)STM32CubeMX,前部分配置流程如串口數(shù)據(jù)收發(fā)基礎(chǔ)(三)節(jié)里一樣。配置好USART1的基本參數(shù),開(kāi)啟定時(shí)器中斷后,接下來(lái)就要開(kāi)啟USART1的DMA。

    2024年02月03日
    瀏覽(17)
  • STM32入門筆記10_USART串口通信+案例:上位機(jī)控制LED亮滅(USART串口通信、TIM定時(shí)器、EXTI綜合案例)

    STM32入門筆記10_USART串口通信+案例:上位機(jī)控制LED亮滅(USART串口通信、TIM定時(shí)器、EXTI綜合案例)

    通信的目的: 將一個(gè)設(shè)備的數(shù)據(jù)傳送到另一個(gè)設(shè)備, 擴(kuò)展硬件系統(tǒng) 通信協(xié)議: 制定通信的規(guī)則, 通信雙方按照協(xié)議規(guī)則進(jìn)行數(shù)據(jù)收發(fā) 名稱 引腳 雙工 時(shí)鐘 電平 設(shè)備 USART TX、RX 全雙工 異步 單端 點(diǎn)對(duì)點(diǎn) I2C SCL、SDA 半雙工 同步 單端 多設(shè)備 SPI SCLK、MOSI、MISO、CS 全雙工 同步 單端

    2024年02月09日
    瀏覽(25)
  • 【嵌入式學(xué)習(xí)-STM32F103-USART串口通信】

    【嵌入式學(xué)習(xí)-STM32F103-USART串口通信】

    4-1 基本流程 4-2 整體代碼 4-2-1 main.c 4-2-2 Serial.c 4-2-3 Serial.h 5-1 查詢 5-2 中斷 5-3 整體代碼 5-3-1 main.c 5-3-2 Serial.c 5-3-3 Serial.h 6-1 使用狀態(tài)機(jī)接收數(shù)據(jù)包的思路 6-2 串口收發(fā)HEX數(shù)據(jù)包 6-2-1 main.c 6-2-2 Serial.c 6-2-3 Serial.h 6-3串口收發(fā)文本數(shù)據(jù)包 6-3-1 main.c 6-3-2 Serial.c 6-3-3 Serial.h 全雙工:打

    2024年02月15日
    瀏覽(64)
  • HAL庫(kù)STM32CUBEMX學(xué)習(xí)記錄(一)——USART(串口中斷收發(fā)數(shù)據(jù))

    HAL庫(kù)STM32CUBEMX學(xué)習(xí)記錄(一)——USART(串口中斷收發(fā)數(shù)據(jù))

    一、首先使用STM32CUBEMX新建一個(gè)工程 二、打開(kāi)工程文件 1.在usart.c中添加以下代碼 ?2.然后在最后面加入中斷回調(diào)函數(shù) 3.在usart.h文件中加入 ?4.新建一個(gè)cmd.c文件,創(chuàng)建命令check函數(shù) 5.在mian函數(shù)中的while(1)循環(huán)中調(diào)用USART1_Check(USART_RX_BUF)函數(shù) 6.最后串口初始化函數(shù)后打開(kāi)串口中

    2024年02月16日
    瀏覽(29)
  • STM32單片機(jī)(九)USART串口----第一節(jié):USART串口協(xié)議

    STM32單片機(jī)(九)USART串口----第一節(jié):USART串口協(xié)議

    ?? 專欄簡(jiǎn)介:本專欄記錄了從零學(xué)習(xí)單片機(jī)的過(guò)程,其中包括51單片機(jī)和STM32單片機(jī)兩部分;建議先學(xué)習(xí)51單片機(jī),其是STM32等高級(jí)單片機(jī)的基礎(chǔ);這樣再學(xué)習(xí)STM32時(shí)才能融會(huì)貫通。 ?? 專欄適用人群 :適用于想要從零基礎(chǔ)開(kāi)始學(xué)習(xí)入門單片機(jī),且有一定C語(yǔ)言基礎(chǔ)的的童鞋

    2024年02月16日
    瀏覽(165)
  • STM32單片機(jī)(九)USART串口----第三節(jié):USART串口實(shí)戰(zhàn)練習(xí)(串口發(fā)送)

    STM32單片機(jī)(九)USART串口----第三節(jié):USART串口實(shí)戰(zhàn)練習(xí)(串口發(fā)送)

    ?? 專欄簡(jiǎn)介:本專欄記錄了從零學(xué)習(xí)單片機(jī)的過(guò)程,其中包括51單片機(jī)和STM32單片機(jī)兩部分;建議先學(xué)習(xí)51單片機(jī),其是STM32等高級(jí)單片機(jī)的基礎(chǔ);這樣再學(xué)習(xí)STM32時(shí)才能融會(huì)貫通。 ?? 專欄適用人群 :適用于想要從零基礎(chǔ)開(kāi)始學(xué)習(xí)入門單片機(jī),且有一定C語(yǔ)言基礎(chǔ)的的童鞋

    2024年02月10日
    瀏覽(98)
  • STM32--USART串口

    STM32--USART串口

    通信接口 是指連接中央處理器(CPU)和標(biāo)準(zhǔn)通信子系統(tǒng)之間的接口,用于實(shí)現(xiàn)數(shù)據(jù)和控制信息在不同設(shè)備之間的傳輸和交換 。通信接口可以是硬件或軟件實(shí)現(xiàn),其目的是使不同設(shè)備之間能夠進(jìn)行有效地通信。 上圖是常見(jiàn)的通用通信類型。 雙工指的是接口能夠?qū)崿F(xiàn)雙向數(shù)據(jù)傳

    2024年02月11日
    瀏覽(22)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包