В большинстве случаев схемы на микроконтроллерах используются для связи с периферийными устройствами (датчиками, дисплеями, реле и т.п.) на небольшие расстояния – обычно в пределах нескольких сантиметров. В этих случаях для связи используются обычные провода и нет необходимости беспокоиться о затухании сигнала, действующих шумах и искажениях сигнала. Но если вам понадобится осуществить связь на расстояние хотя бы больше 10 метров, то в этом случае вам уже придется задуматься о мощности передаваемого сигнала, его затухании и воздействии на него шумов – без учета этих вопросов вам не удастся обеспечить надежную связь.
В этой статье мы рассмотрим использование протокола RS485 для связи на большие расстояния. Протокол RS485 достаточно часто используется для связи на значительные дистанции в условиях воздействия сильных индустриальных помех, поэтому он хорошо подойдет для решения стоящей перед нами задачи. В данном проекте мы будем использовать модуль MAX485, подключаемый к плате Arduino Nano, для реализации передачи данных на большие расстояния. Ранее на нашем сайте мы уже рассматривали использование протокола RS485 для связи между двумя платами Arduino и для связи между платами Arduino и Raspberry Pi.
Различие между UART и связью по протоколу RS485
Большинство современных электронных устройств (модули GPS, Bluetooth, RFID и т.п.) и микроконтроллеры используют для последовательной связи UART (Universal Asynchronous Receiver/Transmitter – универсальный асинхронный приёмопередатчик) на логике TTL. Одним из его достоинств является то, что он требует всего 2 провода (TX (Transmitter — передатчик) и RX (Receiver — приемник)) для осуществления связи. UART не является стандартным протоколом связи, но он представляет собой физическую цепь, по которой вы можете последовательно передавать/принимать данные периферийным устройствам. UART использует последовательную передачу данных, поэтому перед передачей данные необходимо преобразовать из параллельной формы в последовательную.
UART является асинхронным устройством, что означает что он не использует синхронизацию (импульсы синхронизации) для передачи данных от передатчика к приемнику, вместо этого он использует стартовые и стоповые биты, благодаря которым приемник может распознавать начало и конец передачи данных. В UART передача данных организована с помощью пакетов. Каждый пакет содержит 1 стартовый бит, от 5 до 9 бит данных (в зависимости от типа UART), опционально бит четности (для проверки возникла ли ошибка при передаче) и 1 или 2 стоповых бита. UART является достаточно эффективным протоколом и находит широкое применение в современной электронике, однако ему присущи такие недостатки как невозможность поддержки нескольких ведущих и ведомых устройств и максимальный пакет данных в нем ограничен 9 битами. На представленном ниже рисунке показан принцип передачи одного символа в UART. Сигналы High и Lows измеряются по отношению к уровню GND (общий провод, земля), поэтому изменение уровня GND оказывает крайне негативный эффект на передачу данных.
С другой стороны, протокол RS485 ориентирован на обеспечение связи в промышленных средах, в сетях с множеством устройств, и может использоваться для связи на большие расстояния с достаточно большой скоростью передачи данных. Он использует для передачи данных дифференциальный сигнал, который обладает значительно лучшей помехоустойчивостью чем униполярный сигнал, применяемый в UART. Для передачи сигналов в проколе RS485 используются линии Sig+ и Sig-.
Приемник RS485 сравнивает различие уровней напряжения на обоих линиях вместо измерения абсолютного уровня напряжения на одной линии (как в UART). Этот подход также защищает от помех со стороны контура заземления, которые достаточно часто являются причиной проблем со связью. Наибольший эффект в данном случае достигается когда линии Sig+ и Sig- скручены в витую пару, что позволяет эффективно бороться с различными электромагнитными помехами, наводимыми в кабеле, что позволяет передавать данные на расстояние до 1200 метров. Витая пара также позволяет увеличить скорость передачи по сравнению с прямолинейными кабелями. Протокол RS485 позволяет достигать скорости передачи данных 35 Мбит/с, хотя с увеличением расстояния скорость передачи данных уменьшается. На максимальной дистанции 1200 метров максимальная возможная скорость передачи составляет 100 кбит/с
Для связи на большие расстояния с помощью протокола RS485 понадобится Ethernet кабель. Существуют Ethernet кабели различных категорий: CAT-4, CAT-5, CAT-5E, CAT-6, CAT-6A и т.п. В нашем проекте мы использовали кабель CAT-6E, который содержит 4 витые пары проводников 24AWG и поддерживает частоты до 600 МГц. На обоих концах кабель заканчивается разъёмами RJ45. Типовое линейное напряжение в подобном кабеле составляет величину от ±1.5 V до ±6 V (максимальный уровень). Чувствительность приемного устройства в такой линии составляет ±200 mV. На следующем рисунке представлен пример передачи байта 0x3E по линии связи с помощью протокола RS485.
Необходимые компоненты
- Плата Arduino Nano – 2 шт. (купить на AliExpress).
- Модуль преобразования MAX485 – 2 шт. (купить на AliExpress).
- ЖК дисплей 16х2 – 2 шт. (купить на AliExpress).
- Подстроечный потенциометр 10 кОм – 2 шт. (купить на AliExpress).
- Ethernet кабель категории Cat-6E (купить на AliExpress).
- Макетная плата.
- Соединительные провода.
Реклама: ООО «АЛИБАБА.КОМ (РУ)» ИНН: 7703380158
Схема проекта
Схема для осуществления связи на большие расстояния по Ethernet кабелю с помощью Arduino и RS485 представлена на следующем рисунке. Приведена схема передающей и приемной частей проекта.
Каждая часть (приемная и передающая) схемы содержит плату Arduino Nano, алфавитно-цифровой ЖК дисплей 16х2 и модуль преобразования UART в RS485 под названием MAX485. Модуль RS485 подключается к Ethernet кабелю категории Cat-6E при помощи разъема RJ45. В нашем проекте мы использовали кабель длиной 25 метров.
На передающей стороне мы с помощью платы Arduino Nano формируем набор данных для передачи, передаем их модулю MAX485, который работает в качестве ведущего устройства (Master Mode) и преобразует эти данные в формат протокола RS485. На приемном конце модуль MAX485, работающий в режиме ведомого (Slave), “прислушивается” к тому что передает ведущее устройство (Master) и в случае приема данных он их конвертирует в формат UART с логическими уровнями 5V TTL, которые принимаются платой Arduino Nano и отображаются на экране ЖК дисплея 16х2.
Модуль MAX485 (преобразования RS485 в UART)
Модуль преобразования UART-RS485 имеет встроенный чип MAX485, который представляет собой маломощный приемопередатчик, работающий по протоколу RS-485 и поддерживающий различные скорости передачи. Он работает от напряжения +5V, его номинальный ток составляет 300 μA. Модуль MAX485 работает в полудуплексном режиме чтобы осуществлять функции преобразования уровней TTL в уровни RS-485, что означает, что в один и тот же момент времени он может либо передавать, либо принимать, но никак не может выполнять эти функции одновременно. Модуль поддерживает максимальную скорость передачи до 2,5 Мбит/с. Ток потребления модуля составляет от 120μA (в ненагруженном состоянии) до 500μA (в условиях полной загрузки) при отключенном драйвере. Драйвер защищает от тока короткого замыкания. Вход приемника имеет защищенный от сбоев блок (узел), который гарантирует на выходе логику высокого уровня если вход работает в режиме открытой цепи. В дополнение к этому он имеет хорошую защиту от помех. Также модуль содержит в своем составе светодиоды, которые показывают текущее состояние чипа – подается ли на него питание, передает или принимает он информацию, что упрощает процессы отладки схемы при работе с данным модулем.
На представленном ниже рисунке показаны способы подключения модуля MAX485 к другим электронным компонентам. Модуль обеспечивает стандартные для макетных плат промежутки 0.1 дюйма между контактами.
Ethernet кабель категории CAT-6E
Часто, когда речь заходит о передаче информации на большие расстояния, подразумевается использование Ethernet кабеля. И раньше, когда еще не было технологии Wi-Fi, все компьютеры подключались к интернету, именно с помощью подобных кабелей. Основной причиной, почему в большинстве случаев для передачи информации на большие расстояния в настоящее время используются именно Ethernet кабели, а не обычные провода, является то, что Ethernet кабели значительно лучше защищают сигнал от шумов и искажений. Они имеют оплетку поверх изоляционного слоя, что обеспечивает им хорошую защиту от электромагнитных помех. Также каждая пара проводов в таком кабеле скручена в витую пару, что также способствует защите от шумов и помех. Часто такие кабели заканчиваются на концах 8-контактным разъемом RJ45. Существует много категорий Ethernet кабелей: CAT-4, CAT-5, CAT-5E, CAT-6, CAT-6A и т.п. В нашем проекте мы использовали кабель категории CAT-6E, который содержит 4 витые пары проводников 24AWG и поддерживает частоты до 600 МГц.
На следующих рисунках представлена внутренняя структура Ethernet кабеля категории CAT-6E и схема соединений его проводников с разъемом RJ45.
Объяснение программы для Arduino
Полный код программы приведен в конце статьи, здесь же мы кратко рассмотрим его основные фрагменты.
В данном проекте мы будем использовать две платы Arduino Nano, одну в передающей части и одну в приемной части. Для отображения результатов мы будем использовать ЖК дисплеи 16х2. Таким образом, в коде программ для плат Arduino нам необходимо будет сосредоточиться на передаче/приеме данных и их отображении на экране ЖК дисплея 16х2.
Объяснение кода программы для передающей части
Программу для передающей части мы начнем с подключения библиотеки для работы с ЖК дисплеем и объявления (присвоения осмысленного имени) контакта D8, через который будет осуществляться управление передачей информации. Также мы создадим объект для работы с ЖК дисплеем и сообщим плате Arduino контакты, к которым подключен ЖК дисплей.
1 2 3 4 |
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 |
Далее в функции setup мы инициализируем последовательную связь со скоростью 9600 бод и зададим режим работы на вывод данных (OUTPUT) для контакта enablePin – чтобы перевести модуль MAX485 в режим передачи на этот контакт необходимо подать напряжение высокого уровня (high). Поскольку модуль MAX485 способен работать только в полудуплексном режиме, то в один момент времени он может либо передавать, либо принимать информацию. Также в функции setup мы инициализируем ЖК дисплей и отобразим на его экране приветственное сообщение.
1 2 3 4 5 6 7 8 |
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(); |
В функции loop мы будем последовательно увеличивать значение переменной целого типа, которое затем по последовательному каналу будет передаваться другой плате Arduino. Также для целей отладки мы будем выводить это передаваемое значение на экран ЖК дисплея.
1 2 3 4 5 6 7 8 9 |
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; |
Объяснение кода программы для приемной части
Код программы приемной части мы также начнем с подключения стандартной библиотеки для работы с ЖК дисплеем и объявления контакта D8. Также мы создадим объект для работы с ЖК дисплеем и сообщим плате Arduino контакты, к которым подключен ЖК дисплей.
1 2 3 |
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 |
В функции setup мы инициализируем последовательную связь со скоростью 9600 бод и зададим режим работы на вывод данных (OUTPUT) для контакта enablePin – чтобы перевести модуль MAX485 в режим приема на этот контакт необходимо подать напряжение низкого уровня (LOW). Также в функции setup мы инициализируем ЖК дисплей и отобразим на его экране приветственное сообщение.
1 2 3 4 5 6 7 8 |
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) |
Затем в функции loop мы будем проверять поступает ли какая либо информация по последовательному порту. Если поступает, то мы будем считывать из него значение целого типа и отображать его на экране ЖК дисплея.
1 2 3 4 5 6 7 8 9 |
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(); |
Тестирование работы проекта
Более подробно работу проекта можно посмотреть на видео, приведенном в конце статьи. Тестирование проекта в нашем случае будет заключаться в том, что мы с помощью протокола RS485 будем передавать на большое расстояние постепенно увеличивающееся значение целого типа. Для целей тестирования мы использовали скорость передачи всего 9600 бод. Если вам интересно, вы можете попробовать использовать и другие возможные в протоколе RS485 скорости передачи данных. Но при использовании платы Arduino достичь максимальной скорости, возможной в протоколе RS485, не удастся – но в большинстве практических случаев такие высокие скорости при работе с платой Arduino и не требуются.
Исходный код программы (скетча)
Для передающей части
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
int enablePin = 8; int potval =0 ; #include <LiquidCrystal.h> //библиотека для работы с ЖК дисплеем LiquidCrystal lcd(2,3,4,5,6,7); // Define LCD display pins RS,E,D4,D5,D6,D7 void setup() { Serial.begin(9600); // инициализируем последовательную связь со скоростью 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); // (на этом контакте всегда должен быть high чтобы Master (ведущее устройство) могло передавать данные Slave (ведомому устройству)) } void loop() { Serial.print("Sent Value= "); Serial.println(potval); //последовательно передаем значение POTval через шину RS-485 lcd.setCursor(0,0); lcd.print("Sent Value"); lcd.setCursor(0,1); lcd.print(potval); delay(1000); lcd.clear(); potval+=1; } |
Для приемной части
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
int enablePin = 8; #include <LiquidCrystal.h> // библиотека для работы с ЖК дисплеем functions LiquidCrystal lcd(2,3,4,5,6,7); // Define LCD display pins RS,E,D4,D5,D6,D7 void setup() { Serial.begin(9600); // инициализируем последовательную связь со скоростью 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 всегда должно быть LOW чтобы принимать данные от Master (ведущего устройства)) } void loop() { while (Serial.available()) //этот цикл выполняется пока есть какие либо данные в последовательном порту { int pwmval = Serial.parseInt(); //принимаем значение целого типа (INTEGER value) от Master по протоколу 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(); } } |