RS485 Потеря информации при переключении прием-передача

FoxJone
Offline
Зарегистрирован: 19.04.2019

Добрый день, коллеги.

Имею вот такую задачу: есть железка, которая шлет информацию по RS485 (115200, 8 битб 1 стоп). Информацию эту она шлет не кому попало, а только пополучении ответа на свой запрос. То есть железка делает запрос, корреспондент должен правильно ответить, и только после этого железка даст инфу.

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

На мегу залил вот такой скетч:

int i = 0;
int j = 0;
int incom = 0;
int rec[255];
int Answer[21] = {254, 3, 5, 5, 134, 12, 0, 33, 202, 247, 102, 64, 96, 72, 1, 28, 0, 120, 97, 232, 88};
long del = 0;

void setup() {
  Serial.begin(115200);
  Serial1.begin(115200);
  pinMode(DIR, OUTPUT); //пин переключения прием/передача на 485
  digitalWrite(DIR, LOW); // включаем прием
  i = 0;
}

void loop() {
  if (Serial1.available() > 0) {
    incom = Serial1.read();  //читаем байт
    if (incom == 254) {  //начало новой посылки всегда 254
      Serial.print("   i="); Serial.println(i, DEC);
      i = 0;             //если начало новой посылки, то выводит количество байт в предыдущей посылке, переводит строку в мониторе и обнуляет счетчик байт в посылке
    }
    if (incom < 16) Serial.print("0"); // добавляет в мониторе ноль к мелким байтам.. ну привык я хексы видеть двузначными...
    Serial.print(incom, HEX); Serial.print(" "); //выводит в монитор полученный байт. Это все отладочный модуль, потом я его уберу.

    rec[i] = incom; //заносит полученный байт в массив

    if (i == 8) {   //если получено 9 байт с начала посылки, то обрабатывает информацию (9 байт = команда от железяки)

      if (rec[1] == 3 &&  rec[2] == 5 && rec[3] == 5 && rec[4] == 134 && rec[5] == 0 && rec[6] == 0 && rec[7] == 0 && rec[8] == 0)  {   //если первые 9 байт совпали с командой "запрос связи", мега отправляет ответ
        digitalWrite(DIR, HIGH); // включаем передачу
        for ( j = 0; j <= 20; j++) {
          Serial1.write(Answer[j]);  //ответ из 21 байта. Железка его точно принимает и по его получении шлет инфу
          del = millis();
          while ((millis() - del) < 2) { } // задержка между отправкой байтов. Без нее железка не читает, видимо слишком быстро шлются.
        }
        digitalWrite(DIR, LOW); // включаем прием
        Serial.print("   i="); Serial.println(i, DEC);        
        Serial.println("sent answer");
      }
      if (rec[1] == 3 &&  rec[2] == 9 && rec[3] == 45 && rec[4] == 134 && rec[5] == 28 && rec[6] == 0 && rec[7] == 80 && rec[8] == 66) Serial.println("test command");  //тестовая команда, которая ни разу не сработала(
    }
    i++; 
  }
}

Что имею в итоге: в сканере ясно видно, что железка шлет запрос, мега отвечает, железка ее понимает и шлет команду с инфой (это инфа прямо из линии 485):

FE 03 05 05 86 00 00 00 00   ЗАПРОС
FE 03 05 05 86 0C 00 21 CA F7 66 40 60 48 01 1C 00 78 61 E8 58   ОТВЕТ МЕГИ
FE 03 09 2D 86 21 00 50 42 FF 00 01 FC 01 FF 42 00 FD 11 00 01 FB 00 FC 00 03 03 03 03 03 FF 00 04 00 03 00 20 43 43 FA C3 08  КОМАНДА
 
В то же самое время в мониторе порта смотрим что получает мега: 
 
FE 03 05 05 86 00 00 00 00    i=8  ЗАПРОС
sent answer ОТВЕТ МЕГИ
21 00 50 42 FF 00 01 FC 01 FF 42 00 FD 11 00 01 FB 00 FC 00 03 03 03 03 03 FF 00 04 00 03 00 20 43 43 FA C3 08 КОМАНДА
 
Как видим, потеряно 5 байт (отмечены жирным в сканере). Железка не может слать эту посылку, пока не получит ответ - проверено экспериментально на 100%. То есть в момент между отправкой ответа мегой и получением мегой информации куда то пропадают байты.
Мое предположение - очень медленно переключается на прием мах485 и в процессе переключения теряет 5 байт. Что очень странно, потому что переключаться он должен со скоростью, намного превышающей скорость передачи по 485.
 
Ваше мнение, коллеги. Может ли такое быть и как с этим бороться?

 

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

Так у вас в 35 строке задержка стоит. Она не только между посылаемыми байтами срабатывает, но и перед переключением на прием. Вот и терчются первые байты. 

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Задержка нужна, что бы убедиться, что все данные из буферов переданы в линию. Слейв перед отправкой должен иметь некоторую задержку, во вторых мастер должен убедится что все данные ушли и сразу начать слушатт линию. Убедиться можно проверив количество байт в буфере отправки.

 

FoxJone
Offline
Зарегистрирован: 19.04.2019

brokly пишет:

Задержка нужна, что бы убедиться, что все данные из буферов переданы в линию. Слейв перед отправкой должен иметь некоторую задержку, во вторых мастер должен убедится что все данные ушли и сразу начать слушатт линию. Убедиться можно проверив количество байт в буфере отправки.

Да, все верно. Проблему решил, уменьшив задержку до 75 микросекунд.