Modbus-crc16校验原理和方法(含测试代码以及演算过程)

自学记录!内容来源:Modbus-crc16校验原理和方法(含测试代码以及演算过程)_单片机_墨小羽ovo-GitCode 开源社区 (csdn.net)

1.Modbus基础

Modbus是一种串行通信协议,最初由Modicon(目前属于施耐德电气公司)于1979年开发。Modbus协议是应用在Modicon产品上的,后来才被移植到其他产品上。Modbus协议的通信接口可以有多种选择,如RS232、RS485、以太网等。

特点:支持主从方式,即主站、从站。Modbus协议主要分为两种格式,即Modbus RTU和Modbus ASCII,Modbus RTU使用二进制格式传输数据,而Modbus ASCII则将数据以ASCII码形式进行传输。此外,Modbus还可以通过TCP/IP协议进行网络通信,称为Modbus TCP/IP。

格式:   (1) 起始地址(也就是常说的站号)
              (2) 功能码 (01,03,06,10,16等等)
              (3) 数据内容
              (4) 校验码(CRC16校验)

2.校验原理

2.1 CRC计算方法:
    1.预置1个16位的寄存器为十六进制FFFF(即全为1);称此寄存器为CRC寄存器;
    2.把第一个8位二进制数据(既通讯信息帧的第一个字节)与16位的CRC寄存器的低8位相异或,把结果放于CRC寄存器;
    3.把CRC寄存器的内容右移一位(朝低位)用0填补最高位,并检查右移后的移出位;
    4.如果移出位为0:重复第3步(再次右移一位);如果移出位为1:CRC寄存器与多项式A001(1010 0000 0000 0001)进行异或;
   5.重复步骤3和4,直到右移8次,这样整个8位数据全部进行了处理;
   6.重复步骤2到步骤5,进行通讯信息帧下一个字节的处理;
   7.将该通讯信息帧所有字节按上述步骤计算完成后,得到的16位CRC寄存器的高、低字节进行交换。

2.2校验C语言代码

 /*
    * @name   CRC_Check
    * @brief  CRC校验
    * @param  CRC_Ptr->数组指针,LEN->长度
    * @retval CRC校验值      
*/
uint16_t CRC_Check(uint8_t *CRC_Ptr,uint8_t LEN)
{
    uint16_t CRC_Value = 0;
    uint8_t  i         = 0;
    uint8_t  j         = 0;

    CRC_Value = 0xffff;
    for(i=0;i<LEN;i++)  //LEN为数组长度
    {
        CRC_Value ^= *(CRC_Ptr+i);
        for(j=0;j<8;j++)
        {
            if(CRC_Value & 0x00001)
                CRC_Value = (CRC_Value >> 1) ^ 0xA001;
            else
                CRC_Value = (CRC_Value >> 1);
        }
    }
    CRC_Value = ((CRC_Value >> 8) +  (CRC_Value << 8)); //交换高低字节

    return CRC_Value;
}
uint16_t CRC_Check(uint8_t *CRC_Ptr,uint8_t LEN)
{
    uint16_t CRC_Value = 0;
    uint8_t  i = 0;
    uint8_t  j = 0;
    CRC_Value = 0xffff;
    for(i=0;i<LEN;i++)  //LEN为数组长度
    {
        CRC_Value ^= *(CRC_Ptr+i);
        for(j=0;j<8;j++)
        {
            if(CRC_Value & 0x00001)
                CRC_Value = (CRC_Value >> 1) ^ 0xA001;
            else
                CRC_Value = (CRC_Value >> 1);
        }
    }
    CRC_Value = ((CRC_Value >> 8) +  (CRC_Value << 8)); //交换高低字节
    return CRC_Value;
}

2.3手算校验

 我们以这个数据包为例,来分析一下校验过程:
    Tx:000002-01 03 00 00 00 0A C5 CD
    01 起始地址   03功能码  C5 CD 校验码

0x01与0xffff相异或,进行第一轮右移8次运算,得到0x807e;

继续下一轮0x03与0x807e相异或,进行第二轮右移8次运算;

直至0x0A轮次完成,得到最终的crc计算结果C5CD。

2.4modbus测试程序

#include <stdio.h>
int main(void)
{
    // Tx:000000-01 03 00 00 00 0A C5 CD
    unsigned short tmp = 0xffff;
    unsigned short val = 0;
    unsigned char buff[6] = {0};
    buff[0] = 0x01;
    buff[1] = 0x03;
    buff[2] = 0x00;
    buff[3] = 0x00;
    buff[4] = 0x00;
    buff[5] = 0x0A;

   for(int n = 0; n < 6; n++)
  {
    tmp = buff[n] ^ tmp;
    printf("异或数据为:%x\n",tmp);
    for(int i = 0;i < 8;i++){  /*此处的8 -- 指每一个char类型又8bit,每bit都要处理*/
       
        printf("遍历层数为:%d\t\t最后一位的数为:%d",i*n, tmp & 0x01);
        printf("\t当前tmp为:%x\n",tmp );
        if(tmp & 0x01){
            
            tmp = tmp >> 1;
            tmp = tmp ^ 0xa001;
        }   
        else{
            tmp = tmp >> 1;
        }   
    }   
    printf("第%d个数据通过crc16校验后为 %x\n",n,tmp);
}  



/*将CRC校验的高低位对换位置*/
val = tmp >> 8;
val = val | (tmp << 8); 
printf("交换后为: %X\n",val);
return 0;
}

备注:补充tip!

异或 / 相异或

相异或(XOR,Exclusive OR)是一种逻辑运算,它的基本原则是:当两个比较的位不同时,结果是1(真);当两个比较的位相同时,结果是0(假)。这种运算通常用于计算机科学和数字电子学中。

在这里的“A”和“B”是两个比较的位,而“A XOR B”是相异或运算的结果。二进制运算中,相异或的规则可以用下面的真值表来表示:

A   B   A XOR B
0   0   0
0   1   1
1   0   1
1   1   0

相与

相与运算,通常称为“逻辑与”(Logical AND),是一种基本的逻辑运算。在逻辑与运算中,只有当两个(或多个)输入条件都为真(1)时,输出结果才为真(1);如果任何一个输入条件为假(0),输出结果就为假(0)。

这里的“A”和“B”是两个输入位,而“A AND B”是逻辑与运算的结果。逻辑与运算的真值表如下所示:

A   B  A AND B
0   0    0
0   1    0
1   0    0
1   1    1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值