Как отформатировать массив байтов для проверки CRC 16 бит для кадра Modbus?

В настоящее время я пытаюсь использовать Arduino UNO R3 в качестве мастера в последовательном протоколе связи Modbus (а не TCP / IP). Я безрезультатно пытался использовать устаревшие библиотеки, в основном из-за устаревших зависимостей. В любом случае я решил начать с нуля, и моя текущая цель - записать значение регистра 301 (начальный адрес 300) в подчиненный идентификатор. «5». Перед подключением к моему ведомому устройству я хочу убедиться, что могу восстановить CRC для кадра в зависимости от того, записываю ли я в регистр 0, 1 или 2. Для записи 1 у меня есть кадр «05 06 01 2D 00 01 D8 7B», и из моих исследований я могу сказать, что «D8 7B» - это 16-битный CRC для данных. Однако проблема в том, что я не могу воспроизвести вывод CRC на моем Arduino. Я считаю, что это связано с тем, как я подготовил и отформатировал свой байтовый массив, но я не уверен. Я плохо понимаю алгоритмы CRC, поэтому я использую библиотеку, любая помощь будет принята с благодарностью.

Следующий код представляет собой небольшую вариацию примера скетча, предоставленного библиотекой Crc16 компании vinmenn.

#include <Crc16.h>
//Crc 16 library (XModem)
Crc16 crc; 

void setup()
{
    Serial.begin(38400); 
    Serial.println("CRC-16 bit test program");
    Serial.println("=======================");

}

void loop()
{
  /*
    Examples of crc-16 configurations
    Kermit: width=16 poly=0x1021 init=0x0000 refin=true  refout=true  xorout=0x0000 check=0x2189
    Modbus: width=16 poly=0x8005 init=0xffff refin=true  refout=true  xorout=0x0000 check=0x4b37
    XModem: width=16 poly=0x1021 init=0x0000 refin=false refout=false xorout=0x0000 check=0x31c3
    CCITT-False:width=16 poly=0x1021 init=0xffff refin=false refout=false xorout=0x0000 check=0x29b1
    see http://www.lammertbies.nl/comm/info/crc-calculation.html
  */
  //calculate crc incrementally
  byte data[] = {0x05, 0x06, 0x01, 0x2D, 0x00, 0x01};

  Serial.println("Calculating crc incrementally");

  crc.clearCrc();
  for(byte i=0;i<6;i++)
  {
     Serial.print("byte ");
     Serial.print(i);
     Serial.print(" = ");
     Serial.println(data[i]);
     crc.updateCrc(data[i]);
  }
  unsigned short value = crc.getCrc();
  Serial.print("crc = 0x");
  Serial.println(value, HEX);

  Serial.println("Calculating crc in a single call");

  //Modbus
  value = crc.Modbus(data,0,7);
  Serial.print("Modbus crc = 0x");    
  Serial.println(value, HEX);

  while(true);
}

Ниже приведен вывод последовательной консоли при выполнении вышеупомянутого кода.

CRC-16 bit test program
=======================
Calculating crc incrementally
byte 0 = 5
byte 1 = 6
byte 2 = 1
byte 3 = 45
byte 4 = 0
byte 5 = 1
crc = 0x2C86
Calculating crc in a single call
Modbus crc = 0x5A7B

Я использую программу под названием Modbus Poll, чтобы организовать мои байты в фреймы. Ниже приведен снимок экрана с выводом программы.

Опрос Modbus

Опять же, любая помощь будет оценена по достоинству. Заранее спасибо!

edit: Я не упомянул, как в предоставленных материалах подробно описывается моя проблема. Согласно программе опроса Modbus CRC - «D8 7B», однако моя последовательная консоль сообщает «0x5A7B».

edit: я исправил код для отражения CRC более шести байтов (0, 5) и обновил вывод последовательной консоли.

Решение: Устранена проблема, изменив value = crc.Modbus(data,0,7); на value = crc.Modbus(data,0,6);


person TheMountainFurnaceGabriel    schedule 25.05.2020    source источник
comment
Почему вы вычисляете CRC для 7 байтов, если у вас всего 6?   -  person gre_gor    schedule 25.05.2020
comment
@gre_gor Спасибо, что заметили это, я обновил код и последовательный вывод, чтобы отразить изменения.   -  person TheMountainFurnaceGabriel    schedule 25.05.2020


Ответы (1)


Что касается репликации Modbus CRC16 побайтным методом, согласно источник, нужно использовать параметры:

poly = 0x8005
init = 0xffff
refin = true
refout = true
xorout = 0x0000
check = 0x4b37

это означает, что вы должны инициализировать crc как:

Crc16 crc(true, true, 0x8005, 0xffff, 0x0000, 0x8000, 0xffff);

Это возвращает согласованные CRC.

Постепенное вычисление crc
байтом 0 = 5
байтом 1 = 6
байтом 2 = 1
байтом 3 = 45
байтом 4 = 0
байтом 5 = 1
crc = 0x7BD8
Расчет crc за один вызов
Modbus crc = 0x7BD8


Но ваша настоящая проблема заключается в вычислении CRC более 7 байтов вместо 6 (crc.Modbus(data,0,7)). Если 7-й байт равен 0, результирующий CRC становится 0x5A7B.

person gre_gor    schedule 25.05.2020
comment
Большое спасибо за вашу помощь, я даже не осознавал, что забыл исправить эту строчку. Я воспроизвел ваши результаты без ошибок, изменив всего 0, 7 на 0, 6. - person TheMountainFurnaceGabriel; 25.05.2020