CRC16 (ModBus) - 计算算法

CRC16 (ModBus) - computing algorithm

我正在使用 ModBus RTU,我正在尝试弄清楚如何计算 CRC16。 我不需要代码示例。我只是对这个机制感到好奇。 我了解到基本的 CRC 是数据字的多项式除法,根据多项式的长度用零填充。 下面的测试例子是为了检查我的基本理解是否正确:

计算。

01001011000
 1001
 0000011000
      1001
      01010
       1001
       0011 

Edit1:到目前为止,Mark Adler 在之前的 comments/answers.

中进行了验证

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

的结果

Modbus RTU CRC16

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

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

如果有人能解释或阐明我的假设,那就太好了。老实说,我确实花了很多时间寻找答案,但每个解释都是基于 C/C++ 或其他我不理解的代码示例。提前致谢。

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

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

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

B) 参考 RefIn 和 RefOut:是否始终反映 8 位输入和所有输出位,尽管如此我使用 CRC8 或 CRC16 或 CRC32?

C) 我所指的网站中的第 3 列(检查)和第 8 列(XorOut)是什么意思?后者看起来相当简单,我猜它是通过计算 RefOut 之后的值 xor 来应用的,就像 InitValue?

让我们一步一个脚印。您现在已经知道如何正确计算 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。您将获得 table、0xb53f.

中的内容

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

中看到的结果

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

Init的异或是在反射后进行的,可以在table.

中使用CRC-16/RIELLO验证

补充问题的答案:

A) RefIn 与填充位无关。您反映输入字节。然而,在实际计算中,您反映的是多项式,它处理了两种反射。

B) 是的。

C) 是的,XorOut 是你独占的或最终的结果。校验是ASCII中的九个字节“123456789”的CRC校验。