Как надёжно связать две платы Arduino длинным проводом, когда обычные перемычки уже не справляются с помехами. Решение — промышленный интерфейс RS485, недорогой модуль на MAX485 и обычный сетевой кабель витая пара.
Когда перемычек уже мало
В типичных самоделках на Arduino, Raspberry Pi, NodeMCU, ESP8266 или MSP430 датчики, реле и исполнительные механизмы стоят в считанных сантиметрах от платы. Здесь хватает обычных проводов-перемычек: искажения сигнала и наводки на такой длине не успевают проявиться. Если же система управления растягивается больше чем на 10-15 метров, приходится учитывать помехи и мощность сигнала. Иначе часть данных теряется по дороге, и о надёжной работе можно забыть.
Из последовательных интерфейсов с Arduino легко работают I2C и SPI, но на больших расстояниях применяют другой — RS485. Он очень распространён в промышленности, где линии длинные, а помех много. Ниже разобрано, как устроен этот интерфейс, чем он отличается от привычного UART и как связать им две платы Arduino Nano через модули-преобразователи UART-RS485 на микросхеме MAX485.
UART и RS485: в чём разница
Большинство недорогих модулей (GPS, Bluetooth, RFID, ESP8266 и им подобные) общаются с контроллером по UART с TTL-уровнями. Причина — простота: нужны всего два провода, TX (передача) и RX (приём). Строго говоря, UART — не стандартный протокол, а аппаратный узел. Он переводит параллельные данные в последовательную форму и передаёт их бит за битом.
Передача асинхронная: общего тактового сигнала нет, а начало и конец каждой посылки отмечают стартовый и стоповый биты. Пакет состоит из:
- одного стартового бита;
- от 5 до 9 бит данных (зависит от конкретного UART);
- необязательного бита чётности для контроля ошибок;
- одного или двух стоповых битов.
UART хорошо документирован и применяется повсеместно, но ограничения у него серьёзные. Нельзя подключить несколько ведущих и несколько ведомых устройств, кадр данных не длиннее 9 бит, а скорости обмена у ведущего и ведомого должны различаться не более чем на 10%. Для длинных линий важнее всего другое: высокий и низкий уровни отсчитываются от общего провода GND. Поэтому любой сдвиг потенциала земли между устройствами губителен для передачи. На рисунке показано, как по линии UART передаётся символ.
RS485 разрабатывали для промышленных сетей из многих устройств, работающих на больших расстояниях и с более высокими скоростями. Напряжение здесь не измеряется относительно GND — применяется дифференциальная передача. Сигналы «плавающие», не привязанные к земле, и каждый идёт по паре линий Sig+ и Sig-. Приёмник сравнивает разность напряжений между ними, а не абсолютный уровень на одном проводе. Так не возникают земляные петли — частая причина сбоев связи.
Лучший результат получается, когда линии Sig+ и Sig- свиты между собой. Скрутка гасит электромагнитные помехи, наведённые на кабель, и заметно повышает помехоустойчивость. Благодаря этому RS485 передаёт данные на расстояние до 1200 м, а по витой паре достижимы скорости намного выше, чем по прямым проводам. На коротких линиях можно получить до 35 Мбит/с, но с ростом длины скорость падает: на 1200 м остаётся лишь 100 кбит/с. Поэтому для такой связи нужен специальный кабель — сетевая витая пара (о ней ниже).
Типичное выходное напряжение драйверов линии — от ±1,5 В (минимум) до примерно ±6 В (максимум). Чувствительность входа приёмника — ±200 мВ. Помехи в пределах ±200 мВ фактически блокируются благодаря подавлению синфазной составляющей. На рисунке показано, как по двум линиям RS485 передаётся байт 0x3E.
Кабель: витая пара CAT-6E и разъём RJ-45
Когда речь заходит о передаче данных на расстояние, сразу вспоминается Ethernet. Сейчас в интернет выходят в основном по Wi-Fi, а раньше к каждому компьютеру тянули сетевой кабель. Его выбирали вместо обычных проводов потому, что на больших длинах он гораздо лучше защищён от помех и искажений сигнала. Поверх изоляции у него экранирующая оболочка против электромагнитных наводок. Провода каждой пары свиты между собой, что препятствует образованию токовых петель и дополнительно защищает от помех.
Сетевые кабели бывают разных категорий: CAT-4, CAT-5, CAT-5E, CAT-6, CAT-6A и другие. В проекте использован CAT-6E — четыре витые пары проводников 24AWG, полоса до 600 МГц. На обоих концах кабель оконцован 8-контактными разъёмами RJ-45. На снимке видно, как свиты пары внутри изоляции кабеля CAT-6E.
Модуль-преобразователь UART-RS485 на MAX485
Основа модуля — микросхема MAX485, маломощный приёмопередатчик RS-485 с ограниченной скоростью нарастания выходного сигнала (slew-rate limited). Модуль переводит TTL-уровни UART в уровни RS-485 и обратно. Основные характеристики:
- питание от одного источника +5 В, номинальный ток — 300 мкА;
- полудуплексный режим: в каждый момент модуль либо передаёт, либо принимает, но не то и другое сразу;
- максимальная скорость передачи — 2,5 Мбит/с;
- при отключённом драйвере ток потребления — от 120 мкА без нагрузки до 500 мкА при полной нагрузке;
- ток короткого замыкания драйвера ограничен; схема тепловой защиты может перевести выходы драйвера в высокоимпедансное состояние;
- вход приёмника защищён от обрыва (fail-safe): при разомкнутом входе на выходе гарантированно логическая единица;
- высокая помехоустойчивость.
Светодиоды на плате показывают состояние микросхемы: есть ли питание, идёт ли передача или приём. С ними проще отлаживать связь. Выводы модуля разведены на штыревые разъёмы со стандартным шагом 0,1 дюйма, поэтому его удобно ставить на макетную плату. На схеме показано, как MAX485 соединена с остальными элементами модуля.
Схема соединений
Система состоит из двух почти одинаковых половин. Схемы передатчика и приёмника идентичны, различаются только прошивки. Для демонстрации одна плата работает передатчиком, а другая — приёмником. При той же схеме обе платы можно запрограммировать так, чтобы каждая и передавала, и принимала.
Ниже — монтажная схема тех же соединений.
Нажмите для увеличения (1000x517)
Для сборки понадобятся:
- две платы Arduino Nano;
- два символьных ЖК-индикатора 16x2;
- два модуля UART-RS485 на MAX485;
- кабель витая пара CAT-6E длиной 25 м с разъёмами RJ-45;
- два потенциометра 10 кОм.
Каждый модуль MAX485 подключён через разъём RJ-45 к своему концу кабеля. Передающая Nano выдаёт данные в UART. Её модуль MAX485 работает ведущим (Master): преобразует эти данные в сигналы RS485 и отправляет в кабель. Модуль на приёмной стороне — ведомый (Slave). Он слушает линию и превращает принятое обратно в стандартные 5-вольтовые TTL-сигналы UART. Их читает вторая Nano и выводит на свой индикатор.
Программа
Обе прошивки начинаются одинаково. Подключается стандартная библиотека LiquidCrystal, и задаются выводы индикатора: RS, E, D4-D7 подключены к выводам D2-D7 Nano. Вывод D8 объявлен как enablePin — через него модуль MAX485 переключается между передачей и приёмом. Микросхема полудуплексная, поэтому направление обмена нужно задать явно. В setup() последовательный порт запускается на скорости 9600 бод, инициализируется индикатор, и на 3 секунды выводится приветствие.
Передатчик. В setup() на enablePin подаётся высокий уровень, и модуль всё время остаётся в режиме передачи — ведущий только пишет данные ведомому. В loop() раз в секунду в последовательный порт уходит целое число potval, которое каждый раз увеличивается на единицу. То же значение выводится на индикатор для контроля и отладки.
int enablePin = 8;
int potval =0 ;
#include <LiquidCrystal.h> //Include LCD library for using LCD display functions
LiquidCrystal lcd(2,3,4,5,6,7); // Define LCD display pins RS,E,D4,D5,D6,D7
void setup()
{
Serial.begin(9600); // initialize serial at baudrate 9600:
pinMode(enablePin, OUTPUT);
lcd.begin(16,2);
lcd.print("CIRCUIT DIGEST");
lcd.setCursor(0,1);
lcd.print("Transmitter Nano");
delay(3000);
lcd.clear();
digitalWrite(enablePin, HIGH); // (always high as Master Writes data to Slave)
}
void loop()
{
Serial.print("Sent Value= ");
Serial.println(potval); //Serial Write POTval to RS-485 Bus
lcd.setCursor(0,0);
lcd.print("Sent Value");
lcd.setCursor(0,1);
lcd.print(potval);
delay(1000);
lcd.clear();
potval+=1;
}
Приёмник. Здесь в setup() на enablePin подаётся низкий уровень, и модуль постоянно слушает линию. В loop(), пока в последовательном порту есть данные, функция Serial.parseInt() извлекает из них целое число, и оно выводится на индикатор. Текстовая приставка «Sent Value= », которую передатчик отправляет перед числом, не мешает: parseInt() пропускает нецифровые символы.
int enablePin = 8;
#include <LiquidCrystal.h> //Include LCD library for using LCD display functions
LiquidCrystal lcd(2,3,4,5,6,7); // Define LCD display pins RS,E,D4,D5,D6,D7
void setup()
{
Serial.begin(9600); // initialize serial at baudrate 9600:
pinMode(enablePin, OUTPUT);
lcd.begin(16,2);
lcd.print("CIRCUIT DIGEST");
lcd.setCursor(0,1);
lcd.print("Receiver Nano");
delay(3000);
digitalWrite(enablePin, LOW); // (Pin 8 always LOW to receive value from Master)
}
void loop()
{
while (Serial.available()) //While have data at Serial port this loop executes
{
int pwmval = Serial.parseInt(); //Receive INTEGER value from Master throught RS-485
Serial.print("I got value");
Serial.println(pwmval);
lcd.setCursor(0,0);
lcd.print("Received Value");
lcd.setCursor(0,1);
lcd.print(pwmval);
delay(1000);
lcd.clear();
}
}
Испытания и выводы
Так выглядел испытательный стенд с 25-метровым кабелем между платами.
Такая связь — один из самых простых способов передать данные на большое расстояние. Выбранная в проекте скорость обмена намного ниже предельной для MAX485, но её хватает для большинства датчиков. Максимальная пропускная способность при работе с Arduino и другими отладочными платами обычно не нужна — разве что кабель используется как полноценное Ethernet-соединение и требуется вся полоса. Имеет смысл поэкспериментировать со скоростью обмена и попробовать кабели других категорий.
Похожие материалы на сайте