RS-485 là gì: cặp dây vi sai, điện trở đầu cuối và cách dùng module MAX485 với ESP32

Giải thích chuẩn RS-485: tín hiệu vi sai trên hai dây A, B, điện trở đầu cuối 120 Ω, truyền bán song công với chân DE, RE. Kèm sơ đồ nối module MAX485 và chương trình hỏi đáp giữa hai mạch ESP32.

RS-485 là chuẩn truyền dữ liệu phổ biến nhất trong công nghiệp: biến tần, đồng hồ điện, bộ điều khiển nhiệt độ, cảm biến đặt xa hàng trăm mét phần lớn đều có cổng RS-485. Chuẩn này chỉ quy định phần dây dẫn và mức điện; dữ liệu đi trên đó vẫn là các byte của UART, và giao thức thường gặp nhất chạy trên nó là Modbus RTU. Bài viết giải thích cặp dây vi sai, điện trở đầu cuối, cách nhiều thiết bị chia nhau một cặp dây, rồi dùng hai mạch ESP32 với module MAX485 để truyền hỏi đáp qua RS-485.

1. RS-485 khác UART thường ở đâu?

  • UART mức 3,3 V hoặc 5 V chỉ nối được hai thiết bị, dây dài vài mét là bắt đầu lỗi.
  • RS-485 đổi mỗi bit thành hiệu điện áp giữa hai dây A và B. Nhiễu tác động lên hai dây như nhau nên bị loại bỏ khi lấy hiệu. Nhờ đó đường dây đi được tới khoảng 1200 m ở tốc độ thấp.
  • Nhiều thiết bị mắc song song trên cùng một cặp dây: chuẩn gốc cho phép 32 tải, các IC đời mới cho phép nhiều hơn.
  • RS-485 không quy định nội dung dữ liệu, không có địa chỉ hay kiểm tra lỗi. Những việc đó thuộc về giao thức ở lớp trên như Modbus RTU.

2. Đường dây: dây xoắn, điện trở đầu cuối, GND

Sơ đồ đường truyền RS-485: bốn nút mắc song song dọc theo một cặp dây xoắn A, B, hai điện trở đầu cuối 120 ôm ở hai đầu đường dây và dây GND nối chung
Các nút mắc dọc theo một đường dây chính, điện trở 120 Ω ở hai đầu.
  • Cặp dây xoắn: hai dây A, B phải xoắn vào nhau, tốt nhất là cáp có lớp chống nhiễu. Hai dây đi rời nhau làm mất phần lớn khả năng chống nhiễu.
  • Đi dây nối tiếp qua từng nút: đường dây chính đi lần lượt từ nút này sang nút kia. Không đấu hình sao (nhiều nhánh dài tỏa ra từ một điểm).
  • Điện trở đầu cuối 120 Ω: đặt giữa A và B ở hai nút đầu và cuối đường dây, để tín hiệu không dội lại ở đầu dây. Với dây ngắn vài mét và tốc độ thấp, thiếu điện trở này mạch vẫn thường chạy; dây dài thì bắt buộc.
  • Dây GND: bộ thu chịu được chênh lệch điện áp đất trong khoảng -7 đến +12 V. Nên có thêm dây thứ ba nối chung GND giữa các nút để chênh lệch này không vượt giới hạn.
  • Tên dây: các hãng đặt tên A, B không thống nhất; có hãng ghi D+, D-. Nếu nối đúng mà không nhận được gì, thử đổi chéo hai dây.

3. Tín hiệu trên hai dây

Giản đồ tín hiệu RS-485: mức logic ở chân DI, điện áp trên dây A và dây B đổi ngược chiều nhau, và hiệu A trừ B mà bộ thu dùng để đọc lại từng bit
Hai dây A, B mang hai mức ngược nhau; bộ thu đọc hiệu A − B (hình vẽ minh họa nguyên lý).
  • A cao hơn B ít nhất 0,2 V: bộ thu đọc ra mức 1. A thấp hơn B ít nhất 0,2 V: mức 0.
  • Khi không nút nào phát, hai dây thả nổi. Hai điện trở phân cực (kéo A lên, kéo B xuống) giữ cho đường dây ở trạng thái mức 1, đúng với trạng thái nghỉ của UART. Module MAX485 thông dụng đã có sẵn các điện trở này.

4. Bán song công: mỗi lúc một nút phát

