Не работает связь по rs485
- Войдите на сайт для отправки комментариев
Добрый день, участники форума!
Помогите, пожалуйста разобраться с передачей данных по rs485.
Я недавно создавал тему, в которой рассказывал, что сооружаю проект автоматических штор. С помощью форумчан привел в более-менее приличный вид код, который управляет реле.
Следующим шагом хочу добавить возможность связи по rs485. Для первых шагов хочу подключить просто к компьютеру, послать простое сообщение и посмотреть, как это работает. Использую самые распространенные и дешевые конвертер TTL-RS485 и переходник с USB на RS485. Не уверен надо ли изображение этих модулей (маркировки на них нет).
Ардуино - китайский клон Про микро, который определяется как Леонардо. R0 модуля подключен на RX ардуины (0 пин), DI на TX ардуины (1 пин), DE и RE соединены. В коде, соответственно, использую "хардваррный" сериал порт. Связь rs485 по двум КСПВ проводам длиной 15 см (отлаживаю просто на столе).
На компьютере для мониторинга порта использую программу Putty. В ней вроде минимум настроек: номер порта и скорость.
Суть кода в следующем, при нажатии кнопки, включаются реле и отправляется в сериал два байта. Вроде просто. Проблема заключается в том, что в мониторе порта (Putty) ничего не появляется.
То ли отправляю неправильно, то ли принимаю неправильно. То ли вообще все делаю неправильно. Из подозрительного: диод TX на ардуине не мигает, хотя, по идее, должен мигать при отправке сообщений.
Собственно простыня кода приведена ниже. Код отправки сообщений, с которым не могу справиться, в строках 80-84 и 109-113.
Буду благодарен за помощь и пинки в нужном направлении.
/* Скетч для управления шторами ============================ При нажатии на кнопку, шторы отрываются/закрываются. Если во время открытия/закрытия нажать на любую кнопку шторы останавливаются. Для изменения направления движения используется электромагнитное реле. Для подачи напряжения на дигатель используется твердотельное реле. Через модуль rs484 осуществляется обратная связь с Распберри. */ // Определяем пины для подключенных кнопок: #define BUTTON_PIN_1 2 #define BUTTON_PIN_2 3 // Определяем пин для переключения модуля в режим передачи: #define ENABLE_RS485_PIN 6 // Определяем пины для переключения реле на открытие/закрытие: #define PIN_OPEN_CLOSE 14 // Определяем пины для подачи напряжения на дигатель: #define PIN_START_STOP 15 // контакт 6 будет переключать режим приёмник/передатчик #define SerialTxControl 6 #define RS485Transmit HIGH #define RS485Receive LOW // Тут вписываем переменные – это меняющиеся значения: int button1State = 0; // текущее состояние первой кнопки int lastButton1State = 0; // предыдущее состояние первой кнопки int button2State = 0; // текущее состояние второй кнопки int lastButton2State = 0; // предыдущее состояние второй кнопки // Флаг движения штор int action_flag = 0; // Массивы для приема и передачи по rs485. 1 - ID данного модуля byte bufOpen[2] = {1, 1}; byte bufClose[2] = {1, 0}; byte recivebuf[2]; // Переменная для хранения точки отсчета таймера unsigned long timing; void setup() { // инициализируем контакт для кнопки как входной контакт: pinMode( BUTTON_PIN_1, INPUT_PULLUP ); pinMode( BUTTON_PIN_2, INPUT_PULLUP ); // инициализируем контакты для управления реле как выходные контакты: pinMode( PIN_OPEN_CLOSE, OUTPUT ); digitalWrite( PIN_OPEN_CLOSE, LOW ); pinMode( PIN_START_STOP, OUTPUT ); digitalWrite( PIN_START_STOP, LOW ); Serial.begin(9600); // Запуск последовательного соединения на скорости 9600: pinMode( ENABLE_RS485_PIN, OUTPUT ); // Устанавливаем состояние управляющего пина digitalWrite( ENABLE_RS485_PIN, LOW ); // в низкое значение для приема } void loop() { // считываем данные с входного «кнопочного» контакта: button1State = digitalRead( BUTTON_PIN_1 ); button2State = digitalRead( BUTTON_PIN_2 ); // сравниваем текущее состояние (button1State) с предыдущим: if ( button1State != lastButton1State ) { if ( button1State == LOW ) { // Если нажата кнопка "открыть" и движения нет if ( action_flag == 0 ) { // Переключаем реле на открытие digitalWrite( PIN_OPEN_CLOSE, HIGH ); // Подаем напряжение delay ( 10 ); digitalWrite( PIN_START_STOP, HIGH ); timing = millis(); action_flag = 1; // Отправить сообщение по rs485 digitalWrite( ENABLE_RS485_PIN, HIGH ); Serial.write( bufOpen, 2 ); Serial.flush(); digitalWrite( ENABLE_RS485_PIN, LOW ); } // Если нажата кнопка "открыть" и движение есть else { //Остановить движение digitalWrite( PIN_OPEN_CLOSE, LOW ); digitalWrite( PIN_START_STOP, LOW ); action_flag = 0; } } delay ( 300 ); } // сравниваем текущее состояние (button2State) с предыдущим: if ( button2State != lastButton2State ) { if (button2State == LOW) { // Если нажата кнопка "закрыть" и движения нет if ( action_flag == 0 ) { // Переключаем реле на закрытие digitalWrite( PIN_OPEN_CLOSE, LOW ); delay ( 10 ); // Подаем напряжение digitalWrite( PIN_START_STOP, HIGH ); timing = millis(); action_flag = 1; // Отправить сообщение по rs485 digitalWrite( ENABLE_RS485_PIN, HIGH ); Serial.write( bufClose, 2 ); Serial.flush(); digitalWrite( ENABLE_RS485_PIN, LOW ); } // Если нажата кнопка "закрыть" и движение есть else { //Остановить движение digitalWrite( PIN_OPEN_CLOSE, LOW ); digitalWrite( PIN_START_STOP, LOW ); action_flag = 0; } } delay (300); } // для прогона через следующий цикл // делаем текущее состояние предыдущим lastButton1State = button1State; lastButton2State = button2State; // Если флаг движения установлен, отсчитываем время до отключения реле if ( action_flag == 1 ) { if ( millis() - timing > 10000 ) { // Вместо 10000 подставьте нужное вам значение паузы digitalWrite( PIN_START_STOP, LOW ); delay (10); digitalWrite( PIN_OPEN_CLOSE, LOW ); action_flag = 0; } } // Отслеживаем сообщения по rs485 if (Serial.available() >= 2) { // если есть доступные данные // считываем 2 байта recivebuf[2] = Serial.read(); if ( recivebuf[0] == 1 ) { // если сообщение адресовано шторам в спальне (1) if ( recivebuf[1] == 1 ) { // и если сообщение содержит команду "открыть" // Переключаем реле на открытие digitalWrite( PIN_OPEN_CLOSE, HIGH ); // Подаем напряжение delay ( 10 ); digitalWrite( PIN_START_STOP, HIGH ); timing = millis(); action_flag = 1; } else if ( recivebuf[1] == 0 ) { // и если сообщение содержит команду "закрыть" // Переключаем реле на закрытие digitalWrite( PIN_OPEN_CLOSE, LOW ); delay ( 10 ); // Подаем напряжение digitalWrite( PIN_START_STOP, HIGH ); timing = millis(); action_flag = 1; } } } }
у Leonardo, Serial относится к последовательному соединению USB (например отладка в терминал и загрузка скетчей). Последовательное соединение через выводы 0 и 1 осуществляется через Serial1.
Что ж вы такую программу накрутили? Вы ж 485 отлаживаете. Попробуйте по шагам. Сначала коротенькую программку просто отправка символа из ардуины к putty. Только честно. Переключение линии на передачу, посылка строки символов, отключение передачи, пауза. Если получите на ПК посылку, можно переходить к отправке символов из ардуины по получению символа от ПК. Когда обмен будет отлажен, можно переходить к управлению ногами.
Следующим шагом хочу добавить возможность связи по rs485.
Ну и хоти!
А через что? Где схема?
Может я хер хочу 30см,но комплекция не позволяет...
нахрена тебе RS485? Поставь две JDY-40 и ходи по дому, в проводах не путаясь.
Может я хер хочу 30см,но комплекция не позволяет...
Ну, дык - http://www.med-rf.ru/directions/urology_andrology_microsurgery/andrology/1/
ЕвгенийП, а электронике можно также научиться?
Тупо поменять в коде "Serial" на "Serial1" ничего не дало. Придется, видимо, разбираться по шагам.
Вот простенький код. Если в этом коде использовать Serial, то в монитор порта, встроенного в IDE, передаются данные. Все работает. Если заменить "Serial" на "Serial1", то ничего не происходит вообще.
Еще раз про подключение.
конвертер TTL-RS485 - https://aliexpress.ru/item/32348018283.html
Переходник с USB на RS485 - https://aliexpress.ru/item/32428596578.html
R0 модуля подключен на RX ардуины (0 пин), DI на TX ардуины (1 пин), DE и RE соединены и подключены к 7 пину ардуино. Выход А конвертера соединяю с А переходника, В с В.
Беспроводную связь соображалка не потянет. С двумя проводами-то разобраться не могу.
А можно полную схему? Со всеми соединениями. Даже теми, через которые заливается скетч. Если что то прибегает в монитор ИДЕ то надо понять путь, как туда попадают символы.
Беспроводную связь соображалка не потянет. С двумя проводами-то разобраться не могу.
JDY-40 тем и хорош, что прикидывается и работает так же просто как обычный Сериал, тока без проводов. Ничего в программе переделывать не надо, создать SoftSerial, на его выводы подключить JDY и слать в софтсериал данные. А на приемнике так же забирать их из софтсериала. 2021 на носу, эволюция же. Пришло время ужасных чудес.
Вот"схема". Реле не удались. Все-таки хотелось бы именно проводную связь. Пробовал когда-то nrf24l01, esp... в общем осадочек остался.
С Serial все действия происходят через тот же шнурок, по которому заливается скетч. Serial1 уже хотелось бы отсылать через конвертер TTL RS485
Из описания платы : . Обратите внимание, что на Micro класс Serial относится к (CDC) соединению; для последовательного TTL соединения на выводах 0 и 1 используйте класс Serial1. В компе надо смотреть порт, который поднимается после коннекта 485 адаптера.
Ага, выше уже MaksVV мне на это указал. В комментарии №6 я попытался написать простенький код, который должен был работать с Serial1. Но он не работает. Видимо, что-то не то я все равно делаю.
Если есть вторая ардуина, то можно ею послушать Микру - шлет она что-нить в Serial1 или нет.
Если есть вторая ардуина, то можно ею послушать Микру - шлет она что-нить в Serial1 или нет.
Кстати, можно попробовать. Могу в качестве приемника даже взять Нано, чтобы не заморачиваться с разными сериалами. Имеется ввиду, что надо убрать все конвертеры и просто соединить две ардуины через rx и tx пины? Код из комментария №6 пойдет в качестве передатчика?
На Нану пример TwoSerial (или как-то так) из библиотеки SoftwareSerial.
Передатчик подойдёт.
Попробовал принимать сигнал на другую ардуину. Результаты даже не знаю как интерпретировать. В качестве передатчика ардуино про микро. В качестве приемника ардуино нано. Соединения:
ардуино про микро ардуино нано
0 пин (TX) <-> 8 пин (софтварный RX)
1 пин (RX) <-> 9 пин (софтварный TX)
Код передатчика (про микро)
Код приемника (нано)
Передатчик питается от зарядки. Приемник подключен к USB порту компьютера. В мониторе последовательного порта выдает следующее:
Data from port one:
Data from port one:
⸮⸮
Data from port one:
Data from port one:
То есть в порт пишется строка "Data from port one:", как собственно и следует из кода. И периодически проскакивают непечатаемые символы, которые, по-видимому, получаются от передатчика по Serial1. Если отсоединить передатчик, то этих символов в мониторе порта не появляется.
18ю строку я бы выкинул, а inByte печатал в HEX (см. описание Serial.print) и далее пробел для понятности.
Сделал. В мониторе порта выводится следующее:
Data from port one:
FFFFFFFD FFFFFFFF
Data from port one:
FFFFFFFF FFFFFFFF
Data from port one:
Data from port one:
FFFFFFFF FFFFFFFB
Data from port one:
FFFFFFFA FFFFFFFF
Data from port one:
Data from port one:
FFFFFFDF FFFFFFFF
Data from port one:
Все-таки это мусор, а не данные с передатчика.
Всех с наступившим НГ!
И предлагаю в эксперименте с двумя ардуинами убрать адаптеры rs485 и соединить uart ы напрямую
Вот код передатчика, с которым все заработало.
Причем работает как с ардуино в качестве приемника, так и с адаптером, подключенным к ПК. На ПК в мониторе СОМ-порта вижу все данные. Хотя принципиальных отличий от предыдущего своего кода я не вижу. Какие-то новогодние чудеса. Мне не очень понятно как происходит передача, потому что я не подаю сигнал на пины DI и RO конвертера. Или они по умолчанию настроены на передачу?
С отправкой в целом разобрался. Еще немного поковыряюсь и буду разбираться с приемом. Буду продолжать в этой же теме.
Код передатчика (про микро)
Уж сколько раз твердили - на простых чипах 485 прежде чем выключать передачу ( digitalWrite(7, LOW);), дождись, пока сигнал уйдет в линию. На умных чипах этого делать не надо, а на тупых китайских надо. То есть после отправки посылки вы должны подождать, пока чип их отправит и УЖЕ ПОСЛЕ этого выключать передачу. У вас скорость передачи вами же задана и чип не может передавать быстрее, чем вы ему указали. А атмега работает на порядок быстрее и и обрывает передачу. Для скорости 9600 надо ставить задержку 1200-1250 миллисекунд на один посланный байт.
Собственно, весь полученный вами мусор - это обрезанные байты, которые начали передавать и рубанули на половине передачи...
дождись, пока сигнал уйдет в линию. На умных чипах этого делать не надо, а на тупых китайских надо.
.......
Для скорости 9600 надо ставить задержку 1200-1250 миллисекунд на один посланный байт.
А Serial.flush() для этого использовать не более правильно?
дождись, пока сигнал уйдет в линию. На умных чипах этого делать не надо, а на тупых китайских надо.
.......
Для скорости 9600 надо ставить задержку 1200-1250 миллисекунд на один посланный байт.
А Serial.flush() для этого использовать не более правильно?
Может и лучше, но совсем не очевидно... Этот flush очень странно работает: делает не всегда то, что в описании написано. Не говоря уже о том, что меняет свой функционал на прямо противоположный в разных версиях Ардуины ИДЕ. Так что, во избежание будущих багов и глюков я им не пользуюсь. Да и вручную поставить задержку на переключение прием/передача никаких проблем нету. Я вообще стараюсь не пользовать сторонние библиотеки там, где можно самому написать пару строчек.
Ну и правило номер два: по сериалу не шлют символы, строки или там флоаты... Там шлют только и исключительно байты. Поэтому рекомендую использовать только write и read, без всяких print или (упаси боже) println. Потому что иногда они лишнее цепляют к отправляемой посылке (конец строки, перевод каретки и тд) - и потом с этим лишним на этот форум люди приходят)
Ну и правило номер два: по сериалу не шлют символы, строки или там флоаты... Там шлют только и исключительно байты. Поэтому рекомендую использовать только write и read, без всяких print или (упаси боже) println. Потому что иногда они лишнее цепляют к отправляемой посылке (конец строки, перевод каретки и тд) - и потом с этим лишним на этот форум люди приходят)
А вот тут не понял. Я считал, что по сериалу вся информация уходит в виде двоичного кода - ноликов и единичек. А вот как в коде это прописано, это исключительно для удобства восприятия на глаз.
И, кстати, задержка в 1,2 секунды на байт это не многовато?
Ну это правильно, нули и единички. Для удобства объединяем их в байты. Но! Когда вы шлете командой write(5) один байт, то на линию уходит ровно 8 бит (байт=5) и ничего лишнего (ну кроме стоповых битов, которые в любом случае будут). А если вы шлете в сериал println(5), то на линию уйдет байт=53 (символ 5 в ascii) +байт окончания строки +байт перевода каретки. Итого 3 байта. Если это то, что вы хотели, то все нормально. Но очень часто сюда приходят люди с претензией "я послал 5, а оно мне шлет какой то мусор".
Не 1,2 секунды, а 0,0012 секунд. Моя вина - хотел написать микросекунд.
Спасибо за разъяснения. Стало понятнее. В принципе, такой код даже более логичен.
Я чуть забегу вперед. Я планирую делать двухстороннюю связь с распберри и уже сейчас столкнулся с тем, что данные проходят не в 100% случаев. Наводки, помехи, не совсем удачные временные провода... причин может быть много. Но совершенно понятно, что для более-менее надежной связи необходимо подтверждение получения данных. Вы можете дать совет как это лучше реализовать? Я представляю себе так:
Отправили данные
Взвели флаг отправки данных
Повтор 5 раз
Ждем подтверждения две секунды
Если подтверждение получено, то сбрасываем флаг отправки данных и выходим из цикла
Если подтверждение не получено, то снова отправляем данные
Если 5 раз отправка данных неудачна, то сбрасываем флаг отправки данных
Форум (движок, а не сообщество) тут полный отстой - свои сообщения искать практически невозможно... Где то я уже писал развернуто про то как надо работать в 485, попробую найти... Потому что повторно писать лень)
rs485 изначально спроектирован как стандарт связи в дико агрессивной индустриальной среде на расстояния больше километра, и если у тебя в обычной комнате данные не доходят, то это значит, что ты делаешь что-то очень-очень-очень неправильно.
rs485 изначально спроектирован как стандарт связи в дико агрессивной индустриальной среде на расстояния больше километра, и если у тебя в обычной комнате данные не доходят, то это значит, что ты делаешь что-то очень-очень-очень неправильно.
Ага-ага... Вот только изначально его проектировали 50+ лет назад и для скоростей порядка 200-500 кбит/с. И даже при этом во всех протоколах присутствует проверка на ошибки. На скорости 9600 и выше ошибки будут обязательно! Что не отменяет того, что стандарт удобный и пользоваться им можно - к примеру, миллионы автобусов, трамваев и троллейбусов в стране возят на себе информатор (мастер) и по 3-4 табло (слейвы), связанных по 485 да еще и на скорости 115200 (я участвовал в разработке, поэтому гарантирую). А проводка там даже не витая пара, по большей части просто 2 провода кидают где могут.
Но совершенно понятно, что для более-менее надежной связи необходимо подтверждение получения данных. Вы можете дать совет как это лучше реализовать?
Не нашел свой текст, поэтому в двух словах: у вас 2 варианта - взять готовый протокол (например ModBus) или написать свой. Если честно, то я настолько ленивый, что когда у меня встал вопрос работать с устройствами под ModBus, то мне оказалось проще написать свою обработку, чем искать и курить чужие библиотеки, а с вашими шторами модбас явное излишество.
А как реализовать простой и надежный обмен я вот тут коротко расписывал https://arduino.ru/forum/apparatnye-voprosy/konverter-max485-podklyuchenie#comment-559270
FoxJone, напишы мне, согласен работать за еду на любых твоих условиях. Даж не пить согласен. Совсем у мня жопа. :(
Завтра удалю это.
для скоростей порядка 200-500 кбит/с.
На скорости 9600 и выше ошибки будут обязательно!
Вообще-то 100к максимум по стандарту. И даже это в 10 раз больше 9600. Фуфло какое-то несешь.
Дед, удаляй прям щас! Завтра отпишусь, сейчас ужо пить начал...
для скоростей порядка 200-500 кбит/с.
На скорости 9600 и выше ошибки будут обязательно!
Вообще-то 100к максимум по стандарту. И даже это в 10 раз больше 9600. Фуфло какое-то несешь.
Максимум - это пропускная способность. Ошибки могут (а раз могут, то и будут) быть на любых скоростях и на любых каналах связи, даже если это веревочный телеграф, то пробегающая крыса может за веревку хвостом дернуть. Ошибки передачи - это нормально. Ненормально если их больше допустимого уровня и ненормально, если их никто не отсеивает.