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

问题描述 投票:0回答:1

我目前正试图使用Arduino UNO R3作为Modbus串行(不是TCPIP)通信协议的主站。我曾尝试使用过时的库,但无济于事,主要是由于过时的依赖性。无论如何,我决定从头开始,我目前的目标是向寄存器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的CRC16库.

#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轮询 来帮我把我的字节整理成帧。Bellow是程序输出的截图。

Modbus Poll

再次,任何帮助将被感激。先谢谢你

编辑:我没有提到所提供的材料如何详细说明我的问题。根据Modbus轮询程序,CRC是 "D8 7B",然而我的串行控制台报告的是 "0x5A7B"

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

解决了。纠正了这个问题,调整了value = crc.Modbus(data,0,7);value = crc.Modbus(data,0,6);

arduino modbus crc16
1个回答
2
投票

至于用逐字节的方法复制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。

© www.soinside.com 2019 - 2024. All rights reserved.