Giản đồ thời gian điều khiển chiều truyền RS-485: chân DE và RE của nút chủ ở mức cao khi gửi câu hỏi rồi hạ xuống, sau một khoảng lặng nút tớ nâng chân DE và RE để gửi câu trả lời
Nút chủ phát câu hỏi rồi nhả đường dây; sau đó nút tớ mới phát câu trả lời.
  • Vì mọi nút dùng chung một cặp dây, tại một thời điểm chỉ được một nút phát. Kiểu truyền này gọi là bán song công.
  • IC thu phát có hai chân điều khiển: DE (mức cao thì bật bộ phát) và RE (mức thấp thì bật bộ thu). Nối chung hai chân vào một chân GPIO: mức cao là phát, mức thấp là nghe.
  • Trình tự gửi: nâng DE, gửi dữ liệu, chờ đến khi bit cuối cùng ra khỏi chân TX, rồi hạ DE ngay. Trong Arduino, hàm Serial2.flush() làm việc chờ này.
  • Để các nút không phát đè lên nhau, cần quy ước ai được phát lúc nào. Cách đơn giản và phổ biến nhất là một nút chủ hỏi, các nút tớ chỉ trả lời khi được hỏi.
  • Bộ UART của ESP32 còn có chế độ RS-485 tự điều khiển chân DE bằng tín hiệu RTS (setMode(UART_MODE_RS485_HALF_DUPLEX)). Bài này điều khiển bằng tay để thấy rõ nguyên lý.

5. Chuẩn bị

  • Hai mạch ESP32 DevKit V1 30 chân (hoặc bản dùng chip CH340).
  • Hai module chuyển đổi RS-485 dùng IC MAX485 (loại có các chân RO, RE, DE, DI và cọc A, B).
  • Điện trở 2,2 kΩ và 3,3 kΩ cho mạch chia áp ở chân RO, mỗi mạch một cặp.
  • Một đoạn dây đôi xoắn để nối A với A, B với B.
  • Breadboard và dây cắm.
  • Arduino IDE 2.x với gói esp32 by Espressif Systems (bài dùng phiên bản 3.3.10). Không cần cài thêm thư viện.

6. Sơ đồ nối

Sơ đồ nối ESP32 DevKit V1 với module MAX485: DI nối TX2, RO qua mạch chia áp 2,2 và 3,3 kilôôm vào RX2, DE và RE nối chung vào D4, VCC nối VIN 5 V, GND nối GND, hai cọc A và B đi tới module thứ hai
Một nút RS-485; nút thứ hai nối y hệt, rồi nối A với A, B với B giữa hai module.
  • Mức điện áp: MAX485 cần nguồn 5 V nên chân RO phát ra mức 5 V. Chân này phải qua mạch chia áp 2,2 kΩ và 3,3 kΩ trước khi vào RX2 của ESP32. Chân DI, DE, RE nhận mức 3,3 V của ESP32 nên nối thẳng.
  • Nếu dùng module chạy 3,3 V (IC MAX3485 hoặc SP3485) thì cấp 3V3 và nối thẳng RO vào RX2.
  • Mỗi module MAX485 thông dụng có sẵn một điện trở 120 Ω giữa A và B. Với hai module thì đúng bằng hai điện trở đầu cuối cần có. Khi mắc ba module trở lên, tháo điện trở này ở các module nằm giữa.
  • Nối thêm GND giữa hai mạch nếu chúng dùng nguồn khác nhau.

7. Chương trình hỏi đáp qua RS-485

Nạp cùng một chương trình cho hai mạch, chỉ khác hằng LA_NUT_CHU: một mạch đặt true, mạch kia đặt false. Nút chủ mỗi giây gửi một dòng DOC n rồi chờ trả lời tối đa 300 ms. Nút tớ chỉ phát khi nhận được câu hỏi.

/*
  PYWORLD.VN - RS-485 với ESP32 và module MAX485: hai nút hỏi đáp trên một cặp dây, tự điều khiển chiều truyền
  Nạp chương trình cho hai mạch: một mạch đặt LA_NUT_CHU = true (nút hỏi), mạch kia đặt false (nút trả lời)
  DI nối TX2 (GPIO17), RO nối RX2 (GPIO16), DE và RE nối chung vào D4; A nối A, B nối B giữa hai module
*/

#define RX2_PIN 16
#define TX2_PIN 17
#define DE_RE_PIN 4            // Mức cao: phát lên đường dây; mức thấp: nghe

const bool LA_NUT_CHU = true;  // Đổi thành false khi nạp cho mạch thứ hai
const uint32_t TOC_DO_BAUD = 9600;
const unsigned long THOI_GIAN_CHO_TRA_LOI_MS = 300;
const size_t DO_DAI_TOI_DA = 60;

