Lập trình nhúng

Giao thức truyền thông trên STM32 (Phần 6): RS-485 – tín hiệu vi sai, kết cuối và điều khiển chiều DE

RS-485 trên STM32 từ nguyên lý tín hiệu vi sai, đi dây bus với điện trở kết cuối và bias (có bảng tính) đến điều khiển chiều truyền bằng chân DE/RE, bằng GPIO hoặc Driver Enable phần cứng. Phần 6 của series giao thức truyền thông trên STM32.

10 phút đọc
Giao thức truyền thông trên STM32 (Phần 6): RS-485 – tín hiệu vi sai, kết cuối và điều khiển chiều DE

Ghi chú: sơ đồ trong bài do Capitlab vẽ để minh hoạ. Số liệu trong các bảng là giá trị tính theo công thức, cột "Đo thực tế" sẽ được cập nhật khi đo trên phần cứng. Mã nguồn soạn theo tài liệu HAL và datasheet, chưa chạy thử trên phần cứng, nên hãy kiểm tra lại trước khi dùng cho sản phẩm.

RS-485 không phải một giao thức hoàn chỉnh mà chỉ là chuẩn tầng vật lý: nó quy định mức điện áp và cách đi dây. Dữ liệu chạy bên trên thường vẫn là UART, và trên UART lại là giao thức ứng dụng như Modbus RTU (phần 7). RS-485 có mặt khắp nơi trong tự động hoá vì nó đi được xa, chịu nhiễu tốt, và cho nhiều thiết bị dùng chung một đôi dây.

Bài này nói về ba việc phải làm đúng khi đưa RS-485 lên STM32: đi dây với điện trở kết cuối và bias, nối transceiver, và chuyển chiều phát/nhận đúng lúc để không cắt mất byte cuối.

1. Nguyên lý

RS-232 đo điện áp so với GND, nên nhiễu và chênh lệch GND giữa hai thiết bị đi thẳng vào dữ liệu. RS-485 truyền hai tín hiệu ngược pha trên một cặp dây xoắn, và bên nhận chỉ nhìn hiệu giữa hai dây. Nhiễu bám vào hai dây gần như giống nhau (nhiễu chế độ chung), nên khi trừ cho nhau thì mất đi.

Dây A và B bị nhiễu giống nhau nhưng hiệu A trừ B vẫn là sóng vuông sạch với hai ngưỡng ±200 mV

Hình 1. Nhiễu chung trên A và B bị triệt tiêu ở hiệu A − B. Bên nhận quyết định mức logic theo dấu của A − B, với ngưỡng khoảng ±200 mV.

Ở tốc độ thấp (tới khoảng 100 kbit/s), RS-485 đi được khoảng 1200 m. Tốc độ càng cao thì càng ngắn, ở 10 Mbit/s chỉ còn vài chục mét. Đây là con số kinh nghiệm hay được trích, giới hạn thật phụ thuộc cáp và transceiver.

Đặc tả gốc cho phép 32 tải đơn vị trên một bus. Transceiver tải nhỏ (1/4 hoặc 1/8 tải đơn vị) cho phép gắn nhiều node hơn.

Cấu hình hay gặp là bán song công: chỉ hai dây A và B, mỗi thời điểm chỉ một node được phát, và transceiver có chân DE (Driver Enable) và RE (Receiver Enable) để đổi chiều. Cấu hình song công với hai cặp dây cũng có nhưng ít gặp hơn.

Mỗi hãng đặt tên dây một kiểu: có hãng ghi D+ và D−, có hãng ghi A và B ngược với hãng khác. Nối đúng sơ đồ mà không nhận được gì thì thử đảo hai dây.

2. Đi dây

Bus RS-485 bán song công: hai điện trở 120 ohm ở hai đầu, cặp điện trở bias kéo A lên Vcc và B xuống GND, ba node nối vào A và B

Hình 2. Bus RS-485 điển hình. Hai điện trở kết cuối ở hai đầu và một cặp điện trở bias ở một điểm (thường ở master).

Dùng cáp xoắn đôi có trở kháng đặc tính khoảng 120 Ω, đi nối tiếp từ node này sang node kia (daisy-chain). Tránh đi dây hình sao và tránh nhánh rẽ dài.

Đặt điện trở kết cuối 120 Ω ở hai đầu bus, và chỉ ở hai đầu. Khi tắt nguồn, đo giữa A và B phải được khoảng 60 Ω.

Lúc không node nào phát, bus thả nổi và bộ thu có thể đọc ra ký tự rác. Cặp điện trở bias (fail-safe) kéo A lên Vcc và B xuống GND để bus rảnh luôn ở mức "1", tức A − B lớn hơn +200 mV. Cả bus chỉ cần một cặp, thường đặt ở master. Nhiều transceiver đời mới có sẵn tính năng fail-safe bên trong.

Các node phải có GND tham chiếu chung. Trong môi trường công nghiệp, chênh lệch GND giữa các tủ có thể lớn, khi đó nên dùng transceiver cách ly.

Tính điện trở bias

