一、RS485介紹
二、RS485相關(guān)HAL庫(kù)驅(qū)動(dòng)介紹
三、RS485配置步驟
四、編程實(shí)戰(zhàn)
五、總結(jié)
串口、 UART、TTL、RS232、RS422、RS485關(guān)系
串口、UART、TTL、RS232、RS422和RS485之間的關(guān)系可以如此理解:
-
串口:是一個(gè)廣義術(shù)語(yǔ),通常指的是采用串行通信協(xié)議的接口,它可以包括多種具體的物理接口標(biāo)準(zhǔn)和邏輯電平標(biāo)準(zhǔn)。
-
UART(通用異步收發(fā)傳輸器):是一種集成電路,負(fù)責(zé)處理串行通信協(xié)議中的時(shí)序生成、數(shù)據(jù)編碼解碼等功能,是嵌入式系統(tǒng)中常見(jiàn)的用于實(shí)現(xiàn)串行通信的硬件模塊。UART本身并不規(guī)定具體的電氣特性,而是產(chǎn)生遵循串行通信時(shí)序的信號(hào)(如啟動(dòng)位、數(shù)據(jù)位、校驗(yàn)位和停止位)。
-
TTL(晶體管-晶體管邏輯)電平:是一種邏輯電平標(biāo)準(zhǔn),通常在集成電路內(nèi)部或者集成電路之間近距離通信時(shí)使用,它的高低電平相對(duì)較低,通常為3.3V或5V表示邏輯1,0V表示邏輯0。
-
RS232:是一種早期廣泛應(yīng)用于計(jì)算機(jī)和終端設(shè)備之間的串行通信接口標(biāo)準(zhǔn),它規(guī)定了詳細(xì)的電氣特性,如邏輯1(負(fù)電壓,通常為-3V-15V)和邏輯0(正電壓,通常為+3V+15V)。盡管邏輯電平與TTL電平不同,但可以通過(guò)電平轉(zhuǎn)換器將UART產(chǎn)生的TTL電平轉(zhuǎn)換為RS232電平進(jìn)行遠(yuǎn)距離傳輸。
-
RS422:是一種全雙工、差分傳輸?shù)拇型ㄐ艠?biāo)準(zhǔn),它具有較高的抗干擾能力和較長(zhǎng)的傳輸距離,支持多點(diǎn)傳輸,每個(gè)信號(hào)都有明確的方向(發(fā)送和接收分離),常用于工業(yè)控制領(lǐng)域。
-
RS485:也是一種差分傳輸?shù)拇型ㄐ艠?biāo)準(zhǔn),與RS422類似,但增加了多點(diǎn)通信的能力,支持多個(gè)設(shè)備通過(guò)同一條線路進(jìn)行通信,但同一時(shí)間內(nèi)只能有一個(gè)設(shè)備發(fā)送數(shù)據(jù)。
綜上所述,UART是生成串行通信時(shí)序的硬件模塊,而TTL、RS232、RS422和RS485則分別代表了不同的電氣接口標(biāo)準(zhǔn)和邏輯電平標(biāo)準(zhǔn)。在實(shí)際應(yīng)用中,UART產(chǎn)生的TTL電平信號(hào)通常需要通過(guò)電平轉(zhuǎn)換器轉(zhuǎn)化為RS232、RS422或RS485標(biāo)準(zhǔn)的信號(hào),以便在不同的物理環(huán)境中進(jìn)行可靠的串行通信。
串口基礎(chǔ)協(xié)議 和 MODBUS協(xié)議
串口基礎(chǔ)協(xié)議(Serial Port Basic Protocol)通常指的是用于串行通信的基本規(guī)則,它定義了數(shù)據(jù)在串行鏈路上如何進(jìn)行傳輸,包括但不限于以下幾個(gè)關(guān)鍵要素:
- 通信時(shí)序:?jiǎn)?dòng)位、數(shù)據(jù)位(一般為5到8位)、奇偶校驗(yàn)位(可選)和停止位(1到2位)。
- 波特率:每秒傳輸?shù)奈粩?shù),常見(jiàn)的有9600、19200、38400、115200等。
- 通信方向:可以是全雙工(同時(shí)發(fā)送和接收數(shù)據(jù))、半雙工(同一時(shí)間只能進(jìn)行發(fā)送或接收)或單工(只能發(fā)送或只能接收)。
而MODBUS協(xié)議則建立在串口基礎(chǔ)協(xié)議之上,是一種應(yīng)用層協(xié)議,用于在不同設(shè)備間進(jìn)行數(shù)據(jù)交換,特別是工業(yè)控制系統(tǒng)中的現(xiàn)場(chǎng)設(shè)備如PLC、智能儀表、傳感器和執(zhí)行器等。MODBUS協(xié)議的特點(diǎn)包括:
- 主從結(jié)構(gòu):網(wǎng)絡(luò)中有一個(gè)主設(shè)備(主控制器)向多個(gè)從設(shè)備發(fā)起請(qǐng)求,從設(shè)備響應(yīng)請(qǐng)求。
- 功能碼:MODBUS協(xié)議定義了一系列功能碼,每個(gè)功能碼對(duì)應(yīng)一種操作,如讀取線圈狀態(tài)、寄存器值,寫(xiě)入線圈狀態(tài)、寄存器值等。
- 數(shù)據(jù)組織:MODBUS協(xié)議中的數(shù)據(jù)傳輸包括設(shè)備地址、功能碼、數(shù)據(jù)區(qū)(數(shù)據(jù)長(zhǎng)度根據(jù)功能碼定義)和校驗(yàn)碼(如RTU模式下的CRC校驗(yàn))。
在實(shí)際應(yīng)用中,串口基礎(chǔ)協(xié)議提供的是物理層和鏈路層的通信基礎(chǔ),而MODBUS協(xié)議則是更高層次的應(yīng)用層協(xié)議,它規(guī)定了如何在串口通信的基礎(chǔ)上構(gòu)造有意義的消息結(jié)構(gòu),從而實(shí)現(xiàn)設(shè)備間復(fù)雜的控制和數(shù)據(jù)交換。
MODBUS協(xié)議
MODBUS協(xié)議是一種廣泛應(yīng)用于工業(yè)控制領(lǐng)域的串行通信協(xié)議,最初由Modicon公司于1979年發(fā)布,現(xiàn)已成為一種通用的工業(yè)標(biāo)準(zhǔn)協(xié)議。MODBUS允許不同廠商的設(shè)備通過(guò)串行線路或以太網(wǎng)進(jìn)行通信,從而實(shí)現(xiàn)了不同設(shè)備之間的互操作性。
MODBUS協(xié)議主要特點(diǎn):
- 主從架構(gòu):網(wǎng)絡(luò)中只有一個(gè)主設(shè)備(如PLC或HMI),可以向多個(gè)從設(shè)備(如傳感器、執(zhí)行器、其他控制器等)發(fā)送請(qǐng)求并接收響應(yīng)。
- 功能碼:MODBUS協(xié)議定義了一系列功能碼,用于執(zhí)行讀寫(xiě)操作,如讀取線圈狀態(tài)、寄存器值、輸入狀態(tài),寫(xiě)入線圈狀態(tài)、寄存器值等。
- 數(shù)據(jù)傳輸模式:MODBUS支持ASCII、RTU(Remote Terminal Unit)和TCP/IP三種傳輸模式。其中,ASCII模式適合于低速通信和易于調(diào)試,RTU模式適用于高速通信且效率較高,TCP/IP模式則支持在網(wǎng)絡(luò)環(huán)境中傳輸MODBUS協(xié)議。
MODBUS協(xié)議的數(shù)據(jù)幀結(jié)構(gòu):
- MODBUS RTU模式:包含設(shè)備地址、功能碼、數(shù)據(jù)區(qū)(長(zhǎng)度根據(jù)功能碼決定)、CRC校驗(yàn)碼。
- MODBUS ASCII模式:在RTU模式基礎(chǔ)上增加了起始字符、結(jié)束字符和LRC校驗(yàn)碼。
- MODBUS TCP/IP模式:以TCP報(bào)文的形式封裝MODBUS數(shù)據(jù),包含設(shè)備地址(在TCP連接中隱含,不再在報(bào)文中攜帶)、功能碼、數(shù)據(jù)區(qū)、CRC校驗(yàn)碼(TCP層不需要,MODBUS-TCP層可選)。
MODBUS協(xié)議在實(shí)際應(yīng)用中,主設(shè)備可以向從設(shè)備發(fā)出讀寫(xiě)請(qǐng)求,從設(shè)備在接收到請(qǐng)求后根據(jù)功能碼執(zhí)行相應(yīng)操作,并將結(jié)果返回給主設(shè)備。由于其簡(jiǎn)潔、通用和開(kāi)放的特性,MODBUS在工業(yè)自動(dòng)化、樓宇自動(dòng)化、能源管理系統(tǒng)等多個(gè)領(lǐng)域得到廣泛應(yīng)用。
一、RS485介紹
RS485是一種串行通信標(biāo)準(zhǔn),它利用差分信號(hào)對(duì)(通常是一對(duì)非絕緣的導(dǎo)線A和B)來(lái)傳輸數(shù)據(jù),由于其差分信號(hào)的性質(zhì),使得它具有很強(qiáng)的抗共模干擾能力,特別適用于工業(yè)控制環(huán)境,能夠確保在長(zhǎng)距離、復(fù)雜電磁環(huán)境下穩(wěn)定通信。
RS485接口允許構(gòu)建大型分布式系統(tǒng),支持多達(dá)32個(gè)節(jié)點(diǎn)(在某些條件下甚至更多)掛接在同一總線上,并且每個(gè)節(jié)點(diǎn)既可以作為主設(shè)備也可以作為從設(shè)備,非常適合構(gòu)建多點(diǎn)對(duì)多點(diǎn)的網(wǎng)絡(luò)架構(gòu)。
串口基礎(chǔ)協(xié)議是指最底層的數(shù)據(jù)傳輸規(guī)則,包括但不限于數(shù)據(jù)位的定義(例如8位或9位數(shù)據(jù)位)、波特率設(shè)置、停止位數(shù)量以及奇偶校驗(yàn)等參數(shù),這些參數(shù)共同決定了數(shù)據(jù)的基本包格式。
而MODBUS協(xié)議是在串口基礎(chǔ)協(xié)議之上的應(yīng)用層協(xié)議,它定義了更高級(jí)別的數(shù)據(jù)打包、尋址、錯(cuò)誤檢測(cè)以及數(shù)據(jù)交換的具體過(guò)程。MODBUS協(xié)議利用串口基礎(chǔ)協(xié)議提供的傳輸機(jī)制,將數(shù)據(jù)按照特定的幀格式進(jìn)行組織,從而實(shí)現(xiàn)在多個(gè)設(shè)備間的報(bào)文交換和設(shè)備控制。MODBUS協(xié)議因其開(kāi)放性和通用性,在工業(yè)自動(dòng)化領(lǐng)域得到了廣泛應(yīng)用。
總結(jié)RS485接口的關(guān)鍵特性如下:
- 通信方式:半雙工或全雙工(取決于具體應(yīng)用配置)
- 信號(hào)線:一對(duì)差分信號(hào)線(A和B或+和-)
- 電平標(biāo)準(zhǔn):邏輯“1”時(shí),A相對(duì)于B為正,邏輯“0”時(shí)相反,典型差分電壓范圍為±200mV至±2V
- 拓?fù)浣Y(jié)構(gòu):總線型或星型(通過(guò)有源或無(wú)源轉(zhuǎn)換器)
- 通信距離:長(zhǎng)達(dá)1200米(取決于布線質(zhì)量和波特率)
- 通訊速率:最高可達(dá)10Mbps,但常用速率通常在9600bps至115200bps之間
- 抗干擾能力:強(qiáng),因?yàn)椴捎貌罘中盘?hào)傳輸
- 組網(wǎng)功能:強(qiáng)大,可支持多節(jié)點(diǎn)網(wǎng)絡(luò)
- 接口安全性:接口電平低,相對(duì)其他標(biāo)準(zhǔn)(如RS232)更不容易損壞芯片
通過(guò)上述特性,RS485不僅適合長(zhǎng)距離、高速率傳輸,而且具備良好的噪聲抑制能力和大規(guī)模網(wǎng)絡(luò)部署能力。
在RS485總線連接中,組件之間的連接和作用如下:
-
CPU:中央處理器,負(fù)責(zé)控制整個(gè)系統(tǒng)的運(yùn)行和數(shù)據(jù)處理。
-
UART控制器:集成在CPU內(nèi)部或外部的通用異步收發(fā)傳輸器,用于生成和解析串行通信數(shù)據(jù)流。
-
TXD/RXD連接:
- TXD(Transmit Data):UART控制器的發(fā)送數(shù)據(jù)線,通常連接到485收發(fā)器的接收端(如DE/RE引腳禁能時(shí)的接收端或RO引腳)。
- RXD(Receive Data):UART控制器的接收數(shù)據(jù)線,通常連接到485收發(fā)器的發(fā)送端(如DI引腳)。
-
485收發(fā)器:
- 如SP3485、TP8485E、MAX485等,這類芯片用于實(shí)現(xiàn)TTL電平與RS485差分信號(hào)電平之間的轉(zhuǎn)換,并具備收發(fā)控制功能。
- DE(Driver Enable)/RE(Receiver Enable):控制485收發(fā)器工作在發(fā)送或接收模式,防止在同一時(shí)刻既發(fā)送又接收導(dǎo)致沖突。
- DI(Data Input):接收來(lái)自UART的TTL電平信號(hào),并轉(zhuǎn)換為RS485差分信號(hào)。
- RO(Receiver Output):將接收到的RS485差分信號(hào)轉(zhuǎn)換為T(mén)TL電平,發(fā)送給UART。
-
485_A/485_B:
- 這是RS485總線的差分信號(hào)線,485_A和485_B兩根線通過(guò)雙絞線連接到所有的RS485設(shè)備,確保信號(hào)質(zhì)量良好。
-
匹配電阻:
- 在485_A和485_B的兩端(或靠近設(shè)備端)通常會(huì)并聯(lián)一個(gè)120歐姆左右的終端電阻,目的是吸收信號(hào)反射,確保RS485總線的穩(wěn)定性,抑制噪聲,增強(qiáng)信號(hào)質(zhì)量。
總之,通過(guò)上述部件的連接和協(xié)同工作,CPU得以通過(guò)UART控制器與RS485總線上的其它設(shè)備進(jìn)行可靠的數(shù)據(jù)交換。
RS485通信電路中各引腳的功能以及信號(hào)傳輸規(guī)則如下:
-
RO (Receiver Output):
RO是接收器輸出端,當(dāng)RS485總線上的差分信號(hào)滿足一定的閾值條件時(shí),RO會(huì)根據(jù)接收到的差分信號(hào)輸出對(duì)應(yīng)的邏輯電平。具體來(lái)說(shuō):- 如果
A - B
的電壓差大于等于 +0.2V,表明總線上接收到了邏輯“1”,因此RO輸出高電平(邏輯“1”)。 - 如果
A - B
的電壓差小于等于 -0.2V,表明總線上接收到了邏輯“0”,此時(shí)RO輸出低電平(邏輯“0”)。
- 如果
-
RE (Receiver Enable):
RE是接收器使能端,低電平有效。當(dāng)RE為低電平時(shí),允許接收器工作,可以正常接收總線上的數(shù)據(jù);反之,當(dāng)RE為高電平時(shí),接收器被禁止接收數(shù)據(jù)。 -
DE (Driver Enable):
DE是驅(qū)動(dòng)器使能端,高電平有效。當(dāng)DE為高電平時(shí),允許驅(qū)動(dòng)器工作,可以向總線發(fā)送數(shù)據(jù);反之,當(dāng)DE為低電平時(shí),驅(qū)動(dòng)器停止發(fā)送數(shù)據(jù),進(jìn)入高阻態(tài),不影響總線上的其他設(shè)備通信。 -
DI (Driver Input):
DI是驅(qū)動(dòng)器輸入端,與微控制器的TTL/CMOS電平輸出相連,用于決定驅(qū)動(dòng)器要發(fā)送的數(shù)據(jù):- 當(dāng)DI為低電平時(shí),驅(qū)動(dòng)器會(huì)讓A線變低,B線變高,從而在總線上形成邏輯“0”的差分信號(hào)。
- 當(dāng)DI為高電平時(shí),驅(qū)動(dòng)器會(huì)讓A線變高,B線變低,從而在總線上形成邏輯“1”的差分信號(hào)。
-
A 和 B:
這是對(duì)稱的差分信號(hào)線,A和B通常通過(guò)雙絞線連接,共同構(gòu)成RS485通信的物理層基礎(chǔ)。
關(guān)于R19和R22這兩個(gè)偏置電阻的作用:
在某些設(shè)計(jì)中,為了避免總線在沒(méi)有數(shù)據(jù)傳輸時(shí)處于不確定狀態(tài),會(huì)在A線和B線之間設(shè)置偏置電阻(如R19和R22),使得在總線空閑時(shí),A線與B線之間有一個(gè)固定的正向偏移電壓(大于0.2V)。這樣做的目的是確保即使在沒(méi)有明確數(shù)據(jù)信號(hào)的情況下,也不會(huì)因?yàn)樵肼暬蚱渌蛘`判為有效的邏輯信號(hào),增強(qiáng)了通信的可靠性。在實(shí)際應(yīng)用中,這些偏置電阻的選擇和是否需要取決于具體的硬件設(shè)計(jì)需求和所使用的RS485收發(fā)器芯片的特性。
485通信波形圖示例:
在485通信中,發(fā)送端和接收端的信號(hào)波形如下:
發(fā)送端波形圖示:
-
發(fā)送邏輯1時(shí):
- A線的波形顯示為高電平(接近電源電壓)。
- B線的波形顯示為低電平(接近接地電平)。
-
發(fā)送邏輯0時(shí):
- A線的波形顯示為低電平。
- B線的波形顯示為高電平。
接收端波形圖示:
-
判斷邏輯1時(shí):
- A線的電壓高于B線電壓至少0.2V以上,例如A線為3.5V,B線為1V,則(A-B)=2.5V≥+0.2V。
- 在這種情況下,接收器輸出RO會(huì)被置為高電平,表示接收到的是邏輯“1”。
-
判斷邏輯0時(shí):
- B線的電壓高于A線電壓至少0.2V以上,例如B線為3.5V,A線為1V,則(B-A)=-2.5V≤-0.2V。
- 在這種情況下,接收器輸出RO會(huì)被置為低電平,表示接收到的是邏輯“0”。
485通信采用差分信號(hào)傳輸,這種設(shè)計(jì)有效地提高了抗干擾能力,允許多個(gè)設(shè)備共享相同的通信總線,并且能夠在長(zhǎng)距離和惡劣環(huán)境下保持穩(wěn)定的通信。在實(shí)際的波形圖中,可以看到A線和B線的波形互補(bǔ),并且根據(jù)他們的電壓差來(lái)確定傳輸?shù)倪壿嬛怠?br>
二、RS485相關(guān)HAL庫(kù)驅(qū)動(dòng)介紹
實(shí)際上,對(duì)于RS485通信,STM32的HAL庫(kù)并沒(méi)有直接提供名為HAL_RS485_xxx
的特定函數(shù),而是通過(guò)配置通用的UART接口來(lái)實(shí)現(xiàn)RS485通信。在STM32 HAL庫(kù)中,使用通用的UART接口函數(shù)來(lái)驅(qū)動(dòng)RS485,同時(shí)需要搭配額外的RS485收發(fā)器(如SP3485、MAX485等)進(jìn)行電平轉(zhuǎn)換。以下是與RS485通信密切相關(guān)的HAL庫(kù)函數(shù)及其功能描述:
-
__HAL_RCC_USARTx_CLK_ENABLE(…):
- 關(guān)聯(lián)寄存器:RCC_APBxPeriphClockCmd()函數(shù)間接影響USARTx的時(shí)鐘使能寄存器(如APB1ENR/APB2ENR)。
- 功能描述:使能指定USART(例如USART1、USART2等)的時(shí)鐘,這是使用任何USART功能之前的必要步驟。
-
HAL_UART_Init(…):
- 關(guān)聯(lián)寄存器:USART_CR1、USART_CR2、USART_CR3等。
- 功能描述:初始化指定的USART外設(shè),配置諸如波特率、數(shù)據(jù)位數(shù)、停止位、奇偶校驗(yàn)、模式(如異步模式)、硬件流控制等各種參數(shù)。
-
__HAL_UART_ENABLE_IT(…):
- 關(guān)聯(lián)寄存器:USART_CR1(以及USART_CR2和USART_CR3,視中斷類型而定)。
- 功能描述:使能USART的相關(guān)中斷,如接收數(shù)據(jù)寄存器非空中斷(RXNE)、發(fā)送數(shù)據(jù)寄存器為空中斷(TXE)等,這對(duì)RS485通信中的數(shù)據(jù)收發(fā)中斷處理非常重要。
-
HAL_UART_Receive(…):
- 關(guān)聯(lián)寄存器:USART_DR(數(shù)據(jù)寄存器)。
- 功能描述:通過(guò)DMA或中斷方式從USART接收數(shù)據(jù),適用于RS485接收數(shù)據(jù)階段。
-
HAL_UART_Transmit(…):
- 關(guān)聯(lián)寄存器:USART_DR。
- 功能描述:通過(guò)DMA或中斷方式向USART發(fā)送數(shù)據(jù),適用于RS485發(fā)送數(shù)據(jù)階段。
-
__HAL_UART_GET_FLAG(…):
- 關(guān)聯(lián)寄存器:USART_SR(狀態(tài)寄存器)。
- 功能描述:查詢USART當(dāng)前的狀態(tài)標(biāo)志位,例如判斷是否已完成數(shù)據(jù)發(fā)送(TC=Transmission Complete)、是否接收到新的數(shù)據(jù)(RXNE=Received Data Not Empty)等。
針對(duì)RS485通信,還需配置RS485收發(fā)器的控制引腳(如DE/RE)來(lái)切換RS485模式(發(fā)送或接收)。這部分通常不在HAL庫(kù)提供的UART函數(shù)內(nèi),需要在應(yīng)用層手動(dòng)控制或者通過(guò)GPIO中斷等方式進(jìn)行管理。此外,為了正確進(jìn)行RS485通信,還要考慮總線的信號(hào)線連接、終端電阻匹配等問(wèn)題。
三、RS485配置步驟
RS485配置步驟,基于STM32 HAL庫(kù)進(jìn)行,可以細(xì)化為以下步驟:
-
配置串口工作參數(shù)
- 使用
HAL_UART_Init()
函數(shù)初始化串口。在這個(gè)函數(shù)中,你需要提供一個(gè)指向UART_HandleTypeDef
結(jié)構(gòu)體的指針,并在結(jié)構(gòu)體內(nèi)填入串口的工作參數(shù),如波特率、數(shù)據(jù)位數(shù)、停止位數(shù)、奇偶校驗(yàn)等。
- 使用
-
串口底層初始化
- 配置與串口相關(guān)的GPIO引腳,設(shè)置它們?yōu)閺?fù)用功能模式,并配置為AF(Alternate Function)對(duì)應(yīng)的串口功能。
- 配置NVIC(Nested Vectored Interrupt Controller),為串口的中斷請(qǐng)求分配優(yōu)先級(jí),并關(guān)聯(lián)中斷服務(wù)函數(shù)。
- 使能串口對(duì)應(yīng)的時(shí)鐘,通過(guò)
__HAL_RCC_USARTx_CLK_ENABLE()
函數(shù)啟用相應(yīng)USART的時(shí)鐘。
-
開(kāi)啟串口異步接收中斷
- 通過(guò)
__HAL_UART_ENABLE_IT()
函數(shù)啟用串口的接收中斷,例如啟用UART_IT_RXNE
,這樣當(dāng)接收數(shù)據(jù)寄存器非空時(shí),會(huì)產(chǎn)生中斷請(qǐng)求。
- 通過(guò)
-
設(shè)置中斷優(yōu)先級(jí)并使能中斷
- 使用
HAL_NVIC_SetPriority()
函數(shù)設(shè)置串口中斷的服務(wù)優(yōu)先級(jí)。 - 通過(guò)
HAL_NVIC_EnableIRQ()
函數(shù)使能串口對(duì)應(yīng)的中斷請(qǐng)求,例如USART1_IRQn
。
- 使用
-
編寫(xiě)中斷服務(wù)函數(shù)
- 編寫(xiě)串口中斷服務(wù)函數(shù),如
USARTx_IRQHandler()
(其中x
代表具體的串口號(hào),如USART1、USART2等)。 - 在中斷服務(wù)函數(shù)內(nèi)部,調(diào)用
HAL_UART_IRQHandler()
函數(shù)來(lái)處理中斷,特別是如果有數(shù)據(jù)接收,HAL_UART_Receive_IT()
或HAL_UART_Receive_DMA()
可用于異步接收數(shù)據(jù)。
- 編寫(xiě)串口中斷服務(wù)函數(shù),如
-
串口數(shù)據(jù)發(fā)送
- 發(fā)送數(shù)據(jù)時(shí),通過(guò)寫(xiě)入U(xiǎn)SART的數(shù)據(jù)寄存器(USART_DR)來(lái)發(fā)送數(shù)據(jù)。
- 使用
HAL_UART_Transmit()
函數(shù)發(fā)送數(shù)據(jù),該函數(shù)在數(shù)據(jù)發(fā)送完畢后會(huì)返回成功標(biāo)志,適合在非中斷模式下使用;若采用中斷模式發(fā)送數(shù)據(jù),可使用HAL_UART_Transmit_IT()
或HAL_UART_Transmit_DMA()
函數(shù)。
對(duì)于RS485通信,除了上述常規(guī)的UART配置之外,還需額外控制DE(Driver Enable)或RE(Receiver Enable)引腳,以切換RS485收發(fā)器的工作模式。在發(fā)送數(shù)據(jù)時(shí),使能DE引腳以便驅(qū)動(dòng)總線;在接收數(shù)據(jù)時(shí),關(guān)閉DE引腳并開(kāi)啟RE引腳。這部分控制通常通過(guò)GPIO進(jìn)行操作,并非直接在HAL庫(kù)的UART接口函數(shù)內(nèi)完成。
四、編程實(shí)戰(zhàn)
RS485源碼
rs485.c
#include "./BSP/RS485/rs485.h"
#include "./SYSTEM/delay/delay.h"
UART_HandleTypeDef g_rs458_handler; /* RS485控制句柄(串口) */
#ifdef RS485_EN_RX /* 如果使能了接收 */
uint8_t g_RS485_rx_buf[RS485_REC_LEN]; /* 接收緩沖, 最大 RS485_REC_LEN 個(gè)字節(jié). */
uint8_t g_RS485_rx_cnt = 0; /* 接收到的數(shù)據(jù)長(zhǎng)度 */
void RS485_UX_IRQHandler(void)
{
uint8_t res;
if ((__HAL_UART_GET_FLAG(&g_rs458_handler, UART_FLAG_RXNE) != RESET)) /* 接收到數(shù)據(jù) */
{
HAL_UART_Receive(&g_rs458_handler, &res, 1, 1000);
if (g_RS485_rx_cnt < RS485_REC_LEN) /* 緩沖區(qū)未滿 */
{
g_RS485_rx_buf[g_RS485_rx_cnt] = res; /* 記錄接收到的值 */
g_RS485_rx_cnt++; /* 接收數(shù)據(jù)增加1 */
}
}
}
#endif
/**
* @brief RS485初始化函數(shù)
* @note 該函數(shù)主要是初始化串口
* @param baudrate: 波特率, 根據(jù)自己需要設(shè)置波特率值
* @retval 無(wú)
*/
void rs485_init(uint32_t baudrate)
{
/* IO 及 時(shí)鐘配置 */
RS485_RE_GPIO_CLK_ENABLE(); /* 使能 RS485_RE 腳時(shí)鐘 */
RS485_TX_GPIO_CLK_ENABLE(); /* 使能 串口TX腳 時(shí)鐘 */
RS485_RX_GPIO_CLK_ENABLE(); /* 使能 串口RX腳 時(shí)鐘 */
RS485_UX_CLK_ENABLE(); /* 使能 串口 時(shí)鐘 */
GPIO_InitTypeDef gpio_initure;
gpio_initure.Pin = RS485_TX_GPIO_PIN;
gpio_initure.Mode = GPIO_MODE_AF_PP;
gpio_initure.Pull = GPIO_PULLUP;
gpio_initure.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(RS485_TX_GPIO_PORT, &gpio_initure); /* 串口TX 腳 模式設(shè)置 */
gpio_initure.Pin = RS485_RX_GPIO_PIN;
gpio_initure.Mode = GPIO_MODE_AF_INPUT;
HAL_GPIO_Init(RS485_RX_GPIO_PORT, &gpio_initure); /* 串口RX 腳 必須設(shè)置成輸入模式 */
gpio_initure.Pin = RS485_RE_GPIO_PIN;
gpio_initure.Mode = GPIO_MODE_OUTPUT_PP;
gpio_initure.Pull = GPIO_PULLUP;
gpio_initure.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(RS485_RE_GPIO_PORT, &gpio_initure); /* RS485_RE 腳 模式設(shè)置 */
/* USART 初始化設(shè)置 */
g_rs458_handler.Instance = RS485_UX; /* 選擇485對(duì)應(yīng)的串口 */
g_rs458_handler.Init.BaudRate = baudrate; /* 波特率 */
g_rs458_handler.Init.WordLength = UART_WORDLENGTH_8B; /* 字長(zhǎng)為8位數(shù)據(jù)格式 */
g_rs458_handler.Init.StopBits = UART_STOPBITS_1; /* 一個(gè)停止位 */
g_rs458_handler.Init.Parity = UART_PARITY_NONE; /* 無(wú)奇偶校驗(yàn)位 */
g_rs458_handler.Init.HwFlowCtl = UART_HWCONTROL_NONE; /* 無(wú)硬件流控 */
g_rs458_handler.Init.Mode = UART_MODE_TX_RX; /* 收發(fā)模式 */
HAL_UART_Init(&g_rs458_handler); /* HAL_UART_Init()會(huì)使能UART2 */
#if RS485_EN_RX /* 如果使能了接收 */
/* 使能接收中斷 */
__HAL_UART_ENABLE_IT(&g_rs458_handler, UART_IT_RXNE); /* 開(kāi)啟接收中斷 */
HAL_NVIC_EnableIRQ(RS485_UX_IRQn); /* 使能USART2中斷 */
HAL_NVIC_SetPriority(RS485_UX_IRQn, 3, 3); /* 搶占優(yōu)先級(jí)3,子優(yōu)先級(jí)3 */
#endif
RS485_RE(0); /* 默認(rèn)為接收模式 */
}
/**
* @brief RS485發(fā)送len個(gè)字節(jié)
* @param buf : 發(fā)送緩存區(qū)首地址
* @param len : 發(fā)送的字節(jié)數(shù)(為了和本代碼的接收匹配,這里建議不要超過(guò) RS485_REC_LEN 個(gè)字節(jié))
* @retval 無(wú)
*/
void rs485_send_data(uint8_t *buf, uint8_t len)
{
RS485_RE(1); /* 進(jìn)入發(fā)送模式 */
HAL_UART_Transmit(&g_rs458_handler, buf, len, 1000); /* 串口2發(fā)送數(shù)據(jù) */
g_RS485_rx_cnt = 0;
RS485_RE(0); /* 進(jìn)入接收模式 */
}
/**
* @brief RS485查詢接收到的數(shù)據(jù)
* @param buf : 接收緩沖區(qū)首地址
* @param len : 接收到的數(shù)據(jù)長(zhǎng)度
* @arg 0 , 表示沒(méi)有接收到任何數(shù)據(jù)
* @arg 其他, 表示接收到的數(shù)據(jù)長(zhǎng)度
* @retval 無(wú)
*/
void rs485_receive_data(uint8_t *buf, uint8_t *len)
{
uint8_t rxlen = g_RS485_rx_cnt;
uint8_t i = 0;
*len = 0; /* 默認(rèn)為0 */
delay_ms(10); /* 等待10ms,連續(xù)超過(guò)10ms沒(méi)有接收到一個(gè)數(shù)據(jù),則認(rèn)為接收結(jié)束 */
if (rxlen == g_RS485_rx_cnt && rxlen) /* 接收到了數(shù)據(jù),且接收完成了 */
{
for (i = 0; i < rxlen; i++)
{
buf[i] = g_RS485_rx_buf[i];
}
*len = g_RS485_rx_cnt; /* 記錄本次數(shù)據(jù)長(zhǎng)度 */
g_RS485_rx_cnt = 0; /* 清零 */
}
}
rs485.h
#ifndef __RS485_H
#define __RS485_H
#include "./SYSTEM/sys/sys.h"
/******************************************************************************************/
/* RS485 引腳 和 串口 定義
* 默認(rèn)是針對(duì)RS485的.
*/
#define RS485_RE_GPIO_PORT GPIOD
#define RS485_RE_GPIO_PIN GPIO_PIN_7
#define RS485_RE_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOD_CLK_ENABLE(); }while(0) /* PD口時(shí)鐘使能 */
#define RS485_TX_GPIO_PORT GPIOA
#define RS485_TX_GPIO_PIN GPIO_PIN_2
#define RS485_TX_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0) /* PA口時(shí)鐘使能 */
#define RS485_RX_GPIO_PORT GPIOA
#define RS485_RX_GPIO_PIN GPIO_PIN_3
#define RS485_RX_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0) /* PA口時(shí)鐘使能 */
#define RS485_UX USART2
#define RS485_UX_IRQn USART2_IRQn
#define RS485_UX_IRQHandler USART2_IRQHandler
#define RS485_UX_CLK_ENABLE() do{ __HAL_RCC_USART2_CLK_ENABLE(); }while(0) /* USART2 時(shí)鐘使能 */
/******************************************************************************************/
/* 控制RS485_RE腳, 控制RS485發(fā)送/接收狀態(tài)
* RS485_RE = 0, 進(jìn)入接收模式
* RS485_RE = 1, 進(jìn)入發(fā)送模式
*/
#define RS485_RE(x) do{ x ? \
HAL_GPIO_WritePin(RS485_RE_GPIO_PORT, RS485_RE_GPIO_PIN, GPIO_PIN_SET) : \
HAL_GPIO_WritePin(RS485_RE_GPIO_PORT, RS485_RE_GPIO_PIN, GPIO_PIN_RESET); \
}while(0)
#define RS485_REC_LEN 64 /* 定義最大接收字節(jié)數(shù) 64 */
#define RS485_EN_RX 1 /* 使能(1)/禁止(0)RS485接收 */
extern uint8_t g_RS485_rx_buf[RS485_REC_LEN]; /* 接收緩沖,最大RS485_REC_LEN個(gè)字節(jié) */
extern uint8_t g_RS485_rx_cnt; /* 接收數(shù)據(jù)長(zhǎng)度 */
void rs485_init( uint32_t baudrate); /* RS485初始化 */
void rs485_send_data(uint8_t *buf, uint8_t len); /* RS485發(fā)送數(shù)據(jù) */
void rs485_receive_data(uint8_t *buf, uint8_t *len);/* RS485接收數(shù)據(jù) */
#endif
usart.c
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
/* 如果使用os,則包括下面的頭文件即可. */
#if SYS_SUPPORT_OS
#include "includes.h" /* os 使用 */
#endif
/******************************************************************************************/
/* 加入以下代碼, 支持printf函數(shù), 而不需要選擇use MicroLIB */
#if 1
#if (__ARMCC_VERSION >= 6010050) /* 使用AC6編譯器時(shí) */
__asm(".global __use_no_semihosting\n\t"); /* 聲明不使用半主機(jī)模式 */
__asm(".global __ARM_use_no_argv \n\t"); /* AC6下需要聲明main函數(shù)為無(wú)參數(shù)格式,否則部分例程可能出現(xiàn)半主機(jī)模式 */
#else
/* 使用AC5編譯器時(shí), 要在這里定義__FILE 和 不使用半主機(jī)模式 */
#pragma import(__use_no_semihosting)
struct __FILE
{
int handle;
/* Whatever you require here. If the only file you are using is */
/* standard output using printf() for debugging, no file handling */
/* is required. */
};
#endif
/* 不使用半主機(jī)模式,至少需要重定義_ttywrch\_sys_exit\_sys_command_string函數(shù),以同時(shí)兼容AC6和AC5模式 */
int _ttywrch(int ch)
{
ch = ch;
return ch;
}
/* 定義_sys_exit()以避免使用半主機(jī)模式 */
void _sys_exit(int x)
{
x = x;
}
char *_sys_command_string(char *cmd, int len)
{
return NULL;
}
/* FILE 在 stdio.h里面定義. */
FILE __stdout;
/* MDK下需要重定義fputc函數(shù), printf函數(shù)最終會(huì)通過(guò)調(diào)用fputc輸出字符串到串口 */
int fputc(int ch, FILE *f)
{
while ((USART_UX->SR & 0X40) == 0); /* 等待上一個(gè)字符發(fā)送完成 */
USART_UX->DR = (uint8_t)ch; /* 將要發(fā)送的字符 ch 寫(xiě)入到DR寄存器 */
return ch;
}
#endif
/******************************************************************************************/
#if USART_EN_RX /*如果使能了接收*/
/* 接收緩沖, 最大USART_REC_LEN個(gè)字節(jié). */
uint8_t g_usart_rx_buf[USART_REC_LEN];
/* 接收狀態(tài)
* bit15, 接收完成標(biāo)志
* bit14, 接收到0x0d
* bit13~0, 接收到的有效字節(jié)數(shù)目
*/
uint16_t g_usart_rx_sta = 0;
uint8_t g_rx_buffer[RXBUFFERSIZE]; /* HAL庫(kù)使用的串口接收緩沖 */
UART_HandleTypeDef g_uart1_handle; /* UART句柄 */
/**
* @brief 串口X初始化函數(shù)
* @param baudrate: 波特率, 根據(jù)自己需要設(shè)置波特率值
* @note 注意: 必須設(shè)置正確的時(shí)鐘源, 否則串口波特率就會(huì)設(shè)置異常.
* 這里的USART的時(shí)鐘源在sys_stm32_clock_init()函數(shù)中已經(jīng)設(shè)置過(guò)了.
* @retval 無(wú)
*/
void usart_init(uint32_t baudrate)
{
/* UART 初始化設(shè)置*/
g_uart1_handle.Instance = USART_UX; /* USART_UX */
g_uart1_handle.Init.BaudRate = baudrate; /* 波特率 */
g_uart1_handle.Init.WordLength = UART_WORDLENGTH_8B; /* 字長(zhǎng)為8位數(shù)據(jù)格式 */
g_uart1_handle.Init.StopBits = UART_STOPBITS_1; /* 一個(gè)停止位 */
g_uart1_handle.Init.Parity = UART_PARITY_NONE; /* 無(wú)奇偶校驗(yàn)位 */
g_uart1_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE; /* 無(wú)硬件流控 */
g_uart1_handle.Init.Mode = UART_MODE_TX_RX; /* 收發(fā)模式 */
HAL_UART_Init(&g_uart1_handle); /* HAL_UART_Init()會(huì)使能UART1 */
/* 該函數(shù)會(huì)開(kāi)啟接收中斷:標(biāo)志位UART_IT_RXNE,并且設(shè)置接收緩沖以及接收緩沖接收最大數(shù)據(jù)量 */
HAL_UART_Receive_IT(&g_uart1_handle, (uint8_t *)g_rx_buffer, RXBUFFERSIZE);
}
/**
* @brief UART底層初始化函數(shù)
* @param huart: UART句柄類型指針
* @note 此函數(shù)會(huì)被HAL_UART_Init()調(diào)用
* 完成時(shí)鐘使能,引腳配置,中斷配置
* @retval 無(wú)
*/
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
GPIO_InitTypeDef gpio_init_struct;
if (huart->Instance == USART_UX) /* 如果是串口1,進(jìn)行串口1 MSP初始化 */
{
USART_TX_GPIO_CLK_ENABLE(); /* 使能串口TX腳時(shí)鐘 */
USART_RX_GPIO_CLK_ENABLE(); /* 使能串口RX腳時(shí)鐘 */
USART_UX_CLK_ENABLE(); /* 使能串口時(shí)鐘 */
gpio_init_struct.Pin = USART_TX_GPIO_PIN; /* 串口發(fā)送引腳號(hào) */
gpio_init_struct.Mode = GPIO_MODE_AF_PP; /* 復(fù)用推挽輸出 */
gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */
gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* IO速度設(shè)置為高速 */
HAL_GPIO_Init(USART_TX_GPIO_PORT, &gpio_init_struct);
gpio_init_struct.Pin = USART_RX_GPIO_PIN; /* 串口RX腳 模式設(shè)置 */
gpio_init_struct.Mode = GPIO_MODE_AF_INPUT;
HAL_GPIO_Init(USART_RX_GPIO_PORT, &gpio_init_struct); /* 串口RX腳 必須設(shè)置成輸入模式 */
#if USART_EN_RX
HAL_NVIC_EnableIRQ(USART_UX_IRQn); /* 使能USART1中斷通道 */
HAL_NVIC_SetPriority(USART_UX_IRQn, 3, 3); /* 組2,最低優(yōu)先級(jí):搶占優(yōu)先級(jí)3,子優(yōu)先級(jí)3 */
#endif
}
}
/**
* @brief 串口數(shù)據(jù)接收回調(diào)函數(shù)
數(shù)據(jù)處理在這里進(jìn)行
* @param huart:串口句柄
* @retval 無(wú)
*/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART_UX) /* 如果是串口1 */
{
if ((g_usart_rx_sta & 0x8000) == 0) /* 接收未完成 */
{
if (g_usart_rx_sta & 0x4000) /* 接收到了0x0d(即回車鍵) */
{
if (g_rx_buffer[0] != 0x0a) /* 接收到的不是0x0a(即不是換行鍵) */
{
g_usart_rx_sta = 0; /* 接收錯(cuò)誤,重新開(kāi)始 */
}
else /* 接收到的是0x0a(即換行鍵) */
{
g_usart_rx_sta |= 0x8000; /* 接收完成了 */
}
}
else /* 還沒(méi)收到0X0d(即回車鍵) */
{
if (g_rx_buffer[0] == 0x0d)
g_usart_rx_sta |= 0x4000;
else
{
g_usart_rx_buf[g_usart_rx_sta & 0X3FFF] = g_rx_buffer[0];
g_usart_rx_sta++;
if (g_usart_rx_sta > (USART_REC_LEN - 1))
{
g_usart_rx_sta = 0; /* 接收數(shù)據(jù)錯(cuò)誤,重新開(kāi)始接收 */
}
}
}
}
}
}
/**
* @brief 串口X中斷服務(wù)函數(shù)
注意,讀取USARTx->SR能避免莫名其妙的錯(cuò)誤
* @param 無(wú)
* @retval 無(wú)
*/
void USART_UX_IRQHandler(void)
{
#if SYSTEM_SUPPORT_OS /* 使用OS */
OSIntEnter();
#endif
HAL_UART_IRQHandler(&g_uart1_handle); /* 調(diào)用HAL庫(kù)中斷處理公用函數(shù) */
while (HAL_UART_Receive_IT(&g_uart1_handle, (uint8_t *)g_rx_buffer, RXBUFFERSIZE) != HAL_OK) /* 重新開(kāi)啟中斷并接收數(shù)據(jù) */
{
/* 如果出錯(cuò)會(huì)卡死在這里 */
}
#if SYSTEM_SUPPORT_OS /* 使用OS */
OSIntExit();
#endif
}
#endif
usart.h
#ifndef __USART_H
#define __USART_H
#include "stdio.h"
#include "./SYSTEM/sys/sys.h"
/******************************************************************************************/
/* 引腳 和 串口 定義
* 默認(rèn)是針對(duì)USART1的.
* 注意: 通過(guò)修改這幾個(gè)宏定義,可以支持USART1~UART5任意一個(gè)串口.
*/
#define USART_TX_GPIO_PORT GPIOA
#define USART_TX_GPIO_PIN GPIO_PIN_9
#define USART_TX_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0) /* PA口時(shí)鐘使能 */
#define USART_RX_GPIO_PORT GPIOA
#define USART_RX_GPIO_PIN GPIO_PIN_10
#define USART_RX_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0) /* PA口時(shí)鐘使能 */
#define USART_UX USART1
#define USART_UX_IRQn USART1_IRQn
#define USART_UX_IRQHandler USART1_IRQHandler
#define USART_UX_CLK_ENABLE() do{ __HAL_RCC_USART1_CLK_ENABLE(); }while(0) /* USART1 時(shí)鐘使能 */
/******************************************************************************************/
#define USART_REC_LEN 200 /* 定義最大接收字節(jié)數(shù) 200 */
#define USART_EN_RX 1 /* 使能(1)/禁止(0)串口1接收 */
#define RXBUFFERSIZE 1 /* 緩存大小 */
extern UART_HandleTypeDef g_uart1_handle; /* HAL UART句柄 */
extern uint8_t g_usart_rx_buf[USART_REC_LEN]; /* 接收緩沖,最大USART_REC_LEN個(gè)字節(jié).末字節(jié)為換行符 */
extern uint16_t g_usart_rx_sta; /* 接收狀態(tài)標(biāo)記 */
extern uint8_t g_rx_buffer[RXBUFFERSIZE]; /* HAL庫(kù)USART接收Buffer */
void usart_init(uint32_t bound); /* 串口初始化函數(shù) */
#endif
main.c
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./USMART/usmart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./BSP/RS485/rs485.h"
int main(void)
{
uint8_t key;
uint8_t i = 0, t = 0;
uint8_t cnt = 0;
uint8_t rs485buf[5];
HAL_Init(); /* 初始化HAL庫(kù) */
sys_stm32_clock_init(RCC_PLL_MUL9); /* 設(shè)置時(shí)鐘, 72Mhz */
delay_init(72); /* 延時(shí)初始化 */
usart_init(115200); /* 串口初始化為115200 */
usmart_dev.init(72); /* 初始化USMART */
led_init(); /* 初始化LED */
lcd_init(); /* 初始化LCD */
key_init(); /* 初始化按鍵 */
rs485_init(9600); /* 初始化RS485 */
lcd_show_string(30, 50, 200, 16, 16, "STM32", RED);
lcd_show_string(30, 70, 200, 16, 16, "RS485 TEST", RED);
lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);
lcd_show_string(30, 110, 200, 16, 16, "KEY0:Send", RED); /* 顯示提示信息 */
lcd_show_string(30, 130, 200, 16, 16, "Count:", RED); /* 顯示當(dāng)前計(jì)數(shù)值 */
lcd_show_string(30, 150, 200, 16, 16, "Send Data:", RED); /* 提示發(fā)送的數(shù)據(jù) */
lcd_show_string(30, 190, 200, 16, 16, "Receive Data:", RED);/* 提示接收到的數(shù)據(jù) */
while (1)
{
key = key_scan(0);
if (key == KEY0_PRES) /* KEY0按下,發(fā)送一次數(shù)據(jù) */
{
for (i = 0; i < 5; i++)
{
rs485buf[i] = cnt + i; /* 填充發(fā)送緩沖區(qū) */
lcd_show_xnum(30 + i * 32, 170, rs485buf[i], 3, 16, 0X80, BLUE); /* 顯示數(shù)據(jù) */
}
rs485_send_data(rs485buf, 5); /* 發(fā)送5個(gè)字節(jié) */
}
rs485_receive_data(rs485buf, &key);
if (key) /* 接收到有數(shù)據(jù) */
{
if (key > 5) key = 5; /* 最大是5個(gè)數(shù)據(jù). */
for (i = 0; i < key; i++)
{
lcd_show_xnum(30 + i * 32, 210, rs485buf[i], 3, 16, 0X80, BLUE); /* 顯示數(shù)據(jù) */
}
}
t++;
delay_ms(10);
if (t == 20)
{
LED0_TOGGLE(); /* LED0閃爍, 提示系統(tǒng)正在運(yùn)行 */
t = 0;
cnt++;
lcd_show_xnum(30 + 48, 130, cnt, 3, 16, 0X80, BLUE); /* 顯示數(shù)據(jù) */
}
}
}
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-850230.html
五、總結(jié)
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-850230.html
到了這里,關(guān)于【正點(diǎn)原子STM32】RS485串行通信標(biāo)準(zhǔn)(串口基礎(chǔ)協(xié)議 和 MODBUS協(xié)議、總線連接、通信電路、通信波形圖、RS485相關(guān)HAL庫(kù)驅(qū)動(dòng)、RS485配置步驟、)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!