我正在使用ModBus RTU,并且试图弄清楚如何计算CRC16。 我不需要代码示例。我只是对该机制感到好奇。 我了解到,基本CRC是数据字的多项式除法,该多项式除以零填充,具体取决于多项式的长度。 以下测试示例应该检查我的基本理解是否正确:
计算。
01001011000
1001
0000011000
1001
01010
1001
0011
Edit1:到目前为止,由Mark Adler在先前的评论/答案中进行了验证。
在寻找答案时,我看到了很多不同的方法,包括反转,依赖大端字节序或小端字节序等,这些改变了给定011
的结果。
Modbus RTU CRC16
当然,我很想了解不同版本的CRC的工作原理,但我的主要兴趣是简单了解此处应用的机制。到目前为止,我知道:
我确实像上面的示例一样手动计算了这一点,但是在这个问题中,我不想将其写成二进制。我认为我转换成二进制是正确的。我不知道如何合并初始值-是否用它来填充数据字而不是零?还是我需要扭转答案?还有吗?
第一次尝试:用零填充16位。
计算得出的二进制余数将为1111 1111 1001 1011
,十六进制为FF9B
,对于CrC16 / Modbus不正确,但对于CRC16 / Bypass则正确
第二次尝试:由于初始值,用1填充16位。
计算得出的二进制余数为0000 0000 0110 0100
,十六进制为0064
,不正确。
如果有人可以解释或阐明我的假设,那将是很棒的。老实说,我确实花了很多时间来寻找答案,但是每一个解释都是基于C / C ++或其他我不理解的代码示例。预先感谢。
EDIT1:根据this网站,“第一次尝试”指向另一个具有相同多项式但初始值(0x0000)不同的CRC16方法,这告诉我,计算应该是正确的。 如何合并初始值?
EDIT2:Mark Adlers Answer可以解决问题。但是,现在我可以计算CRC16 / Modbus了,还有一些问题需要澄清。不需要,但值得赞赏。
A)计算顺序为:...?
xor
InitValue,前16位(在CRC16中)B)引用RefIn和RefOut:我是否始终使用CRC8或CRC16或CRC32来表示输入的8位,并输出所有位?
C)我指的是网站上的第三列(检查)和第八列(XorOut)是什么意思?后者似乎相当容易,我猜想它是通过像InitValue一样计算RefOut之后的值xor
来实现的。
答案 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。