111,074
社区成员




MODBUS接收返回过来的数据时,要进行CRC校验
第一个是我在网上下的,是CRC校验证,和网上对比是正确的。
public static byte[] CRCCalc(byte[] data)
{
//1.预置1个16位的寄存器为十六进制FFFF(即全为1); 称此寄存器为CRC寄存器;
//crc计算赋初始值
var crc = 0xffff;
for (var i = 0; i < data.Length; i++)
{
//2.把第一个8位二进制数据(既通讯信息帧的第一个字节)与16位的CRC寄存器的低8位相异或,把结果放于CRC寄存器;
crc = crc ^ data[i]; //将八位数据与crc寄存器异或 ,异或的算法就是,两个二进制数的每一位进行比较,如果相同则为0,不同则为1
//3.把CRC寄存器的内容右移一位(朝低位)用0填补最高位,并检查右移后的移出位;
//4.如果移出位为0:重复第3步(再次右移一位); 如果移出位为1:CRC寄存器与多项式A001(1010 0000 0000 0001)进行异或;
//5.重复步骤3和4,直到右移8次,这样整个8位数据全部进行了处理;
for (var j = 0; j < 8; j++)
{
int temp;
temp = crc & 1;
crc = crc >> 1;
crc = crc & 0x7fff;
if (temp == 1) crc = crc ^ 0xa001;
crc = crc & 0xffff;
}
}
//CRC寄存器的高低位进行互换
可是我看了别人的一个程序,他的返回的CRC校验不一样,不知道他这是怎么回事,
先传入要校验的数据
public ushort CalculateCrc16(byte[] buffer, out byte crcLo, out byte crcHi)//协议默认低位在前
{
crcHi = 0xff; // high crc byte initialized
crcLo = 0xff; // low crc byte initialized
for (int i = 0; i < buffer.Length - 2; i++)
{
int crcIndex = crcHi ^ buffer[i]; // calculate the crc lookup index
crcHi = (byte)(crcLo ^ _auchCRCHi[crcIndex]);
crcLo = _auchCRCLo[crcIndex];
}
return (ushort)(crcHi << 8 | crcLo);
}
然后用到的二个函数是
在MODBUS RTU通信协议中,CRC(循环冗余校验)是一个非常重要的部分,用于确保数据传输的准确性。然而,当你在不同的代码实现中看到CRC校验结果不一致时,可能会感到困惑。这主要是因为CRC算法虽然原理相同,但在具体实现上可能存在一些差异,比如初始值设置、字节顺序(大端序或小端序)、多项式的选择以及计算过程中的位移和异或操作顺序等。
首先,让我们回顾一下CRC校验的基本步骤。CRC校验通常包括初始化一个16位的寄存器为特定值(如FFFF),然后对数据帧中的每个字节进行处理,将其与CRC寄存器的低8位进行异或操作,接着对CRC寄存器进行右移,并根据移出的位决定是否与特定的多项式进行异或。这个过程会重复多次,直到处理完所有数据字节。最后,CRC寄存器的值就是计算得到的CRC校验码。
不同的实现可能在以下几个方面有所不同:
为了解决你在C#中遇到的CRC校验不一致问题,你可以尝试以下几个步骤:
在深入学习CRC校验和MODBUS RTU协议时,以下几本书籍将是宝贵的资源:
推荐书籍 | 图书特点 |
---|---|
《通信原理》(作者:陈后金) | 这本书详细介绍了通信系统的基本原理,包括CRC校验的数学基础和实现方法。适合想要深入理解通信原理的读者。 |
《MODBUS协议详解》(作者:李文仲) | 专门讲解MODBUS协议的书籍,包括MODBUS RTU的详细工作原理和CRC校验的具体实现。适合需要深入了解MODBUS协议的工程师。 |
《嵌入式系统开发实战》(作者:刘火良) | 这本书涵盖了嵌入式系统开发的多个方面,包括串口通信和CRC校验的实现。适合嵌入式系统开发者。 |
《CRC理论与应用》(作者:Koopman, Philip) | 从理论到应用全面介绍CRC校验,包括不同多项式的选择和性能分析。适合对CRC校验有深入研究需求的读者。 |
这些书籍各有侧重,你可以根据自己的需求选择合适的书籍进行深入学习。希望这些推荐能帮助你更好地理解和解决CRC校验的问题。
你可以这样理解,你家有扇门,你领居家也有扇门。门的目的都是一样的,但是双方的门钥匙都仅能打开自己那扇门。
额,CRC算法固定,但是过程不固定。主要是初始二项式参数和中间算补码还是最后算补码
所以总体上一个CRC常见就有 20多种不同实现。
不过你要找资料请加“modbus CRC” 因为modbus是这20多种的其中一种,而且是固定实现(哎,这要还不固定,大家可真就无法对接了)
private readonly byte[] _auchCRCHi = new byte[]//crc高位表
{
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
,,,,,,,,,,,,,,,,,,,,,
0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
};
private readonly byte[] _auchCRCLo = new byte[]//crc低位表
{
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,
0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,
0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
0x43, 0x83, 0x41, 0x81, 0x8