如何将字节数组格式化为 Modbus 帧的 16 位 CRC 检查?

How to format a byte array to a 16bit CRC check for a Modbus frame?

我目前正在尝试使用 Arduino UNO R3 作为 Modbus 串行(不是 TCP/IP)通信协议中的主机。我试图为此使用过时的库,但无济于事,主要是由于不推荐使用的依赖项。无论如何,我决定从头开始,我目前的目标是将一个值写入寄存器 301(起始地址 300)到一个从机 I.D。 “5”。在连接到我的从机之前,我想确保我可以根据我是否将 0、1 或 2 写入寄存器来为帧重新生成 CRC。为了写入 1,我将帧设置为“05 06 01 2D 00 01 D8 7B”,根据我的研究,我可以看出 "D8 7B" 是数据的 16 位 CRC。然而,问题是我似乎无法在我的 Arduino 上复制 CRC 输出。我相信这与我准备和格式化字节数组的方式有关,但我不确定。我不太了解 CRC 算法,这就是我使用库的原因,任何帮助将不胜感激。

以下代码是 vinmenn's Crc16 library.

提供的示例草图的细微变化
#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 轮询程序,CRC 是 "D8 7B" 但是我的串行控制台报告“0x5A7B”

编辑:我修复了代码以反映超过六个字节 (0、5) 的 CRC 并更新了串行控制台输出。

解决方案:通过调整更正了问题 value = crc.Modbus(data,0,7);value = crc.Modbus(data,0,6);

按字节方式复制Modbus CRC16,根据the source,需要使用参数:

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

这意味着您应该将 crc 初始化为:

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

这个 returns 一致的 CRC。

Calculating crc incrementally
byte 0 = 5
byte 1 = 6
byte 2 = 1
byte 3 = 45
byte 4 = 0
byte 5 = 1
crc = 0x7BD8
Calculating crc in a single call
Modbus crc = 0x7BD8


但您的实际问题是计算 7 个字节而不是 6 个字节的 CRC (crc.Modbus(data,0,7))。如果第 7 个字节为 0,则结​​果 CRC 变为 0x5A7B。