CRC16(ModBus)——计算算法。

8
我正在使用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 

编辑1:此前的评论/答案已由Mark Adler进行了验证。

Modbus RTU CRC16

当然,我很想知道不同版本的CRC是如何工作的,但我的主要兴趣是简单地了解在这里应用的机制。 到目前为止,我所知道的是:

  • x16+x15+x2+1是多项式:0x18005或0b11000000000000101
  • 初始值为0xFFFF
  • 示例消息的十六进制:01 10 C0 03 00 01
  • 上述消息的CRC16值的十六进制为:C9CD

我像上面的示例一样手动计算了这个值,但我宁愿不在这个问题中以二进制书写。 我认为我的二进制转换是正确的。 我不知道的是如何整合初始值 - 它是用于填充数据字中的还是零? 还是我需要将答案反转? 还是其他什么?

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

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

如果有人能解释或澄清我的假设就太好了。 老实说,我花了很多时间寻找答案,但每个解释都基于C/C++或其他语言的代码示例,而我不理解。 预先感谢您。

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

编辑2:Mark Adlers答案解决了问题。 但是,现在我可以计算CRC16/Modbus,还有一些需要澄清的问题。 不需要但赞赏。

A)计算顺序将是:...?

  • 应用RefIn完成完整输入(包括填充位)
  • 在CRC16中,将InitValue与前16位xor
  • 应用RefOut完成完整输出/余数(在CRC16中的余数最多为16位)

B) 关于RefIn和RefOut: 无论我使用CRC8、CRC16还是CRC32,输入是否总是反射8位,输出是否总是反射所有位数?

C) 网站上的第3列(check)和第8列(XorOut)的含义是什么?后者似乎很容易理解,我猜测它被计算为在RefOut之后使用xor的值,就像InitValue一样?

1个回答

8
让我们一步一步来。你现在知道如何正确计算CRC-16/BUYPASS,所以我们从那里开始。
让我们看一下CRC-16/CCITT-FALSE。它的初始值不是零,但仍然具有RefIn和RefOut作为false,就像CRC-16/BUYPASS一样。要计算您的数据的CRC-16/CCITT-FALSE,您需要将数据的前16位与0xffff的Init值进行异或运算。这给出了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码格式的九个字节“123456789”的CRC。

你已经在第一行中添加了填充位。你将 000 添加到消息 01001011 的末尾。 - Mark Adler
非常感谢,我会编辑我的原始帖子,并可能删除以前的评论,以便将您的答案与我的问题匹配,而不会让任何人感到困惑。您介意看一下我为澄清而添加到我的问题中的其他问题吗? - Pratched
1
这个答案非常出色。不知道为什么三年多了我都没有得到任何赞?! - Ber

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接