RisalDash RisalDash

Гайд · RS-485 · Modbus

Читаем промышленные датчики за 1200 м по RS-485 и Modbus RTU

I²C и обычный UART сдаются после метра-двух. Когда нужно дотянуться до датчика через сарай, котельную или цех — десятки узлов, сотни метров, электрические помехи — ответ это RS-485, а язык поверх него обычно Modbus RTU. Модуль MAX485 за доллар и ESP32 доведут тебя до цели.

RS-485Modbus RTUMAX485ESP32ArduinoПромышленность

RS-485 — не новый протокол, это тот же UART-кадр, просто пущенный по витой паре дифференциальными уровнями, как в CAN. Отсюда и дальнобойность, и стойкость к помехам. Если идея в новинку — сначала загляни в раздел RS-232 / RS-485 интерактивного разбора шин: там на осциллограмме видно, почему дифференциал бьёт однопроводный сигнал.

Почему RS-485, а не UART

Подключение MAX485

MAX485 — это трансивер: с одной стороны UART, с другой — пара A/B шины RS-485. Единственный неочевидный вывод — направление: DE (driver enable) и RE (receiver enable) соединяют вместе и управляют одним GPIO — HIGH на передачу, LOW на приём.

Модуль MAX485             ESP32
-----------              -----
RO  (выход приёмника) --> RX  (напр. GPIO16)
DI  (вход передатчика) <- TX  (напр. GPIO17)
DE + RE (соединены)   <-- DIR (напр. GPIO4)   // HIGH = передача, LOW = приём
VCC                   --> 5V (модуль) / есть варианты под 3V3-логику
GND                   --> GND
A / B  -->  витая пара на шину (120 Ом на двух дальних концах)
ESP32 подключён к RS-485 трансиверу MAX485 — RO к RX, DI к TX, DE и RE связаны на GPIO направления, A и B в витую пару шины
Подключение MAX485: RO → RX, DI → TX, DE+RE на один GPIO направления, A/B в шину. Собрано в BoardLab.

Два аппаратных правила, на которых спотыкаются все: поставь терминатор 120 Ом на двух дальних концах шины (не на каждом узле) и веди A→A, B→B по всей линии. На длинных или «тихих» шинах добавь резисторы смещения, чтобы в покое линия сидела на определённом уровне.

Modbus RTU на один экран

Modbus — простейший протокол «ведущий-ведомый»: ведущий спрашивает, один ведомый отвечает, каждый кадр заканчивается CRC. В основном нужны две функции — 0x03 (чтение holding-регистров) и 0x04 (чтение input-регистров). Вот ESP32 читает два регистра у ведомого №1 библиотекой ModbusMaster, автоматически дёргая пин направления:

#include <ModbusMaster.h>
#define DIR 4                       // пин направления DE+RE
ModbusMaster node;

void preTx()  { digitalWrite(DIR, HIGH); }   // включить передатчик перед отправкой
void postTx() { digitalWrite(DIR, LOW);  }   // вернуться на приём после

void setup() {
  pinMode(DIR, OUTPUT); digitalWrite(DIR, LOW);
  Serial2.begin(9600, SERIAL_8N1, 16, 17);   // UART для RS-485
  node.begin(1, Serial2);                     // адрес ведомого 1
  node.preTransmission(preTx);
  node.postTransmission(postTx);
}

void loop() {
  // Читаем 2 holding-регистра с адреса 0x0000 (функция 0x03)
  if (node.readHoldingRegisters(0x0000, 2) == node.ku8MBSuccess) {
    uint16_t temp = node.getResponseBuffer(0);
    uint16_t hum  = node.getResponseBuffer(1);
    Serial.printf("temp=%u  hum=%u\n", temp, hum);
  }
  delay(1000);
}

Это весь паттерн: указал библиотеке свой UART, дал колбэки на пин направления и вызывай readHoldingRegisters(). Карту регистров своего датчика подставь из его даташита.

Когда не работает — типовые подозреваемые

Сделай правильно пару, терминаторы и пин направления — и один ESP32 опросит целое здание Modbus-датчиков: счётчики энергии, температурные зонды, ПЛК — по одной витой паре.

Посмотри, как дифференциальная пара несёт байт там, где обычный UART не может.