Интерфейс RS-485
RS-485 является одним из наиболее распространенных интерфейсов передачи данных.
Для передачи сигнала используется всего два провода. Обычно применяется витая пара UTP, но можно использовать и простой кабель. Ну, а связка Arduino и RS-485 открывает большие возможности в различных DIY проектах.
Интересные факты о RS-485
Максимальная длина линии интерфейса RS-485 составляет 1200 метров и подключить к одному кабелю можно до 32 устройств. Предком интерфейса RS-485 является RS-232.
Преимущество связки Arduino RS-485
- Длина линии связи, которая может достигать 1200 метров.
- Подключение к одной линии до 32 устройств.
- Помехоустойчивость.
- Простота реализации.
- Любая Arduino может быть ведущим или ведомым устройством.
Недостатки RS-485
- Скорость уменьшается с увеличением длины провода.
- Полудуплексный режим, то есть прием и передача производится по одной паре проводов.
RS-485 на практике
При передачи данных на расстояние от 500 метров потребуется экранированный UTP кабель. Скорость может снизиться до 50 Кбит/с, но этого вполне достаточно для передачи показаний с датчиков.
Схема подключения Arduino по RS-485
Для подключения плат Arduino по интерфейсу RS-485 потребуется конвертирующий модуль на базе MAX485. Это
Модуль TTL to RS-485
Преобразователь логики Arduino в RS-485
Схема соединения двух Arduino UNO
Код программы для Arduino RS-485
Программа для одностороннего приема и передачи
Напомним, что в один момент времени устройство может либо принимать, либо отправлять данные. Для указания устройства в качестве приемника или передатчика на модулях присутствуют контакты DE и RE. Высокий уровень на контактах — режим передатчика, низкий — приёмника.
Программа для передатчика — Она будет отправлять в Serial Port строку «test» один раз в секунду.
Программа для приемника — При появлении в эфире строки «test» будет мигать светодиодом на плате Arduino (13 пин).
Код программы приемника
#define SerialTxControl 2 // Пин 2 будет переключать режим приёмник/передатчик #define RS485Transmit HIGH #define RS485Receive LOW void setup(void) { Serial.begin(9600); // задаем скорость последовательного порта pinMode(SerialTxControl, OUTPUT); digitalWrite(SerialTxControl, RS485Transmit); // переводим устройство в режим передатчика } void loop(void) { Serial.print("test"); // отправляем текст delay(1000); // Выставляем задержку в 1 секунду }
Код программы передатчика
#define SerialTxControl 2 // Пин 2 будет переключать режим приёмник/передатчик #define RS485Transmit HIGH #define RS485Receive LOW char buffer[100]; // Переменная для хранения данных из буфера byte state = 0; void setup(void) { Serial.begin(9600); // задаем скорость последовательного порта pinMode(13, OUTPUT); pinMode(SerialTxControl, OUTPUT); digitalWrite(SerialTxControl, RS485Receive); // переводим устройство в режим приёмника } void loop(void) { int i=0; if( Serial.available() ){ // если в порт пришли какие-то данные delay(5); // немного ждём, чтобы вся пачка данных была принята портом while( Serial.available() ){ buffer[i++] = Serial.read(); // считываем данные и записываем их в буфер } } if(i>0){ // если в буфере что-то есть buffer[i++]='#define SerialTxControl 2 // Пин 2 будет переключать режим приёмник/передатчик #define RS485Transmit HIGH #define RS485Receive LOW char buffer[100]; // Переменная для хранения данных из буфера byte state = 0; void setup(void) { Serial.begin(9600); // задаем скорость последовательного порта pinMode(13, OUTPUT); pinMode(SerialTxControl, OUTPUT); digitalWrite(SerialTxControl, RS485Receive); // переводим устройство в режим приёмника } void loop(void) { int i=0; if( Serial.available() ){ // если в порт пришли какие-то данные delay(5); // немного ждём, чтобы вся пачка данных была принята портом while( Serial.available() ){ buffer[i++] = Serial.read(); // считываем данные и записываем их в буфер } } if(i>0){ // если в буфере что-то есть buffer[i++]='\0'; // превращаем содержимое буфера в строку, добавляя нулевой символ if( strcmp(buffer, "test") ){ // если принятая строка равна тексту ping digitalWrite(13, state); // мигаем светодиодом state = !state; } } }'; // превращаем содержимое буфера в строку, добавляя нулевой символ if( strcmp(buffer, "test") ){ // если принятая строка равна тексту ping digitalWrite(13, state); // мигаем светодиодом state = !state; } } }
Программа для двухстороннего приема и передачи данных
Код программы для первой платы Arduino
Теперь платы Arduino буду менять режим приемника/передатчика в момент отправки сообщения.
#define SerialTxControl 2 #define RS485Transmit HIGH #define RS485Receive LOW char buffer[100]; byte state = 0; void setup(void) { Serial.begin(115200); pinMode(13, OUTPUT); pinMode(SerialTxControl, OUTPUT); digitalWrite(SerialTxControl, RS485Receive); } void loop(void) { int i=0; if( Serial.available() ){ delay(5); while( Serial.available() ){ buffer[i++] = Serial.read(); } if(i>0){ buffer[i++]='#define SerialTxControl 2 #define RS485Transmit HIGH #define RS485Receive LOW char buffer[100]; byte state = 0; void setup(void) { Serial.begin(115200); pinMode(13, OUTPUT); pinMode(SerialTxControl, OUTPUT); digitalWrite(SerialTxControl, RS485Receive); } void loop(void) { int i=0; if( Serial.available() ){ delay(5); while( Serial.available() ){ buffer[i++] = Serial.read(); } if(i>0){ buffer[i++]=''; if( !strcmp(buffer, "ping") ){ digitalWrite(13, state); state = !state; digitalWrite(SerialTxControl, RS485Transmit); Serial.print("pong"); delay(10); digitalWrite(SerialTxControl, RS485Receive); } } } }#define SerialTxControl 2 #define RS485Transmit HIGH #define RS485Receive LOW char buffer[100]; byte state = 0; void setup(void) { Serial.begin(115200); pinMode(13, OUTPUT); pinMode(SerialTxControl, OUTPUT); digitalWrite(SerialTxControl, RS485Receive); } void loop(void) { int i=0; if( Serial.available() ){ delay(5); while( Serial.available() ){ buffer[i++] = Serial.read(); } if(i>0){ buffer[i++]='\0'; if( !strcmp(buffer, "ping") ){ digitalWrite(13, state); state = !state; digitalWrite(SerialTxControl, RS485Transmit); Serial.print("pong"); delay(10); digitalWrite(SerialTxControl, RS485Receive); } } } }'; if( !strcmp(buffer, "ping") ){ digitalWrite(13, state); state = !state; digitalWrite(SerialTxControl, RS485Transmit); Serial.print("pong"); delay(10); digitalWrite(SerialTxControl, RS485Receive); } } } }
Код программы для второй платы Arduino
#define SerialTxControl 2 #define RS485Transmit HIGH #define RS485Receive LOW char buffer[100]; byte state = 0; void setup(void) { Serial.begin(115200); pinMode(13, OUTPUT); pinMode(SerialTxControl, OUTPUT); digitalWrite(SerialTxControl, RS485Receive); } void loop(void) { int i=0; if( Serial.available() ){ delay(5); while( Serial.available() ){ buffer[i++] = Serial.read(); } if(i>0){ buffer[i++]='#define SerialTxControl 2 #define RS485Transmit HIGH #define RS485Receive LOW char buffer[100]; byte state = 0; void setup(void) { Serial.begin(115200); pinMode(13, OUTPUT); pinMode(SerialTxControl, OUTPUT); digitalWrite(SerialTxControl, RS485Receive); } void loop(void) { int i=0; if( Serial.available() ){ delay(5); while( Serial.available() ){ buffer[i++] = Serial.read(); } if(i>0){ buffer[i++]=''; if( !strcmp(buffer, "ping") ){ digitalWrite(13, state); state = !state; digitalWrite(SerialTxControl, RS485Transmit); Serial.print("pong"); delay(10); digitalWrite(SerialTxControl, RS485Receive); } } } }#define SerialTxControl 2 #define RS485Transmit HIGH #define RS485Receive LOW char buffer[100]; byte state = 0; void setup(void) { Serial.begin(115200); pinMode(13, OUTPUT); pinMode(SerialTxControl, OUTPUT); digitalWrite(SerialTxControl, RS485Receive); } void loop(void) { int i=0; if( Serial.available() ){ delay(5); while( Serial.available() ){ buffer[i++] = Serial.read(); } if(i>0){ buffer[i++]='\0'; if( !strcmp(buffer, "ping") ){ digitalWrite(13, state); state = !state; digitalWrite(SerialTxControl, RS485Transmit); Serial.print("pong"); delay(10); digitalWrite(SerialTxControl, RS485Receive); } } } }'; if( !strcmp(buffer, "ping") ){ digitalWrite(13, state); state = !state; digitalWrite(SerialTxControl, RS485Transmit); Serial.print("pong"); delay(10); digitalWrite(SerialTxControl, RS485Receive); } } } }
Разновидности микросхем RS-485
Существуют различные микросхемы RS-485 — MAX485, ADM485, SP485, SN75176. Функциональные возможности которых идентичны, назначения выводов совершенно одинаковые.
Защита от помех
- Снижение скорости передачи данных повышает помехоустойчивость. Не устанавливайте скорость большую, чем требуется для нормального функционирования системы.
- Не прокладывайте сигнальный кабель вместе или вблизи силовых кабелей.
- В промышленных зонах рекомендуется применять экранированную витую пару с последующем заземлением экрана.
- Использование индуктивных фильтров для избавления системы от высокочастотных помех.
Заключение
Интерфейс RS-485 применяется в промышленных системах из-за устойчивости к помехам и возможностью передавать данные на большие расстояния.
Но этот интерфейс нашел применение в домашних системах Умного дома и проектах Arduino по тем же причинам.
RS-485 широко используется с протоколами ModBus и DMX512.
* ModBus — открытый коммуникационный протокол.
* DMX512 — протокол передачи данных между контроллерами и световым оборудованием.
Ссылки
Wikipedia: https://ru.wikipedia.org/wiki/RS-485
Datasheet MAX485: https://datasheets.maximintegrated.com/en/ds/MAX1487-MAX491.pdf