查询行业信息的网站,网上装修公司网站策划书,基于asp网站开发 论文,兰州建网站文章目录 CRC概述CRC名词解释宽度 (WIDTH)多项式 #xff08;POLY#xff09;初始值 #xff08;INIT#xff09;结果异或值 #xff08;XOROUT#xff09;输入数据反转#xff08;REFIN#xff09;输出数据反转#xff08;REFOUT#xff09; CRC手算过程模二加减POLY初始值 INIT结果异或值 XOROUT输入数据反转REFIN输出数据反转REFOUT CRC手算过程模二加减异或运算XOR运算过程 直接计算输入数据不反转输入数据反转方法1方法2 查表法原理表的生成查表法代码 总结 原文链接
https://blog.csdn.net/stronger2017/article/details/72903415 原文链接https://blog.csdn.net/fuckthebugs/article/details/132267279
原文链接https://blog.csdn.net/m0_57585228/article/details/125088520
CRC概述
###校验 校验是什么个人理解就是经过一个算法使用大量数据几MB的数据生成较小长度的一串信息(如16Bit)并切要做到 原数据不同时生成的信息大概率不同不是加密算法不考虑刻意造数据的情况 原数据中任意一个或几个数据出现错误时生成的信息不同所有的原信息都需要被囊括进生成数据中也就是说每一个数据都必须参与校验的计算过程并且能对其产生影响
CRC名词解释
宽度 (WIDTH)
即最后生成的数据长度
可以为任意长度 一般使用16bit或32bit 如0xFFFF是16bit的校验和 如0xFFFFFFFF是32bit的校验和 多项式 POLY
这个多项式的每项的系数为0或1最高系数是和宽度相等因为有0次幂存在因此总多项式为
宽度1项
例如16bit的CRC16-MODBUS的生成多项式为
x^16 x^15 x^2 1,用HEX表示为0x1 8005 要求最高幂这里是x的16次方系数为1最低次幂永远是x的0次方系数为1 因为最高次一定为1因此可以将其省略所有生成多项式的值为0x8005
注意多项式的其他位可以是任意的但是检验效果并不完全相同建议使用某些协议规定的多项式
初始值 INIT
因为使用程序进行CRC计算时使用一个宽度 (WIDTH)为长度的寄存器进行
我们需要给这个寄存器写入初始值写入的初始值即为这个值
一般为全是0或者全是1 如16bit为0xFFFF或0x0000 结果异或值 XOROUT
计算完成后输出之前需要于此值进行异或操作
一般为全0或全1长度和宽度 (WIDTH)相等
输入数据反转REFIN
CRC计算时是以字节(Byte)为单位输入寄存器中的 这个参数是说明输入是从这个数据的 直接输入寄存器则是高位到低位 经过反转输入则是低位到高位 具体输入到寄存器的哪个位置之后再说 反转的例子 0x800b1000 0000反转之后就是0x010b0000 0001 0x500b0101 0000反转之后就是0x0A (0b0000 1010) 输出数据反转REFOUT
输出数据反转和输入反转类似
只不过是以宽度 (WIDTH)为基准反转而已 如0x8000(0b1000 0000 0000 0000)反转是0x0001 (0b0000 0000 0000 0001) 如0xA000(0b1010 0000 0000 0000)反转是0x0005 (0b0000 0000 0000 0101) 使用CRC的协议会将这些都规定好需要时查询即可
CRC手算过程
这只是帮助理解所使用的过程应用中一般人不会手算CRC吧这里先忽略初值选取简单的数据和多项式
模二加减异或运算XOR
这三个说法是等价的即运算的两个算子相同为0不同为1,c语言中为 例子0b0^0b10b1 0b1100^0b11100b0010 运算过程
在数据最后补0位数与宽度相等 将多项式完整的的最高项与数据的第一个1对齐其他位当作0即可也就是不改变数据 整体进行异或操作 重复上述操作直到所有数据均参与了计算参与有2种作为0被掠过也算参与 所以计算值为0b1110(0xE) 进入在线计算网站验证如下图
直接计算
输入数据不反转
从刚才的手算过程中可以看出如果每一个数据均需要被遍历如果为0则掠过如果为1则进行异或操作 很明显需要使用循环来进行操作 因为是按照字节Byte来传输数据 因此需要嵌套循环外层改变传入的数据内层遍历8个位bit 首先建立寄存器CRC这里以16位为例则需要数据类型为u16 填入初值这里是0xFFFF 因为要向左移位因此将数据放到寄存器的高8位32位就是最高的8位中与高8位异或放入 如果最高位为1则先左移1位后寄存器与多项式异或如果为0则仅仅左移1位 重复直到所有数据都参与 寄存器中剩下的便是CRC结果 为什么要放到高8位呢 因为异或具有交换律和结合律这里不证明请查百度 因此后8位本质上是将高8位的数据所计算的异或值本应该与下一个字节进行计算的先一步进行运算 在往后只需要将下一个字节的数据与移位后的高8位上一个字节提前计算的异或即可了 代码例子C语言写的
u16 CRC16(u8 * Dat, int Len)
{u16 Poly 0x8005;u16 CRC 0xffff;u8 Zj 0;for (int i 0; i Len; i){
//在这里加输入反转Zj (Dat[i]);CRC ^ (Zj 8);for (int j 0; j 8; j){if (CRC 0x8000){CRC 1;CRC ^ Poly;}else{CRC 1;}}}
//在这里加输出反转return ((CRC)^0x0000);
}如果需要反转输出则在输出异或之前加上反转部分的代码即可 反转 的实现 u16 CRC_Reverse_16(u16 Dat)
{u16 Res 0;u16 zj Dat;for (int i 0; i 16; i){if (zj 0x8000)Res 1i;zj 1;}return Res;
}
u8 CRC_Reverse_8(u8 Dat)
{u8 Res 0;u8 zj Dat;for (int i 0; i 8; i){if (zj 0x80)Res 1 i;zj 1;}return Res;
}输入数据反转
方法1
可以直接在输入之前加上反转的代码即可即上面加注释的位置 优点编程简单无需改架构 缺点运算量大会占用更多时间 方法2
将上述代码改为向右移动这样做之后输出也会自动反转如需正向则需反转回来这个运算量小 注意需要与寄存器的低8位进行异或32位就是最低的8位 例子代码 u16 CRC16_ModBus(u8 * Dat, int Len)
{u16 Poly CRC_Reverse_16(0x8005);u16 CRC 0xffff;u8 Zj 0;for (int i 0; i Len; i){CRC ^ Dat[i];for (int j 0; j 8; j){if (CRC 0x0001){CRC 1;CRC ^ Poly;}else{CRC 1;}}}return (CRC ^ 0x0000);
}这个是用来计算MODBUS的CRC校验的
即输入输出均反转 下边是验证 查表法
上述计算过程运算量相等较大因为每移动一位均需要计算一次异或操作适合上位机使用
下位机还是建议使用查表法如果将1Byte的数据做成表只需要之前的1/8的计算量
原理
异或操作的交换律和结合律
将1Byte数据直接进行消除直接计算的原理类似也是将异或值提前计算只是在程序开跑之前就计算了这个计算值就是表
表的生成
使用表是以空间换时间的操作方式
为了便于计算出表我们将初始值设为0也可以不为全0只不过需要多一步异或而已与输入的那Byte数据进行异或的部分必须为0输入0-0xFF的1Byte数据进行CRC输出值为表 生成MODBUS的表的例程 u16 CRC16_ModBus1(u8 Dat)
{u16 Poly CRC_Reverse_16(0x8005);u16 CRC 0xffff;u8 Zj 0;for (int i 0; i Len; i){CRC ^ Dat[i];for (int j 0; j 8; j){if (CRC 0x0001){CRC 1;CRC ^ Poly;}else{CRC 1;}}}return (CRC ^ 0x0000);
}
int main()
{u8 i0;for(i0;i0xFF;i){printf(%X,CRC16_ModBus1(i));}
}查表法代码 这是生成的表 const u16 T[256]
{0x0000,0xC0C1,0xC181,0x0140,0xC301,0x03C0,0x0280,0xC241,0xC601,0x06C0,0x0780,0xC741,0x0500,0xC5C1,0xC481,0x0440,0xCC01,0x0CC0,0x0D80,0xCD41,0x0F00,0xCFC1,0xCE81,0x0E40,0x0A00,0xCAC1,0xCB81,0x0B40,0xC901,0x09C0,0x0880,0xC841,0xD801,0x18C0,0x1980,0xD941,0x1B00,0xDBC1,0xDA81,0x1A40,0x1E00,0xDEC1,0xDF81,0x1F40,0xDD01,0x1DC0,0x1C80,0xDC41,0x1400,0xD4C1,0xD581,0x1540,0xD701,0x17C0,0x1680,0xD641,0xD201,0x12C0,0x1380,0xD341,0x1100,0xD1C1,0xD081,0x1040,0xF001,0x30C0,0x3180,0xF141,0x3300,0xF3C1,0xF281,0x3240,0x3600,0xF6C1,0xF781,0x3740,0xF501,0x35C0,0x3480,0xF441,0x3C00,0xFCC1,0xFD81,0x3D40,0xFF01,0x3FC0,0x3E80,0xFE41,0xFA01,0x3AC0,0x3B80,0xFB41,0x3900,0xF9C1,0xF881,0x3840,0x2800,0xE8C1,0xE981,0x2940,0xEB01,0x2BC0,0x2A80,0xEA41,0xEE01,0x2EC0,0x2F80,0xEF41,0x2D00,0xEDC1,0xEC81,0x2C40,0xE401,0x24C0,0x2580,0xE541,0x2700,0xE7C1,0xE681,0x2640,0x2200,0xE2C1,0xE381,0x2340,0xE101,0x21C0,0x2080,0xE041,0xA001,0x60C0,0x6180,0xA141,0x6300,0xA3C1,0xA281,0x6240,0x6600,0xA6C1,0xA781,0x6740,0xA501,0x65C0,0x6480,0xA441,0x6C00,0xACC1,0xAD81,0x6D40,0xAF01,0x6FC0,0x6E80,0xAE41,0xAA01,0x6AC0,0x6B80,0xAB41,0x6900,0xA9C1,0xA881,0x6840,0x7800,0xB8C1,0xB981,0x7940,0xBB01,0x7BC0,0x7A80,0xBA41,0xBE01,0x7EC0,0x7F80,0xBF41,0x7D00,0xBDC1,0xBC81,0x7C40,0xB401,0x74C0,0x7580,0xB541,0x7700,0xB7C1,0xB681,0x7640,0x7200,0xB2C1,0xB381,0x7340,0xB101,0x71C0,0x7080,0xB041,0x5000,0x90C1,0x9181,0x5140,0x9301,0x53C0,0x5280,0x9241,0x9601,0x56C0,0x5780,0x9741,0x5500,0x95C1,0x9481,0x5440,0x9C01,0x5CC0,0x5D80,0x9D41,0x5F00,0x9FC1,0x9E81,0x5E40,0x5A00,0x9AC1,0x9B81,0x5B40,0x9901,0x59C0,0x5880,0x9841,0x8801,0x48C0,0x4980,0x8941,0x4B00,0x8BC1,0x8A81,0x4A40,0x4E00,0x8EC1,0x8F81,0x4F40,0x8D01,0x4DC0,0x4C80,0x8C41,0x4400,0x84C1,0x8581,0x4540,0x8701,0x47C0,0x4680,0x8641,0x8201,0x42C0,0x4380,0x8341,0x4100,0x81C1,0x8081,0x4040
};查表的代码和直接计算类似只需要注意两点 每次移动8位 移动之前要与数据进行异或操作来生成表的序号移动异或之后的低位就相当于直接计算的一个循环走完重新输入数据了这里是将8位数据直接消除因此需要生成标号这个标号仅使用即可无需放入寄存器中因为它马上就因为移位丢失了 MODBUS的查表法代码
u16 CRC16_ModBus2(u8 *Dat, int Len)
{u16 CRC 0xffff;//初始值u8 Zj;for (int i 0; i Len ; i){Zj (CRC 0xFF)^ Dat[i];//生成标号一次将低8位数据消除CRC 8;CRC ^ T[Zj];}return (CRC);
}总结
typedef unsigned char u8;
typedef unsigned short int u16;u16 CRC_Reverse_16(u16 Dat)
{u16 Res 0;u16 zj Dat;for (int i 0; i 16; i){if (zj 0x8000)Res 1i;zj 1;}return Res;
}
u8 CRC_Reverse_8(u8 Dat)
{u8 Res 0;u8 zj Dat;for (int i 0; i 8; i){if (zj 0x80)Res 1 i;zj 1;}return Res;
}
u16 CRC16_ModBus_Forward(u8 * Dat, int Len)
{u16 Poly 0x8005;u16 CRC 0xffff;u8 Zj 0;for (int i 0; i Len; i){Zj CRC_Reverse_8(Dat[i]);CRC ^ (Zj 8);for (int j 0; j 8; j){if (CRC 0x8000){CRC 1;CRC ^ Poly;}else{CRC 1;}}}return (CRC_Reverse_16(CRC)^0x0000);
}
u16 CRC16_ModBus_Reverse(u8 * Dat, int Len)
{u16 Poly CRC_Reverse_16(0x8005);u16 CRC 0xffff;u8 Zj 0;for (int i 0; i Len; i){CRC ^ Dat[i];for (int j 0; j 8; j){if (CRC 0x0001){CRC 1;CRC ^ Poly;}else{CRC 1;}}}return (CRC ^ 0x0000);
}
const u16 T[256]
{0x0000,0xC0C1,0xC181,0x0140,0xC301,0x03C0,0x0280,0xC241,0xC601,0x06C0,0x0780,0xC741,0x0500,0xC5C1,0xC481,0x0440,0xCC01,0x0CC0,0x0D80,0xCD41,0x0F00,0xCFC1,0xCE81,0x0E40,0x0A00,0xCAC1,0xCB81,0x0B40,0xC901,0x09C0,0x0880,0xC841,0xD801,0x18C0,0x1980,0xD941,0x1B00,0xDBC1,0xDA81,0x1A40,0x1E00,0xDEC1,0xDF81,0x1F40,0xDD01,0x1DC0,0x1C80,0xDC41,0x1400,0xD4C1,0xD581,0x1540,0xD701,0x17C0,0x1680,0xD641,0xD201,0x12C0,0x1380,0xD341,0x1100,0xD1C1,0xD081,0x1040,0xF001,0x30C0,0x3180,0xF141,0x3300,0xF3C1,0xF281,0x3240,0x3600,0xF6C1,0xF781,0x3740,0xF501,0x35C0,0x3480,0xF441,0x3C00,0xFCC1,0xFD81,0x3D40,0xFF01,0x3FC0,0x3E80,0xFE41,0xFA01,0x3AC0,0x3B80,0xFB41,0x3900,0xF9C1,0xF881,0x3840,0x2800,0xE8C1,0xE981,0x2940,0xEB01,0x2BC0,0x2A80,0xEA41,0xEE01,0x2EC0,0x2F80,0xEF41,0x2D00,0xEDC1,0xEC81,0x2C40,0xE401,0x24C0,0x2580,0xE541,0x2700,0xE7C1,0xE681,0x2640,0x2200,0xE2C1,0xE381,0x2340,0xE101,0x21C0,0x2080,0xE041,0xA001,0x60C0,0x6180,0xA141,0x6300,0xA3C1,0xA281,0x6240,0x6600,0xA6C1,0xA781,0x6740,0xA501,0x65C0,0x6480,0xA441,0x6C00,0xACC1,0xAD81,0x6D40,0xAF01,0x6FC0,0x6E80,0xAE41,0xAA01,0x6AC0,0x6B80,0xAB41,0x6900,0xA9C1,0xA881,0x6840,0x7800,0xB8C1,0xB981,0x7940,0xBB01,0x7BC0,0x7A80,0xBA41,0xBE01,0x7EC0,0x7F80,0xBF41,0x7D00,0xBDC1,0xBC81,0x7C40,0xB401,0x74C0,0x7580,0xB541,0x7700,0xB7C1,0xB681,0x7640,0x7200,0xB2C1,0xB381,0x7340,0xB101,0x71C0,0x7080,0xB041,0x5000,0x90C1,0x9181,0x5140,0x9301,0x53C0,0x5280,0x9241,0x9601,0x56C0,0x5780,0x9741,0x5500,0x95C1,0x9481,0x5440,0x9C01,0x5CC0,0x5D80,0x9D41,0x5F00,0x9FC1,0x9E81,0x5E40,0x5A00,0x9AC1,0x9B81,0x5B40,0x9901,0x59C0,0x5880,0x9841,0x8801,0x48C0,0x4980,0x8941,0x4B00,0x8BC1,0x8A81,0x4A40,0x4E00,0x8EC1,0x8F81,0x4F40,0x8D01,0x4DC0,0x4C80,0x8C41,0x4400,0x84C1,0x8581,0x4540,0x8701,0x47C0,0x4680,0x8641,0x8201,0x42C0,0x4380,0x8341,0x4100,0x81C1,0x8081,0x4040
};
u16 CRC16_ModBus_Table(u8 *Dat, int Len)
{u16 CRC 0xffff;u8 Zj;for (int i 0; i Len ; i){Zj (CRC 0xFF)^ Dat[i];CRC 8;CRC ^ T[Zj];}return (CRC);
}