Điện áp trên bus khi rảnh: VAB = Vcc × Rt / (2 × Rb + Rt), trong đó Rt là điện trở kết cuối tương đương (hai điện trở 120 Ω song song là 60 Ω) và Rb là điện trở bias mỗi bên. VAB cần lớn hơn ngưỡng +200 mV và còn dư. Bảng tính, chưa kể tải của các bộ thu vốn còn kéo VAB xuống thêm:

Vcc Rb = 390 Ω Rb = 470 Ω Rb = 560 Ω Rb = 680 Ω
5 V 357 mV 300 mV 254 mV 211 mV
3,3 V 236 mV 198 mV 168 mV 139 mV

Với Vcc = 3,3 V, Rb = 560 Ω hay 680 Ω không vượt được ngưỡng 200 mV. Cần Rb khoảng 390 Ω hoặc nhỏ hơn, tuỳ số node. Đổi lại, Rb càng nhỏ thì bus càng tốn dòng khi rảnh. Datasheet transceiver thường có khuyến nghị cụ thể, nên đọc trước khi chọn.

3. Nối với STM32

Transceiver (MAX485, SP3485, THVD1500, ADM2587E cách ly...) có bốn chân phía MCU:

Chân Tên đầy đủ Nối với
RO Receiver Output RX của STM32
DI Driver Input TX của STM32
DE Driver Enable GPIO (cao là phát)
RE Receiver Enable (tích cực thấp) Thường nối chung với DE

Khi DE và RE nối chung vào một GPIO, mức cao là phát (DE bật, RE tắt), mức thấp là nhận. Tiện thêm một điểm: lúc phát, bộ thu tắt nên node không nghe lại tiếng vọng của chính nó.

Transceiver 3,3 V (SP3485, THVD1500) nối thẳng với STM32. Transceiver 5 V như MAX485 xuất RO ở mức 5 V, cần xem chân RX của STM32 có chịu được không, thường thì thêm mạch chuyển mức hoặc cầu phân áp.

4. Mã nguồn

4.1. Điều khiển DE bằng GPIO

#define RS485_TX_EN()  HAL_GPIO_WritePin(DE_GPIO_Port, DE_Pin, GPIO_PIN_SET)
#define RS485_RX_EN()  HAL_GPIO_WritePin(DE_GPIO_Port, DE_Pin, GPIO_PIN_RESET)

void rs485_send(const uint8_t *p, uint16_t n)
{
    RS485_TX_EN();
    HAL_UART_Transmit_IT(&huart2, (uint8_t *)p, n);
}

// Chỉ trả về chế độ nhận khi byte cuối đã ra khỏi thanh ghi dịch (TC), không phải TXE
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
    if (huart == &huart2) RS485_RX_EN();
}

Giản đồ DE và TX: hạ DE ở TXE sẽ cắt byte cuối, phải hạ ở TC khi bit stop cuối đã phát xong

Hình 3. TXE xảy ra khi byte cuối vừa chuyển vào thanh ghi dịch, byte đó còn phải phát hết. TC xảy ra khi bit stop cuối đã ra khỏi chân. Hạ DE phải ở TC.

Khi dùng HAL_UART_Transmit_IT hoặc DMA, HAL gọi HAL_UART_TxCpltCallback ở ngắt TC (truyền xong hoàn toàn), nên hạ DE trong callback này là đúng. Nếu tự viết ngắt và hạ DE ngay khi thanh ghi dữ liệu trống (TXE), byte cuối còn nằm trong thanh ghi dịch sẽ bị cắt.

Bảng dưới là thời gian tính cho một byte 8N1. Ở tốc độ cao, chuyển chiều sớm chừng chục µs là đủ mất cả byte:

Baudrate Thời gian 1 byte (10 bit)
9 600 1041,7 µs
19 200 520,8 µs
115 200 86,8 µs
921 600 10,85 µs
1 000 000 10,0 µs

4.2. Nhận lại sau khi phát

Hạ DE xong là thiết bị phải nhận được ngay. Nếu dùng cách nhận bằng DMA và IDLE ở phần 1, cứ để phần nhận chạy liên tục, chỉ đổi chiều transceiver. Với DE và RE nối chung, bộ thu tắt trong lúc phát nên bộ đệm nhận không bị lẫn tiếng vọng.

4.3. Driver Enable phần cứng của USART

Nhiều dòng STM32 có chân USARTx_DE: phần cứng tự bật transceiver trong lúc phát, với thời gian đệm trước và sau khung cấu hình được. Trong CubeMX, bật RS485 Hardware Flow Control (hoặc khởi tạo bằng HAL_RS485Ex_Init), chọn cực tính DE và thời gian assertion/de-assertion, đơn vị 1/16 bit, từ 0 đến 31. Cách này chính xác tới từng bit và không phụ thuộc độ trễ ngắt, nên chip có hỗ trợ thì dùng.

// Khởi tạo thay cho HAL_UART_Init (ví dụ):
if (HAL_RS485Ex_Init(&huart2, UART_DE_POLARITY_HIGH, 8, 8) != HAL_OK) Error_Handler();

// Sau đó chỉ cần gửi bình thường, phần cứng tự bật tắt DE:
HAL_UART_Transmit(&huart2, buf, len, 100);

