0x6A Logbook

0x6A Logbook
Shi6a的筆記本
  1. 首頁
  2. 自動化技巧
  3. 正文

RS485 通訊協定完整教學:從硬體接線到 ESP32/STM32 實作

2026 年 5 月 21 日 5點熱度 0人點贊 0條評論

RS485 通訊協定是工業自動化領域最廣泛使用的有線通訊標準之一。無論是 PLC、變頻器、感測器陣列還是 SCADA 系統,RS485 幾乎無所不在。它的最大優勢——長距離(最長 1200m)、多站(最多 256 個裝置)、差動訊號抗干擾——讓它成為工廠環境的首選。本文從 MAX485 教學開始,帶你實作 ESP32 RS485 和 STM32 的通訊。

這篇文章會從 RS485 的硬體原理開始,帶你一步步看懂接線、選擇收發器晶片,並在 ESP32(Arduino)和 STM32(HAL) 上實作 RS485 通訊。

什麼是 RS485?

RS485(也稱 TIA-485)是由 Electronic Industries Alliance(EIA) 定義的差動串列通訊標準。它使用兩條線(A 線 / D+ 和 B 線 / D-)傳送差動訊號,而不是像 UART 那樣用單端訊號對地參考。

差動訊號的核心優點:

  • 抗共模干擾:外界雜訊同時耦合到 A、B 兩線,電壓差不受影響
  • 長距離傳輸:1200m 仍可保持 10Mbps 以上速率(距離越短速度越快)
  • 多站匯流排:一條匯流排最多可接 256 個收發器(標準 RS485 驅動器為 32 單位負載)
  • 雙向半雙工:同一時間只能一個裝置發送,但所有裝置都能接收

RS485 vs RS232 vs TTL UART

特性 RS485 RS232 TTL UART
訊號方式 差動(平衡) 單端(不平衡) 單端
電壓範圍 ±1.5V ~ ±6V ±3V ~ ±15V 0V ~ 3.3V/5V
最大距離 1200m 15m 1~3m
最大速率 50Mbps(短距) 115.2kbps 取決於 MCU
多站能力 最多 256 個 點對點 點對點
共模電壓 -7V ~ +12V N/A N/A
收發器 IC MAX485 / MAX3485 MAX232 內建於 MCU
典型應用 工業網路、Modbus 舊式 PC COM Port 晶片間通訊

簡單總結:RS232 是 PC 時代的遺產,TTL UART 是晶片內部用的,而 RS485 才是工業現場的主力。

📖 延伸閱讀:SPI 通訊教學 · MQTT 實戰教學 · I2C 通訊教學

RS485 硬體接線

RS485 多站通訊拓撲圖
圖 1:RS485 多站匯流排拓撲 — 主站搭配多個從站,A/B 線兩端需要 120Ω 終端電阻

A/B 線(D+/D-)

RS485 使用兩條絞線(Twisted Pair):

  • A 線(D+ / Non-inverting):當 A 電壓高於 B 時,邏輯為 1(Mark)
  • B 線(D- / Inverting):當 B 電壓高於 A 時,邏輯為 0(Space)

注意不同廠商的標示方式可能不同——有些標 A/B,有些標 D+/D-,有些標 P/N(Positive/Negative)。接線前一定要確認規格書。

終端電阻

在匯流排最遠的兩端各接一顆 120Ω 電阻(A 到 B 之間):

  • 防止訊號反射造成資料錯誤
  • 確保空閒時差動電壓在負載狀態
  • 只在最遠的兩個節點加,中間節點不需要

偏壓電阻

在某些系統中,為了確保匯流排空閒(所有發送器均為高阻抗)時的電位穩定,會在 主站端 加入偏壓電阻:

  • A 線接到 Vcc(通常 470Ω ~ 1kΩ)
  • B 線接到 GND(通常 470Ω ~ 1kΩ)

收發器晶片:MAX485 與 MAX3485

MCU 的 UART 腳位輸出的是 TTL 電平(0-3.3V 或 0-5V),不能直接接到 RS485 匯流排。你需要一顆 RS485 收發器:

