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

【正點(diǎn)原子STM32】RS485串行通信標(biāo)準(zhǔn)(串口基礎(chǔ)協(xié)議 和 MODBUS協(xié)議、總線連接、通信電路、通信波形圖、RS485相關(guān)HAL庫(kù)驅(qū)動(dòng)、RS485配置步驟、)

這篇具有很好參考價(jià)值的文章主要介紹了【正點(diǎn)原子STM32】RS485串行通信標(biāo)準(zhǔn)(串口基礎(chǔ)協(xié)議 和 MODBUS協(xié)議、總線連接、通信電路、通信波形圖、RS485相關(guān)HAL庫(kù)驅(qū)動(dòng)、RS485配置步驟、)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

一、RS485介紹
二、RS485相關(guān)HAL庫(kù)驅(qū)動(dòng)介紹
三、RS485配置步驟
四、編程實(shí)戰(zhàn)
五、總結(jié)


串口、 UART、TTL、RS232、RS422、RS485關(guān)系

正電原子485,STM32,RS485串行通信標(biāo)準(zhǔn),總線連接、通信電路、波形圖,RS485相關(guān)HAL庫(kù)驅(qū)動(dòng),RS485配置步驟,串口基礎(chǔ)協(xié)議,MODBUS協(xié)議
串口、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)鍵要素:

  1. 通信時(shí)序:?jiǎn)?dòng)位、數(shù)據(jù)位(一般為5到8位)、奇偶校驗(yàn)位(可選)和停止位(1到2位)。
  2. 波特率:每秒傳輸?shù)奈粩?shù),常見(jiàn)的有9600、19200、38400、115200等。
  3. 通信方向:可以是全雙工(同時(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)包括:

  1. 主從結(jié)構(gòu):網(wǎng)絡(luò)中有一個(gè)主設(shè)備(主控制器)向多個(gè)從設(shè)備發(fā)起請(qǐng)求,從設(shè)備響應(yīng)請(qǐng)求。
  2. 功能碼:MODBUS協(xié)議定義了一系列功能碼,每個(gè)功能碼對(duì)應(yīng)一種操作,如讀取線圈狀態(tài)、寄存器值,寫(xiě)入線圈狀態(tài)、寄存器值等。
  3. 數(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):

  1. 主從架構(gòu):網(wǎng)絡(luò)中只有一個(gè)主設(shè)備(如PLC或HMI),可以向多個(gè)從設(shè)備(如傳感器、執(zhí)行器、其他控制器等)發(fā)送請(qǐng)求并接收響應(yīng)。
  2. 功能碼:MODBUS協(xié)議定義了一系列功能碼,用于執(zhí)行讀寫(xiě)操作,如讀取線圈狀態(tài)、寄存器值、輸入狀態(tài),寫(xiě)入線圈狀態(tài)、寄存器值等。
  3. 數(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介紹

正電原子485,STM32,RS485串行通信標(biāo)準(zhǔn),總線連接、通信電路、波形圖,RS485相關(guān)HAL庫(kù)驅(qū)動(dòng),RS485配置步驟,串口基礎(chǔ)協(xié)議,MODBUS協(xié)議
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ò)部署能力。
正電原子485,STM32,RS485串行通信標(biāo)準(zhǔn),總線連接、通信電路、波形圖,RS485相關(guān)HAL庫(kù)驅(qū)動(dòng),RS485配置步驟,串口基礎(chǔ)協(xié)議,MODBUS協(xié)議
在RS485總線連接中,組件之間的連接和作用如下:

  1. CPU:中央處理器,負(fù)責(zé)控制整個(gè)系統(tǒng)的運(yùn)行和數(shù)據(jù)處理。

  2. UART控制器:集成在CPU內(nèi)部或外部的通用異步收發(fā)傳輸器,用于生成和解析串行通信數(shù)據(jù)流。

  3. 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引腳)。
  4. 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。
  5. 485_A/485_B

    • 這是RS485總線的差分信號(hào)線,485_A和485_B兩根線通過(guò)雙絞線連接到所有的RS485設(shè)備,確保信號(hào)質(zhì)量良好。
  6. 匹配電阻

    • 在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ù)交換。