5. Lỗi thường gặp

Triệu chứng Nguyên nhân thường gặp Cách xử lý
Nhận được rác khi không ai phát Thiếu điện trở bias, bus thả nổi Thêm cặp bias hoặc dùng transceiver fail-safe
Mất byte cuối của gói Hạ DE ở TXE thay vì TC Hạ DE ở HAL_UART_TxCpltCallback hoặc dùng USART_DE phần cứng
Hai node phát cùng lúc, dữ liệu hỏng RS-485 không có phân xử như CAN Dùng giao thức hỏi đáp master-slave để chỉ một node phát
Lỗi khi tốc độ cao hoặc bus dài Thiếu hoặc thừa điện trở kết cuối, nhánh rẽ quá dài Đo A-B bằng oscilloscope, chỉ để điện trở ở hai đầu
Không nhận được dữ liệu dù nối đúng A và B nối ngược do ký hiệu khác nhau giữa các hãng Thử đảo A và B
Một node làm hỏng cả bus Node lỗi giữ DE ở mức phát Thêm cơ chế thời gian chờ (watchdog) hạ DE
Nhiễu mạnh, mất khung ngẫu nhiên Cáp không xoắn, GND chênh lệch Dùng cáp xoắn có bọc, transceiver cách ly

6. Lưu ý khi thiết kế

Nhánh rẽ (stub) càng ngắn càng tốt, lý tưởng là bằng 0, tức mọi node nằm ngay trên đường bus.

Trong môi trường công nghiệp, chân A và B cần bảo vệ: điện trở nối tiếp, diode TVS dành cho RS-485, và ống phóng điện khí nếu có nguy cơ sét lan truyền.

Với bus dài và tốc độ cao, chọn transceiver có giới hạn tốc độ sườn (slew-rate limited) để giảm dội, và chỉ chạy tốc độ vừa đủ dùng.

RS-485 không có phân xử, nên giao thức bên trên phải quy định ai được nói và khi nào. Giao thức hỏi đáp như Modbus RTU còn yêu cầu khoảng lặng rõ ràng giữa các khung.

7. Kế hoạch đo thực tế

Cột "Đo thực tế" để trống cho đến khi chạy trên phần cứng.

Thử nghiệm Cách đo Giá trị tính toán Đo thực tế
Điện trở bus khi tắt nguồn Đồng hồ vạn năng giữa A và B Khoảng 60 Ω (điền sau)
Điện áp vi sai A-B khi rảnh, có và không có bias Oscilloscope vi sai hoặc hai kênh trừ nhau Theo bảng ở mục 2 (điền sau)
Dạng sóng ở 9600, 115200 và 1 Mbaud, có và không có điện trở kết cuối Oscilloscope, quan sát dội Dội rõ khi thiếu kết cuối (điền sau)
Độ trễ chuyển chiều DE (GPIO so với phần cứng) Logic analyzer: DE so với TX Phần cứng: theo thời gian assertion/de-assertion đặt (điền sau)
Khoảng cách tối đa ở mỗi tốc độ Tăng dần chiều dài cáp, ghi nhận lúc lỗi bắt đầu Theo quy tắc kinh nghiệm ở mục 1 (điền sau)
Tỷ lệ lỗi khi có nhiễu (gần động cơ hoặc biến tần) Gửi 1 triệu byte, đếm lỗi Không lỗi nếu cáp tốt (điền sau)

8. Hỏi đáp

RS-485 khác RS-232 thế nào? RS-232 nối điểm-điểm, tín hiệu tính theo GND (±3 đến ±15 V), tầm ngắn. RS-485 vi sai, nhiều node, đi xa và chịu nhiễu tốt hơn nhiều. Bên trên cả hai thường vẫn là UART.

RS-485 và RS-422 khác gì nhau? RS-422 cũng vi sai nhưng chỉ một bộ phát với nhiều bộ thu, thường dùng hai cặp dây song công. RS-485 cho phép nhiều bộ phát, nên chạy được bán song công trên hai dây.

Bus ngắn, tốc độ thấp có cần kết cuối không? Vài mét ở 9600 baud thường vẫn chạy khi không có kết cuối, nhưng gắn vào vẫn an toàn hơn. Bus dài hoặc tốc độ cao thì bắt buộc.

Chạy Modbus trên RS-485 được không? Được, đây là cách dùng phổ biến nhất. Xem phần 7: Modbus.

Kết luận

Điện trở 120 Ω chỉ đặt ở hai đầu, cả bus một cặp bias. Hạ DE ở ngắt TC, hoặc dùng USART_DE phần cứng, để không cắt byte cuối. RS-485 không phân xử, nên giao thức bên trên phải lo chuyện ai được nói.

Phần 7 dựng Modbus RTU trên RS-485: khung dữ liệu, CRC-16 và khoảng lặng 3,5 ký tự.

Tài liệu tham khảo

  • TIA/EIA-485, datasheet transceiver (MAX485, SP3485, THVD1500...)
  • Tài liệu STM32 về USART Driver Enable (HAL_RS485Ex_Init) và reference manual của dòng chip bạn dùng