CRC16(ModBus)-计算算法

时间:2019-03-15 09:54:26

标签: modbus crc16 boolean-polynomials

我正在使用ModBus RTU,并且试图弄清楚如何计算CRC16。 我不需要代码示例。我只是对该机制感到好奇。 我了解到,基本CRC是数据字的多项式除法,该多项式除以零填充,具体取决于多项式的长度。 以下测试示例应该检查我的基本理解是否正确:

  • 数据字:0100 1011
  • 多项式:1001(x 3 +1)
  • 由于最高指数x 3
  • 而被3位填充
  • 计算:0100 1011 000/1001->余数:011

计算。

01001011000
 1001
 0000011000
      1001
      01010
       1001
       0011 

Edit1:到目前为止,由Mark Adler在先前的评论/答案中进行了验证。

在寻找答案时,我看到了很多不同的方法,包括反转,依赖大端字节序或小端字节序等,这些改变了给定011的结果。

Modbus RTU CRC16

当然,我很想了解不同版本的CRC的工作原理,但我的主要兴趣是简单了解此处应用的机制。到目前为止,我知道:

  • x 16 + x 15 + x 2 +1是多项式:0x18005或0b11000000000000101
  • 初始值为0xFFFF
  • 十六进制消息示例:01 10 C0 03 00 01
  • 上述消息的CRC16(十六进制):C9CD

我确实像上面的示例一样手动计算了这一点,但是在这个问题中,我不想将其写成二进制。我认为我转换成二进制是正确的。我不知道如何合并初始值-是否用它来填充数据字而不是零?还是我需要扭转答案?还有吗?

  • 第一次尝试:用零填充16位。 计算得出的二进制余数将为1111 1111 1001 1011,十六进制为FF9B,对于CrC16 / Modbus不正确,但对于CRC16 / Bypass则正确

  • 第二次尝试:由于初始值,用1填充16位。 计算得出的二进制余数为0000 0000 0110 0100,十六进制为0064,不正确。

如果有人可以解释或阐明我的假设,那将是很棒的。老实说,我确实花了很多时间来寻找答案,但是每一个解释都是基于C / C ++或其他我不理解的代码示例。预先感谢。

EDIT1:根据this网站,“第一次尝试”指向另一个具有相同多项式但初始值(0x0000)不同的CRC16方法,这告诉我,计算应该是正确的。 crccalc 如何合并初始值?

EDIT2:Mark Adlers Answer可以解决问题。但是,现在我可以计算CRC16 / Modbus了,还有一些问题需要澄清。不需要,但值得赞赏。

A)计算顺序为:...?

  • 第一次将RefIn用于完整的输入(包括填充位)
  • 第二个xor InitValue,前16位(在CRC16中)
  • 第三次将RefOut用于完整的输出/余数(CRC16中的余数最大为16位)

B)引用RefIn和RefOut:我是否始终使用CRC8或CRC16或CRC32来表示输入的8位,并输出所有位?

C)我指的是网站上的第三列(检查)和第八列(XorOut)是什么意思?后者似乎相当容易,我猜想它是通过像InitValue一样计算RefOut之后的值xor来实现的。

1 个答案:

答案 0 :(得分:0)

让我们一次迈出这一步。现在,您知道了如何正确计算CRC-16 / BUYPASS,因此我们将从此处开始。

让我们看一下CRC-16 / CCITT-FALSE。该值的初始值不为零,但RefIn和RefOut仍为false,例如CRC-16 / BUYPASS。要对数据计算CRC-16 / CCITT-FALSE,请使用Init值0xffff对数据的前16位进行异或运算。得到fe ef C0 03 00 01。现在,用多项式0x11021来做您所知道的。您将获得表0xb53f中的内容。

现在您知道如何应用Init。下一步是将RefIn和RefOut处理为 true 。我们将以CRC-16 / ARC为例。 RefIn表示我们在输入的每个字节中反映位。 RefOut表示我们反映了其余部分。输入的消息为:80 08 03 c0 00 80。除以多项式0x18005得到0xb34b。现在我们反射所有这些位(不是在每个字节中,而是所有16位),然后得到0xd2cd。这就是您在表中看到的结果。

我们现在有了计算CRC-16 / MODBUS所需的内容,它具有一个非零的Init值(0xffff)且RefIn和RefOut为true。我们从消息开始,每个字节中的位反映出 ,并且前16位反转。那就是7f f7 03 c0 00 80。除以0x18005,您将得到其余的0xb393。反映这些位,我们得到0xc9cd,即预期的结果。

在反射之后应用Init的异或运算,您可以在该表中使用CRC-16 / RIELLO进行验证。

其他问题的答案:

A)RefIn与填充位无关。您反映输入字节。但是,在实际计算中,您将反射多项式,而这将同时考虑这两种反射。

B)是。

C)是的,XorOut是您独占的东西-或最终结果。检查以ASCII表示的9个字节“ 123456789”的CRC。