正電原子485,STM32,RS485串行通信標(biāo)準(zhǔn),總線連接、通信電路、波形圖,RS485相關(guān)HAL庫(kù)驅(qū)動(dòng),RS485配置步驟,串口基礎(chǔ)協(xié)議,MODBUS協(xié)議
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,STM32,RS485串行通信標(biāo)準(zhǔn),總線連接、通信電路、波形圖,RS485相關(guān)HAL庫(kù)驅(qū)動(dòng),RS485配置步驟,串口基礎(chǔ)協(xié)議,MODBUS協(xié)議
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>正電原子485,STM32,RS485串行通信標(biāo)準(zhǔn),總線連接、通信電路、波形圖,RS485相關(guān)HAL庫(kù)驅(qū)動(dòng),RS485配置步驟,串口基礎(chǔ)協(xié)議,MODBUS協(xié)議

二、RS485相關(guān)HAL庫(kù)驅(qū)動(dòng)介紹

正電原子485,STM32,RS485串行通信標(biāo)準(zhǔn),總線連接、通信電路、波形圖,RS485相關(guān)HAL庫(kù)驅(qū)動(dòng),RS485配置步驟,串口基礎(chǔ)協(xié)議,MODBUS協(xié)議
實(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配置步驟

正電原子485,STM32,RS485串行通信標(biāo)準(zhǔn),總線連接、通信電路、波形圖,RS485相關(guān)HAL庫(kù)驅(qū)動(dòng),RS485配置步驟,串口基礎(chǔ)協(xié)議,MODBUS協(xié)議
RS485配置步驟,基于STM32 HAL庫(kù)進(jìn)行,可以細(xì)化為以下步驟:

  1. 配置串口工作參數(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)等。
  2. 串口底層初始化

    • 配置與串口相關(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í)鐘。
  3. 開(kāi)啟串口異步接收中斷

    • 通過(guò)__HAL_UART_ENABLE_IT()函數(shù)啟用串口的接收中斷,例如啟用UART_IT_RXNE,這樣當(dāng)接收數(shù)據(jù)寄存器非空時(shí),會(huì)產(chǎn)生中斷請(qǐng)求。
  4. 設(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。
  5. 編寫(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ù)。
  6. 串口數(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)

正電原子485,STM32,RS485串行通信標(biāo)準(zhǔn),總線連接、通信電路、波形圖,RS485相關(guān)HAL庫(kù)驅(qū)動(dòng),RS485配置步驟,串口基礎(chǔ)協(xié)議,MODBUS協(xié)議
正電原子485,STM32,RS485串行通信標(biāo)準(zhǔn),總線連接、通信電路、波形圖,RS485相關(guān)HAL庫(kù)驅(qū)動(dòng),RS485配置步驟,串口基礎(chǔ)協(xié)議,MODBUS協(xié)議

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ù) */
        }
    }
}

正電原子485,STM32,RS485串行通信標(biāo)準(zhǔn),總線連接、通信電路、波形圖,RS485相關(guān)HAL庫(kù)驅(qū)動(dòng),RS485配置步驟,串口基礎(chǔ)協(xié)議,MODBUS協(xié)議
正電原子485,STM32,RS485串行通信標(biāo)準(zhǔn),總線連接、通信電路、波形圖,RS485相關(guān)HAL庫(kù)驅(qū)動(dòng),RS485配置步驟,串口基礎(chǔ)協(xié)議,MODBUS協(xié)議
正電原子485,STM32,RS485串行通信標(biāo)準(zhǔn),總線連接、通信電路、波形圖,RS485相關(guān)HAL庫(kù)驅(qū)動(dòng),RS485配置步驟,串口基礎(chǔ)協(xié)議,MODBUS協(xié)議

五、總結(jié)

正電原子485,STM32,RS485串行通信標(biāo)準(zhǔn),總線連接、通信電路、波形圖,RS485相關(guān)HAL庫(kù)驅(qū)動(dòng),RS485配置步驟,串口基礎(chǔ)協(xié)議,MODBUS協(xié)議
正電原子485,STM32,RS485串行通信標(biāo)準(zhǔn),總線連接、通信電路、波形圖,RS485相關(guān)HAL庫(kù)驅(qū)動(dòng),RS485配置步驟,串口基礎(chǔ)協(xié)議,MODBUS協(xié)議文章來(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)!

