Подключение конвертера RS-485 в TTL к Arduino

kasper007
Offline
Зарегистрирован: 23.05.2016

Доброго всем дня,

возникла задача передавать небольшое количество данных на расстояние до 50-70 метров. Решил организовать это с помощью RS-485 интерфейса. Не мудурствую лукаво повторил схему указанную ниже:

http://adatum.ru/podklyuchenie-konvertera-rs-485-v-ttl-k-arduino.html

Все хорошо, но принимаемый байт не соответсвует отправленному.

К примеру (отправка по байтно в HEX):

отправил: 0x01 получил: 0x7F

отправил: 0x01 0x02 0x03 получил: 0x7F 0xBF 0x00

отправил: 0x01 0x02 0x03 0x04 получил: 0x7F 0xBF 0xF7 0x00

отправил: 0x01 0x02 0x03 0x04 0x05 получил: 0x7F 0xBF 0xF7 0xF5 0x00

Результаты повторяемы: что на куске кабеля 20 см, что на бухте в 30 метров. При отправке одной о той же посылки, получаю в ответ один и тот же результат. Т.е. помех и наводок нет. Переписал программу для отправки одного байта - тот же самый результат, те же самые занчения.

Использкю я правда другу андруину: Mega2560, в качестве порта передачи/приема использую serial1.

Подскажите, в чем может быть ошибка.

 

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Линии А и В не перекручены случайно....?

kasper007
Offline
Зарегистрирован: 23.05.2016

А к А подключено; В к B подключено, сами линии перекручены (использую типовую витую пару)

Araris
Offline
Зарегистрирован: 09.11.2012

Если результаты повторяемы, то возникают сомнения в программной части. Покажите-ка скетчи передатчика и приёмника.

kasper007
Offline
Зарегистрирован: 23.05.2016

и приемник и передатчик - это терминальная программа на ПК.

Ардуино работает в качестве эхо. Прежде чем связывать две ардуины я решил проверить на всякий случай.

// Объявляем переменные и константы:
const uint8_t     CONTROL_TX_RX = 10;  // указываем номер вывода arduino, к которому подключены выводы RE и DE
byte test;

void setup()
  {
  pinMode(CONTROL_TX_RX,   OUTPUT);  
  digitalWrite(CONTROL_TX_RX, LOW);    // устанавливаем  «0» - режим приёма данных
  Serial1.begin(9600);
  while (!Serial1) { }                      //  ожидаем открытия порта
  Serial1.println("Port_1 open");
  }

void loop(){
   if (Serial1.available()) {
      test = Serial1.read();
      delay(100);
      digitalWrite(CONTROL_TX_RX, HIGH);
      delay(100);
      Serial1.write(test);
      digitalWrite(CONTROL_TX_RX, LOW);
     }
}

 

P.S. Похоже китайский модуль RS-485 дохлый. Я убираю один из проводов (RX/TX) между ардуиной и модулем, а в ответ получаю те же значения. Вопрос пока снимается, буду заказывать новые конверторы.

Veoramid
Offline
Зарегистрирован: 20.07.2016

kasper007 пишет:

      digitalWrite(CONTROL_TX_RX, HIGH);
      delay(100);
      Serial1.write(test);
      digitalWrite(CONTROL_TX_RX, LOW);

 

Не совсем понятен сей текст.

Что бы не повторятся чиать тут: http://arduino.ru/forum/programmirovanie/modbus-rs485-gotovyi-shild#comm...

Что бы попробовать ЭХО1 байта попробовать поставить  после       Serial1.write(test); еще delay

И еще раз - по нормальному переключение на прием нужно делать после передачи последнего байта  по флагу из соотвествующего регистра.

kasper007
Offline
Зарегистрирован: 23.05.2016

Вопрос решился, действительно был дохлый китайский модуль RS485, поэтому даже отправка одного байта не осуществлялась. Заменил, сейчас все просто летает в обе стороны между UNO и Mega.

Veoramid пишет:

И еще раз - по нормальному переключение на прием нужно делать после передачи последнего байта  по флагу из соотвествующего регистра.

Не пошел по этому пути. Пакеты, которые передаются всегда одной длины, поэтому примерно посчитал на калькуляторе время отправки пакета, проверил все на практике и добавил delay() после передачи, но перед переключением из режима передачи в режим чтения, чтобы посылки уходили полностью.

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

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

kasper007
Offline
Зарегистрирован: 23.05.2016

Передача данных потребовалась в рамках проекта "подводный телеуправляемый аппарат". Проект больше для души, чем для коммерции.

http://arduino.ru/forum/proekty/podvodnyi-teleupravlyaemyi-apparat

Еще месяц передача шла только от пульта управления к роботу. Поэтому одна из ардуин всегда слушала, вторая всегда только говорила.

Но в процессе реализации обнаружились некоторые особенности (к примеру разные значения мощности двух одинаковых регуляторов). для решения потребовалось вводить возможность калибровки прямо с пульта управления. Затем захотелось иметь понимание о своем положении под водой (глубина) и параметрах движения (эти пакеты уже идут в обратную сторону, от робота к пульту управления) И вот тут появилась необходимость двунаправленной отправки пакетов. И тут как раз столкнулся именно с тем, что написал многоуважаемый DIYMan.

Первым делом ввел заголовок пакета, который указывает только на начало пакета и байт идентификации пакета (передача данных управления моторами, передача калибровочных данных, передача телеметрии). Ну и чтобы было понимание, что получаем именно то, что нужно, заканчивается пакет контрольной суммой. 

А чтобы разделить очередность передач и не связываться с какими-то серьезными протоколами я решил сделать следующее: приоритетным отправителем является пультр управления, он в нормальном режиме установлен в режим передачи. Но после передачи пакета он переключается в режим "слушать шину" на длительность в 2 длины пакета. Так же и подводная часть всегда в нормальном состоянии находится в режиме "слушать шину", но после приема пакета (и именно только в этот момент), если у нее есть что сказать, она переходит в режим передачи и отправляет данные к пульту управления.

Частота импульсов ESC регуляторов моторов 50 HZ, это 20 мсек. Скорость передачи данных 57600, длина посылки 20 байт. Т.е. время передачи одной посылки 3 мсек от пульта управления к роботу и потом 6 мсек слушает в ответ. По таймингу пролез, поэтому дальше рыть не стал.

 

Navigator
Navigator аватар
Offline
Зарегистрирован: 26.01.2016

Для управления подводным аппаратом передаете по RS485 только один байт? Или я не правильно вас понимаю.

kasper007
Offline
Зарегистрирован: 23.05.2016

Нет, в настоящее время передается три разных типа пакетов: 20 байт, 5 байт, 57 байт. Вопрос передачи по rs485 решился. Проблема была в usb-rs485 конвертере, пришел с Али дохлый.

Navigator
Navigator аватар
Offline
Зарегистрирован: 26.01.2016

Ранее пользовался этими модулями https://ru.aliexpress.com/item/FREE-SHIPPING-MAX485-module-RS485-module-TTL-turn-RS-485-module-MCU-development/32348768435.html?spm=2114.10010208.1000014.18.Df8zAV&scm=1007.13338.47322.0&pvid=5ddcc12a-3a8c-4f94-b535-3ecaf41acca0&tpp=1 , передавал данные с одной уно на другую уно. Скетчи не сохранились, какие использовал библиотеки точно не помню. Сейчас возникла снова необходимость передавать данные по RS485 c уно в нано. Попробовал как здесь https://www.youtube.com/watch?v=6pirdFDzWzA. Побайтно все передается. А как во второй части видео, три байта не получается. Сначала была ошибка при компиляции, исправил ошибку заменив файл ld.exe  ide 1.6.4 на аналогичный из более старой ide 1.0.6. Пока не получилось передавать несколько байт. Как вы решили эту задачу? 

kasper007
Offline
Зарегистрирован: 23.05.2016

железо использую абсолютно такое же. Никаких библиотек, использую физические порты

Вот пример передачи. 13 байт. Первый 0xAA - идентификатор пакета, последний CRC, 11 байт внути информационных

#define PIN_TX_RX 8  // указываем номер вывода arduino, к которому подключены выводы RE и DE
byte num[] = {0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00};
unsigned long previous, current;

void setup() {
Serial1.begin(57600);
pinMode(PIN_TX_RX,   OUTPUT);
digitalWrite(PIN_TX_RX, HIGH);  
delay(1000); 
previous = millis();
}

void loop() {
byte CRC = 0;
current = millis(); 

// --------------
// какое-то действие, которое инициализирует передачу
flag = true;
//---------------

if ((current-previous)>30) { //отправка происходит раз в 30 мс, при условии, что есть отправлять
   if (flag) {
   for (int i=1; i<12; i++){CRC=CRC^num[i];}
   num[12]=CRC;
   Serial1.write(num,13);
   flag = false;
   previous = current;
   }
}
}

А вот прием этой же посылки на втором устройстве:

#define PIN_TX_RX 10 
byte inBIT[11];

void setup() {
Serial.begin(57600);
pinMode(PIN_TX_RX,   OUTPUT);
digitalWrite(PIN_TX_RX, LOW);  
delay(1000); 
}

void loop() {
  if (Serial.available() > 0) {
  delay(3);
  byte bl_type = Serial.read();
  if (bl_type == 0xAA) {
     byte CRC = 0;
     for (int temp = 0; temp < 11; temp++) {
     inBIT[temp] = Serial.read();
     delayMicroseconds(500);
     CRC = CRC ^ inBIT[temp];
     }
     inBIT[11] = Serial.read();
     if (inBIT[11] == CRC) {
     // ------------------
     // посылка пришла полностью, что-то делаем с полученными данными
     //--------------------
     }
     }
  }
}

Если не ставлю delay(3), то поступающая посылка не успевает полностью заскочить в буфер порта

Navigator
Navigator аватар
Offline
Зарегистрирован: 26.01.2016

Спасибо.

Пример из видео тоже заработал со старой 1.0.6. 

 

sslobodyan
Offline
Зарегистрирован: 28.09.2016

Я тоже раньше страдал фигней, придумывая свои протоколы для каждой новой железяки. А потом один раз написал библиотечку по MODBUS и получил кучу профитов. Не зря этот протокол есть промышленным стандартом по управлению удаленным оборудованием. Он и достаточно прост в реализации и расширяем по ходу развития проекта. Особенно мне понравилось, когда я связал по этому протоколу железку с LabView и нарисовал в этой проге пульт управления и индикации. Там и графики изменения параметров, и различный анализ, и автоматические команды понаделывал. Так что мой совет - уходите от велосипедов, пользуйтесь готовыми проверенными разработками.

Veoramid
Offline
Зарегистрирован: 20.07.2016

Кстати тут получился готовый слейв:

http://arduino.ru/forum/programmirovanie/modbus-rs485-gotovyi-shild#comm...