主内容,转载的。
原文链接:https://blog.youkuaiyun.com/m0_37105371/article/details/89363473
CRC16的算法原理:
1、根据CRC16的标准选择初值CRCLn的值。
2、将数据的第一个字节与CRCLn的高8位异或。
3、判断最高位,若该位为0,左移1位,若为1左移一位再与多项式Hex码异或。
4、重复3直至8个位全部移位计算结束。
5、重复将所有输入数据操作完成以上步骤,所得的16位数即为16位CRC校验码。
常见的几组CRC公式:
1、CRC16/IBM 或 CRC16/ARC 或 CRC16/LHA:
公式:x16+x15+x2+1
宽度:16
Poly值:0x8005
初始值:0x0000
基准输入:true
基准输出:true
标志位:0x0000
2、CRC16/MAXIM:
公式:x16+x15+x2+1
宽度:16
Poly值:0x8005
初始值:0x0000
基准输入:true
基准输出:true
标志位:0xFFFF
3、CRC16/USB:
公式:x16+x15+x2+1
宽度:16
Poly值:0x8005
初始值:0xFFFF
基准输入:true
基准输出:true
标志位:0xFFFF
4、CRC16/MODBUS(最常见):
公式:x16+x15+x2+1
宽度:16
Poly值:0x8005
初始值:0x0000
基准输入:true
基准输出:true
标志位:0x0000
5、CRC16/CCITT 或 CRC-CCITT 或CRC16/CCITT-TRUE或 CRC16/KERMIT:
公式:x16+x15+x5+1
宽度:16
Poly值:0x1021
初始值:0x0000
基准输入:true
基准输出:true
标志位:0x0000
6、 CRC16/CCITT-FALSE:
公式:x16+x15+x5+1
宽度:16
Poly值:0x1021
初始值:0xFFFF
基准输入:false
基准输出:false
标志位:0x0000
7、CRC16/X25:
公式:x16+x15+x5+1
宽度:16
Poly值:0x1021
初始值:0x0000
基准输入:true
基准输出:true
标志位:0xFFFF
8、CRC16/XMODEM 或 CRC16/ZMODEM 或 CRC16/ACORN:
公式:x16+x15+x5+1
宽度:16
Poly值:0x1021
初始值:0x0000
基准输入:false
基准输出:false
标志位:0x0000
9、CRC16/DNP:
公式:x16+x13+x12+x11+x10+x8+x6+x5+x2+1
宽度:16
Poly值:0x3D65
初始值:0x0000
基准输入:true
基准输出:true
标志位:0xFFFF
使用:M-Bus, ect
关于数据位序:如果我们的机器是小端模式(低位在后,高位在前),而数据输入的要求是低位在前高位在后时,就需要对数据顺序进行反转。
多项式的值是如果计算的:
以多项式:x16 + x12 + x5 + 1 为例
x16表示第16位为1,x12表示第12位为1,x5表示第5位为1
(1<<16) | (1<<12) | (1<<5) | 1 = 1 0001 000 0010 0001 = 0x1 1021
CRC16只取上面计算值的低16位所以最终结果为0x1021。
然后按上面及查的资料,测试了下面的代码,验证成功。
#include <iostream>
unsigned char test[5] = { 0x40,0x00,0x01,0x30, };//0x4414 校验码
unsigned char len = 5;
unsigned long crc_code = 0x18005;
unsigned long crc_hignbit = 0x10000;
int main()
{
unsigned long temp = 0;
unsigned int crc;
unsigned char i;
unsigned char* ptr = test;
unsigned char len_temp = len;
while (len_temp--) {
for (i = 0x80; i != 0; i = i >> 1) {
temp = temp * 2;
if ((temp & crc_hignbit) != 0)
temp = temp ^ crc_code;
if ((*ptr & i) != 0)
temp = temp ^ (crc_hignbit ^ crc_code);
}
ptr++;
}
crc = temp;
printf("crc为: 0x%x ", crc);
}
测试工具: