为什么modbusrtu返回数据的CRC校验二个写法不同结果也不一样

那该多好啊!!! 2024-07-29 16:31:10

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);
        }

然后用到的二个函数是

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

...全文
942 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复

在MODBUS RTU通信协议中,CRC(循环冗余校验)是一个非常重要的部分,用于确保数据传输的准确性。然而,当你在不同的代码实现中看到CRC校验结果不一致时,可能会感到困惑。这主要是因为CRC算法虽然原理相同,但在具体实现上可能存在一些差异,比如初始值设置、字节顺序(大端序或小端序)、多项式的选择以及计算过程中的位移和异或操作顺序等。

首先,让我们回顾一下CRC校验的基本步骤。CRC校验通常包括初始化一个16位的寄存器为特定值(如FFFF),然后对数据帧中的每个字节进行处理,将其与CRC寄存器的低8位进行异或操作,接着对CRC寄存器进行右移,并根据移出的位决定是否与特定的多项式进行异或。这个过程会重复多次,直到处理完所有数据字节。最后,CRC寄存器的值就是计算得到的CRC校验码。

不同的实现可能在以下几个方面有所不同:

配图

  1. 初始值设置:有些实现可能将CRC寄存器初始化为FFFF,而有些可能使用其他值。
  2. 字节顺序:在计算CRC时,有的实现可能先处理低位字节,有的可能先处理高位字节,这会影响到最终CRC值的字节顺序。
  3. 多项式选择:虽然MODBUS RTU通常使用固定的多项式(如0xA001),但不同的应用场景可能会使用不同的多项式。
  4. 位移和异或操作顺序:在处理每个数据字节后,不同的实现可能会有不同的位移和异或操作顺序。

    配图

为了解决你在C#中遇到的CRC校验不一致问题,你可以尝试以下几个步骤:

  1. 确认多项式和初始值:确保你的实现使用的多项式和初始值与MODBUS RTU标准一致。
  2. 检查字节顺序:确定你的实现是否正确处理了字节顺序,特别是在将CRC值分解为高位和低位字节时。

    配图

  3. 对比测试数据:使用已知的测试数据和CRC值来验证你的实现是否正确。
  4. 调试和日志记录:在关键步骤添加日志记录,以便跟踪CRC计算过程中的每一步,找出可能的差异点。

推荐书籍

在深入学习CRC校验和MODBUS RTU协议时,以下几本书籍将是宝贵的资源:

推荐书籍图书特点
《通信原理》(作者:陈后金)这本书详细介绍了通信系统的基本原理,包括CRC校验的数学基础和实现方法。适合想要深入理解通信原理的读者。
《MODBUS协议详解》(作者:李文仲)专门讲解MODBUS协议的书籍,包括MODBUS RTU的详细工作原理和CRC校验的具体实现。适合需要深入了解MODBUS协议的工程师。
《嵌入式系统开发实战》(作者:刘火良)这本书涵盖了嵌入式系统开发的多个方面,包括串口通信和CRC校验的实现。适合嵌入式系统开发者。
《CRC理论与应用》(作者:Koopman, Philip)从理论到应用全面介绍CRC校验,包括不同多项式的选择和性能分析。适合对CRC校验有深入研究需求的读者。

这些书籍各有侧重,你可以根据自己的需求选择合适的书籍进行深入学习。希望这些推荐能帮助你更好地理解和解决CRC校验的问题。

已隐藏部分内容,更多查看原文

EmbSW_Guru_Wx 2024-10-18
  • 打赏
  • 举报
回复 1

你可以这样理解,你家有扇门,你领居家也有扇门。门的目的都是一样的,但是双方的门钥匙都仅能打开自己那扇门。

wanghui0380 2024-07-29
  • 打赏
  • 举报
回复

额,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
内容概要:本文详细介绍了欧姆龙CP1H PLC搭配CIF11通讯板与施耐德ATV71变频器之间的Modbus RTU协议通讯方案。首先阐述了硬件配置,包括CP1H与CIF11板的连接方式以及ATV71变频器的接线方法。接着深入探讨了变频器的关键参数设置,确保两者能够正确通信。随后展示了程序架构的设计思路,包括发送和接收缓冲区的定义、频率写入的具体实现步骤、接收处理的状态机写法,以及针对常见问题如响应延迟的解决方案。文中还提供了完整的代码示例,涵盖从硬件初始化到数据交互的全过程,并分享了一些实用的经验技巧,如双缓存机制的应用、CRC校验的注意事项等。此外,作者强调了扩展性和稳定性方面的考虑,例如通过调整波特率、增加终端电阻等方式提高系统的抗干扰能力。 适合人群:从事工业自动化领域的工程师和技术人员,尤其是对PLC与变频器通讯感兴趣的从业者。 使用场景及目标:适用于需要将欧姆龙CP1H PLC与施耐德ATV71变频器进行高效稳定的Modbus RTU协议通讯的实际工程项目中。主要目的是帮助读者快速掌握这一通讯方案的核心要点,减少调试时间和成本,提升系统可靠性。 其他说明:附带的程序包包含了详细的中文注释、Modbus地址表和接线图CAD文件,便于读者理解和实施。文中提到的一些优化措施对于提高通讯质量非常有用,如采用双绞屏蔽线、合理设置波特率等。

111,074

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • AIGC Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