我正在使用ModBus RTU,我正在试图弄清楚如何计算CRC16。我不需要代码示例。我只是好奇这个机制。我已经知道基本CRC是数据字的多项式除法,用零填充,取决于多项式的长度。以下测试示例应该检查我的基本理解是否正确:
计算。
01001011000
1001
0000011000
1001
01010
1001
0011
编辑1:到目前为止,Mark Adler在之前的评论/答案中进行了验证。
寻找答案我已经看到了许多不同的方法,包括逆转,依赖于小端或大端等,这改变了给定的011
的结果。
Modus RTU KRS16
当然我很想了解不同版本的CRC是如何工作的,但我的主要兴趣是简单地理解这里应用的机制。到目前为止,我知道:
我像上面的例子一样手动计算了这个,但我宁愿不在这个问题中用二进制写下来。我认为我对二进制的转换是正确的。我不知道的是如何合并初始值 - 它是用来填充数据字而不是零?或者我是否需要撤消答案?别的什么?
1111 1111 1001 1011
,其为十六进制的FF9B
,对于CrC16 / Modbus不正确,但对于CRC16 /旁路是正确的0000 0000 0110 0100
,其为十六进制的0064
且不正确。如果有人可以解释或澄清我的假设,那将是很好的。老实说,我花了很多时间寻找答案,但每个解释都是基于C / C ++或其他的代码示例,我不明白。提前致谢。
编辑1:根据this网站,“第一次尝试”指向另一个具有相同多项式但具有不同初始值(0x0000)的CRC16方法,这告诉我,计算应该是正确的。 如何合并初始值?
EDIT2:马克阿德勒斯答案就行了。但是,现在我可以计算CRC16 / Modbus,还有一些问题需要澄清。不需要,但赞赏。
A)计算的顺序是:......?
xor
InitValue(在CRC16中)为前16位B)参考RefIne和RefOut:它是否始终反映8位输入和所有输出位仍然使用CRC 8或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,请使用0xffff
的Init值对数据的前16位进行异或。这给了fe ef C0 03 00 01
。现在做你所知道的,但用多项式0x11021
。你会得到表格中的内容,0xb53f
。
现在您知道如何应用Init。下一步是处理RefIn和RefOut是真的。我们将以CRC-16 / ARC为例。 RefIn意味着我们反映输入的每个字节中的位。 RefOut意味着我们反映剩余部分的比特。输入消息是:80 08 03 c0 00 80
。除以多项式0x18005
,我们得到0xb34b
。现在我们反映所有这些位(不是每个字节,而是所有16位),我们得到0xd2cd
。这就是你在表格中看到的结果。
我们现在有了计算CRC-16 / MODBUS所需的东西,它具有非零的初始值(0xffff
)和RefIn和RefOut都为真。我们从消息开始,每个字节中的位被反射,前16位被反转。那就是7f f7 03 c0 00 80
。除以0x18005
,你得到剩余的0xb393
。反映这些位,我们得到0xc9cd
,预期的结果。
在反射之后应用Init或者Init,您可以使用该表中的CRC-16 / RIELLO进行验证。
增加问题的答案:
A)RefIn与填充位无关。您反映输入字节。但是,在实际计算中,您会反映多项式,它会处理两种反射。
B)是的。
C)是的,XorOut是您的独家或最终结果。检查是ASCII中九个字节“123456789”的CRC。