晶片 電壓 速率 腳位
MAX485 5V 2.5Mbps 8-pin DIP/SOIC
MAX3485 3.3V 12Mbps 8-pin DIP/SOIC
MAX1487 5V 2.5Mbps 8-pin(高 ESD)
SN65HVD3082E 5V 20Mbps 8-pin(低功耗)

對於 ESP32(3.3V 系統),MAX3485 是首選——不需要電平轉換。對於 STM32(5V 容忍腳位),MAX485 也可以直接驅動。

MAX485/MAX3485 腳位

腳位 名稱 說明
1 RO Receiver Output → MCU RX
2 RE Receiver Enable (Low = 啟用接收)
3 DE Driver Enable (High = 啟用發送)
4 DI Driver Input ← MCU TX
5 GND 接地
6 A Non-inverting output/input (D+)
7 B Inverting output/input (D-)
8 Vcc 電源(MAX485: 5V / MAX3485: 3.3V)

關鍵控制腳:DE 和 RE。RS485 是半雙工,發送和接收不能同時進行。通常把 DE 和 RE 接在一起,用一個 GPIO 控制:

  • GPIO = HIGH:DE 啟用 → 發送模式(RE 同時被拉高,接收關閉)
  • GPIO = LOW:RE 啟用 → 接收模式(DE 同時被拉低,發送關閉)

ESP32 + MAX3485 實作(Arduino)

接線方式

ESP32 MAX3485
GPIO17 (TX2) DI (Pin 4)
GPIO16 (RX2) RO (Pin 1)
GPIO4 DE + RE (Pin 2&3)
3.3V Vcc (Pin 8)
GND GND (Pin 5)

A 和 B 腳接到 RS485 匯流排。

程式碼

#include <HardwareSerial.h>

#define TX2_PIN 17
#define RX2_PIN 16
#define RS485_CTRL 4   // DE/RE 控制腳

HardwareSerial rs485(2);  // UART2

void setup() {
  Serial.begin(115200);
  pinMode(RS485_CTRL, OUTPUT);
  digitalWrite(RS485_CTRL, LOW); // 預設接收模式

  rs485.begin(9600, SERIAL_8N1, RX2_PIN, TX2_PIN);
}

void rs485_send(const uint8_t* data, size_t len) {
  digitalWrite(RS485_CTRL, HIGH);  // 切換到發送模式
  delay(1);                         // 等待電晶體穩定
  rs485.write(data, len);
  rs485.flush();                    // 等待資料發送完畢
  delay(1);
  digitalWrite(RS485_CTRL, LOW);   // 回到接收模式
}

void loop() {
  if (rs485.available()) {
    uint8_t buf[64];
    size_t len = rs485.readBytes(buf, 64);
    
    Serial.print("收到 ");
    Serial.print(len);
    Serial.println(" bytes:");
    for (size_t i = 0; i < len; i++) {
      Serial.printf("0x%02X ", buf[i]);
    }
    Serial.println();

    // 回傳相同資料(Loopback 測試)
    rs485_send(buf, len);
  }
}

STM32 + MAX485 實作(HAL)

CubeMX 設定

  • USART2:非同步模式,Baud Rate 9600,8N1
  • PA0:GPIO_Output(DE/RE 控制)
  • PA2 (TX)、PA3 (RX) 連接到 MAX485

程式碼

#define RS485_CTRL_PORT GPIOA
#define RS485_CTRL_PIN  GPIO_PIN_0

#define RS485_TX_MODE()  HAL_GPIO_WritePin(RS485_CTRL_PORT, RS485_CTRL_PIN, GPIO_PIN_SET)
#define RS485_RX_MODE()  HAL_GPIO_WritePin(RS485_CTRL_PORT, RS485_CTRL_PIN, GPIO_PIN_RESET)

void RS485_Send(uint8_t* data, uint16_t len) {
  RS485_TX_MODE();
  HAL_Delay(1);
  HAL_UART_Transmit(&huart2, data, len, HAL_MAX_DELAY);
  HAL_Delay(1);
  RS485_RX_MODE();
}

