Не могу разобраться с протоколом передачи данных

Vinch
Offline
Зарегистрирован: 01.08.2013

У меня есть прибор и к нему подключаются различные датчики по RS485, для программирования адреса датчика и других параметров есть специальная программа, я хотел бы сделать небольшой прибор, чтобы не таскать с собой ноутбук постоянно. Протокол похож на modbus rtu, но у меня не сходится контрольная сумма. И для отправки команды неизвестному датчику используется адрес FF, а не 00.

Vinch
Offline
Зарегистрирован: 01.08.2013

Вот примеры посылок и принятых пакетов

Jeka_M
Jeka_M аватар
Offline
Зарегистрирован: 06.07.2014
Vinch
Offline
Зарегистрирован: 01.08.2013

Вот пример посылки FF 03 00 00 00 14 EA

FF - это адрес датчика

03 - чтение значений из нескольких регистров хранения

00 00 - start address

00 14 - num of coils

EA - CRC, как я понял

Щас читал про Modbus, и похоже это не rtu, а

Modbus ASCII — для обмена используются только ASCII символы. Для проверки целостности используется однобайтовая контрольная сумма. Начало и конец сообщения помечаются специальными символами (начало сообщения ":", конец сообщения CR/LF).

контрольную сумму пробовал многими калькуляторами подобрать и в итоге нашел CheckSum8 2s Complement

Осталось все это в ардуино как-то реализовать..

Vinch
Offline
Зарегистрирован: 01.08.2013

Вот так сделал отправку:

int val = 0;
byte checksum;


void setup() {
  Serial.begin(57600); 
  readdata(0xFF, 0x0, 0x14);
}

void loop() {
//  if (Serial.available() > 0) {
//    val = Serial.read();
//    Serial.print("I received: ");
//    Serial.print(val);
//    Serial.println();
//  }
}

void readdata(byte slave, word address, word flags) {
  Serial.print(":");
  if(slave < 0x10) Serial.print("0"); 
  Serial.print(slave, HEX);
  Serial.print("03");
  if(address < 0x10) Serial.print("000"); 
  else if(address < 0x100) Serial.print("00");
  else if(address < 0x1000) Serial.print("0");
  Serial.print(address, HEX);
  if(flags < 0x10) Serial.print("000");
  else if(flags < 0x100) Serial.print("00");
  else if(flags < 0x1000) Serial.print("0");
  Serial.print(flags, HEX);
  checksum = 0x100 - ((slave + address + flags + 0x03)%0x100);
  if(checksum < 0x10) Serial.print("0");
  Serial.println(checksum, HEX);
}

проверил, в Symply Modbus Slave работает.

Теперь самое сложное для меня это обработать ответ от датчика в ардуино, подскажите каким образом можно это сделать?

nik182
Offline
Зарегистрирован: 04.05.2015

А как же google? Вот первая же ссылка https://github.com/pepsilla/Arduino/tree/master/MODBUS/ASCII.

Vinch
Offline
Зарегистрирован: 01.08.2013

nik182 пишет:

А как же google? Вот первая же ссылка https://github.com/pepsilla/Arduino/tree/master/MODBUS/ASCII.

Там пример для двух ардуин, я пробовал отправлять с ее помощью, и там отправляется CRC 16 bit, а в моем случае должно быть 8 бит

Да и не совсем понятная мне библиотека

nik182
Offline
Зарегистрирован: 04.05.2015

Для просветления читаем http://modbus.org/docs/PI_MBUS_300.pdf . (Особенно стр. 8 рис.3, 110,111)

В вашем случае полный фрейм  :FF 03 00 00 00 14 EA CR LF  - в нем EA это не CRC , а LRC - appendix C мануала модбус. Это два HEX charters от 8 битной LRC. Пример расчета LRC дан на си.

Совершенно понятная библиотека. Использовать просто как грабли. Заряжаешь пакет и отправляешь. Судя по тексту библиотеки в отправку вствляется именно LRC.  https://github.com/pepsilla/Arduino/blob/master/MODBUS/ASCII/libraries/AsciiModbusMaster/AsciiModbusMaster.cpp (строки 614-628).

А вообще (строка 590) void sendPacket(unsigned char bufferSize) можно взять себе и после маленькой замены способа отправки использовать для отправки запроса к слейву. Но тогда логику приёма ответа придётся писать самому.