// Gửi một dòng: chiếm đường dây, gửi, chờ gửi hết rồi nhả đường dây ngay
void guiDong(const String &dong) {
  digitalWrite(DE_RE_PIN, HIGH);
  Serial2.print(dong);
  Serial2.print('\n');
  Serial2.flush();               // Chờ đến khi bit cuối cùng rời khỏi chân TX
  digitalWrite(DE_RE_PIN, LOW);
}

// Chờ một dòng kết thúc bằng ký tự xuống dòng; trả về false nếu quá thời gian
bool nhanDong(String &dong, unsigned long thoiGianChoMs) {
  dong = "";
  unsigned long batDau = millis();
  while (millis() - batDau < thoiGianChoMs) {
    while (Serial2.available()) {
      char kyTu = Serial2.read();
      if (kyTu == '\n') {
        dong.trim();
        return true;
      }
      if (dong.length() < DO_DAI_TOI_DA) {
        dong += kyTu;
      }
    }
    delay(1);
  }
  return false;
}

void setup() {
  Serial.begin(115200);
  pinMode(DE_RE_PIN, OUTPUT);
  digitalWrite(DE_RE_PIN, LOW);   // Mặc định ở chế độ nghe để không chiếm đường dây
  Serial2.begin(TOC_DO_BAUD, SERIAL_8N1, RX2_PIN, TX2_PIN);
  Serial.printf("\nRS-485 %u baud, vai tro: %s\n", (unsigned)TOC_DO_BAUD, LA_NUT_CHU ? "nut chu (hoi)" : "nut to (tra loi)");
}

void loop() {
  static uint32_t soLan = 0;
  String dong;

  if (LA_NUT_CHU) {
    // Nút chủ: hỏi rồi chờ trả lời trong thời gian giới hạn
    while (Serial2.available()) {
      Serial2.read();             // Bỏ dữ liệu cũ còn sót trong bộ đệm
    }
    soLan++;
    guiDong("DOC " + String(soLan));
    if (nhanDong(dong, THOI_GIAN_CHO_TRA_LOI_MS)) {
      Serial.printf("Hoi lan %u, tra loi: %s\n", (unsigned)soLan, dong.c_str());
    } else {
      Serial.printf("Hoi lan %u: khong co tra loi\n", (unsigned)soLan);
    }
    delay(1000);
  } else {
    // Nút tớ: chỉ lên tiếng khi được hỏi
    if (nhanDong(dong, 1000) && dong.startsWith("DOC")) {
      delay(5);                   // Chờ nút chủ nhả đường dây rồi mới trả lời
      guiDong("OK " + dong.substring(4) + " " + String(millis() / 1000) + "s");
      Serial.printf("Nhan \"%s\", da tra loi\n", dong.c_str());
    }
  }
}

8. Kết quả mong đợi

Hình minh họa Serial Monitor của chương trình RS-485 trên hai mạch ESP32: nút chủ in câu trả lời OK của từng lần hỏi và báo không có trả lời khi rút dây, nút tớ in câu hỏi đã nhận
Kết quả mong đợi trên Serial Monitor của hai mạch (hình minh họa).
  1. Mở Serial Monitor của hai mạch ở 115200 baud. Nút chủ in câu trả lời của từng lần hỏi; nút tớ in câu hỏi đã nhận.
  2. Rút một dây A hoặc B: nút chủ báo khong co tra loi. Cắm lại, việc hỏi đáp tiếp tục bình thường.
  3. Thay đoạn dây ngắn bằng một cuộn dây đôi xoắn dài vài chục mét: kết quả không đổi. Đây là điều UART mức 3,3 V không làm được.

9. Xử lý lỗi thường gặp

Hiện tượngNguyên nhân thường gặpCách xử lý
Không bao giờ có trả lờiNối ngược A với B, sai tốc độ baud, hoặc cả hai mạch cùng đặt là nút chủĐổi chéo hai dây; kiểm tra hằng LA_NUT_CHU và tốc độ baud
Mất byte cuối của mỗi dòngHạ chân DE trước khi gửi xongGọi Serial2.flush() trước khi hạ DE
Câu trả lời bị hỏng phần đầuNút tớ trả lời khi nút chủ chưa kịp nhả đường dâyGiữ khoảng chờ vài mili giây trước khi nút tớ trả lời
Nhận được byte lạ khi không ai phátThiếu điện trở phân cực nên đường dây thả nổiDùng module có sẵn điện trở phân cực, hoặc thêm điện trở kéo A lên nguồn và kéo B xuống GND
Chạy với dây ngắn, lỗi với dây dàiThiếu điện trở đầu cuối, dây không xoắn, tốc độ quá caoĐặt 120 Ω ở hai đầu, dùng dây đôi xoắn, giảm tốc độ baud
ESP32 nóng hoặc chân RX2 hỏngChân RO mức 5 V nối thẳng vào ESP32Thêm mạch chia áp, hoặc dùng module RS-485 chạy 3,3 V

10. Xem thêm


Tin tức liên quan

Bluetooth Low Energy (BLE) là gì: quảng bá, GATT, dịch vụ, đặc tính và ESP32
Bluetooth Low Energy (BLE) là gì: quảng bá, GATT, dịch vụ, đặc tính và ESP32

Giải thích Bluetooth Low Energy: quảng bá và kết nối, cấu trúc GATT gồm dịch vụ, đặc tính, mô tả, UUID. Hướng dẫn cho ESP32 làm thiết bị BLE có đặc tính đọc, ghi, thông báo và thử bằng điện thoại.

Điều khiển hồng ngoại hoạt động thế nào: sóng mang 38 kHz, giao thức NEC và ESP32
Điều khiển hồng ngoại hoạt động thế nào: sóng mang 38 kHz, giao thức NEC và ESP32

Giải thích điều khiển hồng ngoại: sóng mang 38 kHz, mắt thu và giao thức NEC với khung 32 bit, mã lặp. Hướng dẫn tự giải mã phím điều khiển và tự phát lệnh bằng ESP32, không dùng thư viện ngoài.

RF 433 MHz là gì: điều chế ASK/OOK và tự viết giao thức phát, thu bằng ESP32
RF 433 MHz là gì: điều chế ASK/OOK và tự viết giao thức phát, thu bằng ESP32

Giải thích sóng RF 433 MHz và điều chế ASK/OOK, cách mã hóa bit bằng độ rộng xung và khung tin 24 bit. Hướng dẫn tự viết chương trình phát và thu trên hai mạch ESP32, không dùng thư viện ngoài.

Vòng dòng 4-20 mA là gì và cách đọc cảm biến 4-20 mA bằng ESP32
Vòng dòng 4-20 mA là gì và cách đọc cảm biến 4-20 mA bằng ESP32

Giải thích vòng dòng 4-20 mA: vì sao dùng dòng điện, vì sao bắt đầu từ 4 mA, cách đổi ra giá trị đo và ngưỡng báo lỗi. Hướng dẫn đọc bằng ESP32 qua điện trở shunt 120 Ω, với ADC có sẵn và với ADS1115.

CAN bus (phần 2): bộ lọc nhận, tốc độ bit và xử lý lỗi bus-off trên ESP32
CAN bus (phần 2): bộ lọc nhận, tốc độ bit và xử lý lỗi bus-off trên ESP32

Phần 2 về CAN bus với ESP32: đặt bộ lọc nhận theo mã lọc và mặt nạ, chọn tốc độ bit theo chiều dài dây, hiểu ba trạng thái lỗi của nút và viết chương trình theo dõi bộ đếm lỗi, tự hồi phục sau bus-off.

CAN bus (phần 1): tín hiệu, khung tin, phân xử ưu tiên và gửi nhận bằng ESP32
CAN bus (phần 1): tín hiệu, khung tin, phân xử ưu tiên và gửi nhận bằng ESP32

Giải thích CAN bus: hai dây CAN_H, CAN_L, mức trội và mức lặn, khung tin có ID 11 bit, phân xử ưu tiên, CRC và ACK. Kèm hai chương trình ESP32 dùng bộ điều khiển TWAI: tự kiểm tra và hai nút gửi nhận.

Modbus TCP/IP (phần 2): ESP32 làm máy khách và cổng chuyển đổi Modbus TCP sang RTU
Modbus TCP/IP (phần 2): ESP32 làm máy khách và cổng chuyển đổi Modbus TCP sang RTU

Hướng dẫn dùng ESP32 làm máy khách Modbus TCP đọc thanh ghi của một thiết bị trong mạng, và làm cổng chuyển đổi Modbus TCP sang Modbus RTU qua RS-485: cách đổi khung, mã thiết bị, thời gian chờ, mã lỗi 0x0B.

Modbus TCP/IP (phần 1): phần đầu MBAP và ESP32 làm máy chủ qua Wi-Fi
Modbus TCP/IP (phần 1): phần đầu MBAP và ESP32 làm máy chủ qua Wi-Fi

Giải thích Modbus TCP/IP: phần đầu MBAP, cổng 502, điểm khác với Modbus RTU. Kèm chương trình ESP32 làm máy chủ Modbus TCP qua Wi-Fi với 10 thanh ghi giữ và 8 cuộn, tự phân tích khung, không dùng thư viện.


Bình luận
Đã thêm vào giỏ hàng