本文來(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)文章

  • 正點(diǎn)原子stm32F407學(xué)習(xí)筆記5——串口通信實(shí)驗(yàn)

    正點(diǎn)原子stm32F407學(xué)習(xí)筆記5——串口通信實(shí)驗(yàn)

    上位機(jī)給開(kāi)發(fā)板發(fā)送數(shù)據(jù),開(kāi)發(fā)板將收到的數(shù)據(jù)發(fā)回給上位機(jī) 串口設(shè)置的一般步驟可以總結(jié)為如下幾個(gè)步驟: 串口時(shí)鐘使能,GPIO 時(shí)鐘使能。 設(shè)置引腳復(fù)用器映射:調(diào)用 GPIO_PinAFConfig 函數(shù)。 GPIO 初始化設(shè)置:要設(shè)置模式為復(fù)用功能。 串口參數(shù)初始化:設(shè)置波特率,字長(zhǎng),奇

    2024年02月06日
    瀏覽(28)
  • 【正點(diǎn)原子STM32連載】第十三章 串口通信實(shí)驗(yàn) 摘自【正點(diǎn)原子】APM32E103最小系統(tǒng)板使用指南

    【正點(diǎn)原子STM32連載】第十三章 串口通信實(shí)驗(yàn) 摘自【正點(diǎn)原子】APM32E103最小系統(tǒng)板使用指南

    1)實(shí)驗(yàn)平臺(tái):正點(diǎn)原子APM32E103最小系統(tǒng)板 2)平臺(tái)購(gòu)買地址:https://detail.tmall.com/item.htm?id=609294757420 3)全套實(shí)驗(yàn)源碼+手冊(cè)+視頻下載地址: http://www.openedv.com/docs/boards/xiaoxitongban 本章將介紹使用串口進(jìn)行數(shù)據(jù)的收發(fā)操作,具體實(shí)現(xiàn)APM32E103與上位機(jī)軟件的數(shù)據(jù)通信,APM32E103將接受

    2024年02月21日
    瀏覽(16)
  • RS-422和RS-485串行接口標(biāo)準(zhǔn)在FPGA中的實(shí)現(xiàn)

    RS-422和RS-485串行接口標(biāo)準(zhǔn)在FPGA中的實(shí)現(xiàn) 隨著工業(yè)自動(dòng)化技術(shù)的迅速發(fā)展,串行通信接口已經(jīng)成為了現(xiàn)代自動(dòng)控制系統(tǒng)中最為重要的通信方式之一。而在眾多的串行通信接口標(biāo)準(zhǔn)中,RS-422和RS-485接口是在工業(yè)自動(dòng)化應(yīng)用中被廣泛采用的兩種標(biāo)準(zhǔn)。 RS-422和RS-485是一種差分信號(hào)通

    2024年02月04日
    瀏覽(62)
  • STM32RS485通信

    STM32RS485通信

    本章所要實(shí)現(xiàn)的功能是:通過(guò)操作 KEY_UP 鍵,STM32F1 的串口 2 將 PC 機(jī)發(fā) 送過(guò)來(lái)的數(shù)據(jù)原封不動(dòng)的返回給 PC 機(jī)串口,同時(shí) DS0 指示燈不斷閃爍,提示系 統(tǒng)正常運(yùn)行。程序框架如下: (1)初始化串口 2,并使能串口接收中斷等 (2)編寫(xiě)串口 2 中斷函數(shù)(將接收到的數(shù)據(jù)返回出去

    2024年02月14日
    瀏覽(17)
  • 【【STM32-29正點(diǎn)原子版本串口發(fā)送傳輸實(shí)驗(yàn)】

    【【STM32-29正點(diǎn)原子版本串口發(fā)送傳輸實(shí)驗(yàn)】

    通過(guò)串口接收或發(fā)送一個(gè)字符 例程目的 開(kāi)發(fā)板上我們接入的是實(shí)現(xiàn)異步通信的UART接口 USB轉(zhuǎn)串口原理圖 我們一步步分析 PA9是串口1 的發(fā)送引腳 PA10是串口1 的接受引腳 。因?yàn)槲覀儸F(xiàn)在只是用到異步收發(fā)器功能,所以我們現(xiàn)在只需要 stm32fxx_hal_uart.c 文件(及其頭文件)的驅(qū)動(dòng)代

    2024年02月09日
    瀏覽(20)
  • 在STM32上實(shí)現(xiàn)RS485通信

    RS485是一種常用的串行通信協(xié)議,通常用于遠(yuǎn)距離數(shù)據(jù)傳輸和多點(diǎn)通信。在STM32單片機(jī)上實(shí)現(xiàn)RS485通信,通常需要配置相關(guān)硬件和軟件,包括串口外設(shè)、GPIO和通信協(xié)議。 本文將介紹如何在STM32上實(shí)現(xiàn)RS485通信,包括硬件連接、串口配置和通信協(xié)議,并給出相應(yīng)的代碼示例。 一、

    2024年01月16日
    瀏覽(21)
  • STM32 RS485通信的一種辦法

    STM32 RS485通信的一種辦法

    一、RS485 ? ? ? ?485通信,通信接口的遠(yuǎn)程重?cái)?shù)據(jù)采集方法,在要求通信距離為幾十米到上千米時(shí),廣泛采用RS-485串行總線標(biāo)準(zhǔn)。RS-485采用平衡發(fā)送和差分接受,因此具有抑制共模干擾的能力。 它的電氣特性是邏輯“1”以兩線間電壓差+(2-6)V表示;邏輯“0”以兩線間電壓差

    2024年02月11日
    瀏覽(27)
  • STM32開(kāi)發(fā)(六)STM32F103 通信 —— RS485 Modbus通信編程詳解

    STM32開(kāi)發(fā)(六)STM32F103 通信 —— RS485 Modbus通信編程詳解

    ??《上一篇》 ???《主目錄》 ???《下一篇》 了解 RS485 Modbus協(xié)議技術(shù) 。本實(shí)驗(yàn)是基于STM32F103開(kāi)發(fā) 實(shí)現(xiàn) 通過(guò)RS-485實(shí)現(xiàn)modbus協(xié)議。 準(zhǔn)備好了嗎?開(kāi)始我的show time。 1、硬件開(kāi)發(fā)準(zhǔn)備 主控:STM32F103ZET6 RS485收發(fā)器:SP3485P 2、軟件開(kāi)發(fā)準(zhǔn)備 軟件開(kāi)發(fā)使用虛擬機(jī) + VScode + STM32Cub

    2024年02月03日
    瀏覽(24)
  • STM32 IAP應(yīng)用開(kāi)發(fā)——通過(guò)串口/RS485實(shí)現(xiàn)固件升級(jí)(方式2)

    STM32 IAP應(yīng)用開(kāi)發(fā)——通過(guò)串口/RS485實(shí)現(xiàn)固件升級(jí)(方式2)

    什么是IAP? IAP(In-Application Programming) 指MCU可以在系統(tǒng)中獲取新代碼并對(duì)自己重新編程,即可用程序來(lái)改變程序。在應(yīng)用編程(IAP)是用戶的應(yīng)用代碼對(duì)片內(nèi)Flash存儲(chǔ)器進(jìn)行擦除/編程的方法。這種方式的典型應(yīng)用就是用一小段代碼來(lái)實(shí)現(xiàn)程序的下載,實(shí)際上單片機(jī)的ISP功能就

    2024年02月14日
    瀏覽(24)
  • STM32 IAP應(yīng)用開(kāi)發(fā)——通過(guò)串口/RS485實(shí)現(xiàn)固件升級(jí)(方式1)

    STM32 IAP應(yīng)用開(kāi)發(fā)——通過(guò)串口/RS485實(shí)現(xiàn)固件升級(jí)(方式1)

    什么是IAP? IAP(In-Application Programming) 指MCU可以在系統(tǒng)中獲取新代碼并對(duì)自己重新編程,即可用程序來(lái)改變程序。在應(yīng)用編程(IAP)是用戶的應(yīng)用代碼對(duì)片內(nèi)Flash存儲(chǔ)器進(jìn)行擦除/編程的方法。這種方式的典型應(yīng)用就是用一小段代碼來(lái)實(shí)現(xiàn)程序的下載,實(shí)際上單片機(jī)的ISP功能就

    2024年02月10日
    瀏覽(19)

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

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

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

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

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包