void RS485_Receive_IT(void) {
  RS485_RX_MODE();
  static uint8_t rx_byte;
  HAL_UART_Receive_IT(&huart2, &rx_byte, 1);
}

// 在回呼函數中處理收到的資料
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
  if (huart->Instance == USART2) {
    static uint8_t rx_buf[64];
    static uint16_t idx = 0;
    
    rx_buf[idx++] = rx_byte;
    
    // 遇到換行或緩衝區滿,處理一筆完整訊息
    if (rx_byte == '
' || idx >= 64) {
      RS485_Send(rx_buf, idx);  // 回傳(Loopback)
      idx = 0;
    }
    
    HAL_UART_Receive_IT(&huart2, &rx_byte, 1);
  }
}

DE/RE 控制時序圖

RS485 的正確操作離不開 DE/RE 的精準控制。下圖展示了 ESP32 發送一筆資料的全過程:

RS485 DE/RE 控制與差動訊號傳輸時序
圖 2:RS485 DE/RE 控制與差動訊號傳輸時序 — 注意 DE 必須在資料發送前拉高,傳完後拉低回到接收模式

關鍵時間點:

  1. t₁:DE 拉高 — 啟用驅動器,MAX485 開始驅動 A/B 線
  2. t₂:開始發送資料 — A/B 線產生差動電壓
  3. t₃:資料發送完成 — TX Buffer 已清空
  4. t₄:DE 拉低 — 關閉驅動器,回到接收模式

注意 t₁→t₂ 和 t₃→t₄ 之間需要 1~2ms 的延遲,確保匯流排穩定。延遲過短會導致資料尾端被截斷,這是 RS485 開發中最常見的 bug。

RS485 常見問題與排錯

1. 資料亂碼或接收不到

  • 檢查 Baud Rate:確認所有裝置的鮑率一致
  • 檢查 A/B 線是否接反:A 接 A、B 接 B,不要在途中交叉
  • 檢查終端電阻:沒有 120Ω 終端電阻時,長線會發生訊號反射
  • 檢查 DE/RE 延遲:切換模式後留足夠時間讓收發器穩定

2. 最後一兩個 byte 遺失

這是 DE 切換時序問題的典型症狀。解決方案:

  • 在 rs485.flush() 或 HAL_UART_Transmit() 返回後,務必延遲 2ms 以上再將 DE 拉低
  • 考慮使用硬體自動方向控制(如 MAX13487 或 ADM2483)

3. 超過 32 個裝置時通訊不穩

標準 RS485 驅動器定義為 1 單位負載(UL),最多驅動 32 UL。超過 32 個裝置時:

  • 使用 1/4 UL 收發器(如 MAX1487),可接 128 個
  • 使用 1/8 UL 收發器(如 SN65HVD3082E),可接 256 個
  • 加入 RS485 中繼器 擴充網路

4. 接地問題

RS485 雖然使用差動訊號,但 共模電壓範圍有限(-7V ~ +12V)。當節點間距離很遠時,地電位差可能超出範圍。解決方案:

  • 在匯流排上加一條 第三條接地線
  • 使用 隔離型 RS485 收發器(如 ADM2483、ISO3082)
  • 使用 RS485 隔離模組(如 B0505S 隔離電源 + 光耦合)

總結

RS485 是工業通訊的基石。它的差動訊號設計讓它能在惡劣的工廠環境中穩定傳輸,而半雙工的特性要求開發者精準掌握 DE/RE 控制時序。

學會 RS485 之後,下一步可以學習 Modbus RTU——這是建立在 RS485 實體層之上的應用層協定,廣泛用於 PLC、感測器和工業儀表。到時候你在 ESP32 和 STM32 上的 RS485 底層程式碼可以直接沿用。

如果你在實作中遇到問題,歡迎留言討論。

 

標籤: RS485 工業通訊 教學
最後更新:2026 年 5 月 21 日

shi6a

這個人很懶,什麼都沒留下

點贊
< 上一篇
下一篇 >

文章評論

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回覆

COPYRIGHT © 2026 0x6A Logbook. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang