绪论 本文意在简单通俗的对CRC16的计算及编程进行讲解有错误的地方欢迎大家评论区指出不胜感激。一、计算概念的简要介绍下图为CRC在线计算根据图示首先介绍计算基本的概念。1、数据宽度数据宽度指的就是CRC校验码的长度二进制位数其长度与简记式长度一致。记为R如8位16位。2、多项式POLY多项式简记式多项式作为CRC校验的除数其公式例如G(x) x^16 x^15 x^2 1即除数为0x18005手动计算时使用。即得多项式简记式为0x8005程序使用。3、初始值在一些标准中规定了初始值需要先将要计算的数据与初始值的最低字节进行异或然后再与多项式进行计算。4、输出异或值XOROUT将计算得到的CRC结果值再与结果异或值进行一次异或计算得到的最终值才是我们需要的CRC校验码。选择使用5、输入数据反转、输出数据反转输入值反转的意思是在计算之前先将二项式反转然后再用得到的新值和数据进行计算。如对于G(X)X16X15X2116#18005其正向值为1 1000 0000 0000 0101反转值则为1010 0000 0000 0001 1。输出值反转则是将最终得到的CRC结果反转。选择使用CRC在线计算操作界面二、CRC16计算下面以数据流0x12 0x34为例进行CRC16计算。2.1、手动计算2.1.1直接计算法① 0x12 CRC计算0 0 0 1 0 0 1 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00x12)除数1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1余数 1 0 1 0 0 0 0 0 0 0 0 0 0 1 0 10除数1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1余数 1 1 0 0 0 0 0 0 0 0 0 0 1 1 1 10除数1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1余数校验码 1 1 0 1 10 00x006C② 0x12 0x34 CRC计算0 0 0 0 0 0 0 00 1 1 0 1 1 0 00x006C0 0 1 1 0 1 0 00 0 0 0 0 0 0 00x34 80 0 1 1 0 1 0 0 0 1 1 0 1 1 0 00 0 0 0 0 0 0 0异或结果除1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1余数 1 0 00 1 1 0 1 1 0 01 0 10 0 0除数1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1余数 100 1 1 0 1 1 0 01 0 1 1 0 10除数1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1余数10 1 1 0 1 1 0 01 0 1 1 1 1 10除数1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1余校验码1 1 1 0 1 1 0 01 0 1 1 1 0 1 10xECBB2.1.2查表计算法① 0x12 CRC计算0 0 0 1 0 0 1 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00x12)除数1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1余数 1 0 1 0 0 0 0 0 0 0 0 0 0 1 0 10除数1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1余数 1 1 0 0 0 0 0 0 0 0 0 0 1 1 1 10除数1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1余数校验码 1 1 0 1 10 00x006C② 0x34 CRC计算0 0 1 1 0 1 0 00 0 0 0 0 0 0 00 0 1 1 0 1 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0除1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1余数 1 0 00 0 0 0 0 0 0 01 0 10 0 0除数1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1余数 1 00 0 0 0 0 0 0 01 0 1 1 0 10除数1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1余数 10 0 0 0 0 0 0 01 0 1 1 1 1 10除数1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1余数(校验码)1 0 0 0 0 0 0 01 0 1 1 1 0 1 10x80BB③ 0x12 0x34 CRC查表计算1 0 0 0 0 0 0 0 1 0 1 1 1 0 1 10x80BB0 1 1 0 1 1 0 00 0 0 0 0 0 0 00x006C 81 1 1 0 1 1 0 0 1 0 1 1 1 0 1 1 校验码0xECBB异或2.1.3 查表法计算推论对比查表法与直接计算法可知查表法计算结果与直接计算法的结果一致但两个的计算步骤有差别。直接计算法的公式可表达为crc_new [(crc_old ^ (B 8)) 8] mod POLY查表法的公式可表达为crc_new (crc_old 8) ^ table[(crc_old 8) ^ B]注B表示字节数据mod POLY表示CRC16计算table[]表示查表直接计算法是按照CRC原理步骤进行移位计算的方法。查表法在计算步骤上进行了调整具体的步骤可描述为a、(crc_old 8)^B计算影响余数的高8位b、table[...]查表得到对应的余数。c、(crc_old 8)保留低8位并移位。d、^将余数与移位后的值组合。对于查表法计算方法的改变我们需要知道CRC的计算本质是多项式除法而每次处理一个字节时只有当前CRC的高8位会进入被除数的高位从而影响模2除法的余数。低8位在本次计算中只是左移不会直接影响余数计算它们会在后续字节处理时逐步影响。对于这两点的理解可以通过上面实例中两种算法标黄部分进行对比即可知道具体的论证请自行查找此处不予讨论。2.2、直接计算法程序uint16 crc16(uint8 *addr, uint16 num) { uint16 crc 0x0000; int i; for (; num 0; num--) /* 1 个1个字节的读取数据 */ { crc crc ^ (*addr 8); /* 从数据中读取一个字节左移8位后与16位的CRC异或*/ for (i 0; i 8; i) /*对每一字节的数模2运算进行8次*/ { if (crc 0x8000) crc (crc 1) ^ 0x8005; else crc 1; } crc 0xFFFF; } return(crc); }2.3、查表法代码// 初始化CRC表 void init_crc16_table() { unsigned short poly 0x8005; int i 0; int j 0; for (i 0; i 256; i) { unsigned short crc i 8; for (j 0; j 8; j) { if (crc 0x8000) crc (crc 1) ^ poly; else crc 1; } crc16_table[i] crc; } } // 计算CRC unsigned short calculate_crc16(unsigned char *data, int length) { unsigned short crc 0x0000; // 初始值 int i 0; for (i 0; i length; i) { crc (crc 8) ^ crc16_table[((crc 8) ^ data[i]) 0xFF]; } return crc; // 最终异或值 }2.4、计算验证通过在线CRC计算对0x12 0x34进行CRC16计算计算结果与手动计算一致。
CRC16校验
绪论 本文意在简单通俗的对CRC16的计算及编程进行讲解有错误的地方欢迎大家评论区指出不胜感激。一、计算概念的简要介绍下图为CRC在线计算根据图示首先介绍计算基本的概念。1、数据宽度数据宽度指的就是CRC校验码的长度二进制位数其长度与简记式长度一致。记为R如8位16位。2、多项式POLY多项式简记式多项式作为CRC校验的除数其公式例如G(x) x^16 x^15 x^2 1即除数为0x18005手动计算时使用。即得多项式简记式为0x8005程序使用。3、初始值在一些标准中规定了初始值需要先将要计算的数据与初始值的最低字节进行异或然后再与多项式进行计算。4、输出异或值XOROUT将计算得到的CRC结果值再与结果异或值进行一次异或计算得到的最终值才是我们需要的CRC校验码。选择使用5、输入数据反转、输出数据反转输入值反转的意思是在计算之前先将二项式反转然后再用得到的新值和数据进行计算。如对于G(X)X16X15X2116#18005其正向值为1 1000 0000 0000 0101反转值则为1010 0000 0000 0001 1。输出值反转则是将最终得到的CRC结果反转。选择使用CRC在线计算操作界面二、CRC16计算下面以数据流0x12 0x34为例进行CRC16计算。2.1、手动计算2.1.1直接计算法① 0x12 CRC计算0 0 0 1 0 0 1 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00x12)除数1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1余数 1 0 1 0 0 0 0 0 0 0 0 0 0 1 0 10除数1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1余数 1 1 0 0 0 0 0 0 0 0 0 0 1 1 1 10除数1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1余数校验码 1 1 0 1 10 00x006C② 0x12 0x34 CRC计算0 0 0 0 0 0 0 00 1 1 0 1 1 0 00x006C0 0 1 1 0 1 0 00 0 0 0 0 0 0 00x34 80 0 1 1 0 1 0 0 0 1 1 0 1 1 0 00 0 0 0 0 0 0 0异或结果除1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1余数 1 0 00 1 1 0 1 1 0 01 0 10 0 0除数1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1余数 100 1 1 0 1 1 0 01 0 1 1 0 10除数1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1余数10 1 1 0 1 1 0 01 0 1 1 1 1 10除数1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1余校验码1 1 1 0 1 1 0 01 0 1 1 1 0 1 10xECBB2.1.2查表计算法① 0x12 CRC计算0 0 0 1 0 0 1 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00x12)除数1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1余数 1 0 1 0 0 0 0 0 0 0 0 0 0 1 0 10除数1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1余数 1 1 0 0 0 0 0 0 0 0 0 0 1 1 1 10除数1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1余数校验码 1 1 0 1 10 00x006C② 0x34 CRC计算0 0 1 1 0 1 0 00 0 0 0 0 0 0 00 0 1 1 0 1 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0除1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1余数 1 0 00 0 0 0 0 0 0 01 0 10 0 0除数1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1余数 1 00 0 0 0 0 0 0 01 0 1 1 0 10除数1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1余数 10 0 0 0 0 0 0 01 0 1 1 1 1 10除数1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1余数(校验码)1 0 0 0 0 0 0 01 0 1 1 1 0 1 10x80BB③ 0x12 0x34 CRC查表计算1 0 0 0 0 0 0 0 1 0 1 1 1 0 1 10x80BB0 1 1 0 1 1 0 00 0 0 0 0 0 0 00x006C 81 1 1 0 1 1 0 0 1 0 1 1 1 0 1 1 校验码0xECBB异或2.1.3 查表法计算推论对比查表法与直接计算法可知查表法计算结果与直接计算法的结果一致但两个的计算步骤有差别。直接计算法的公式可表达为crc_new [(crc_old ^ (B 8)) 8] mod POLY查表法的公式可表达为crc_new (crc_old 8) ^ table[(crc_old 8) ^ B]注B表示字节数据mod POLY表示CRC16计算table[]表示查表直接计算法是按照CRC原理步骤进行移位计算的方法。查表法在计算步骤上进行了调整具体的步骤可描述为a、(crc_old 8)^B计算影响余数的高8位b、table[...]查表得到对应的余数。c、(crc_old 8)保留低8位并移位。d、^将余数与移位后的值组合。对于查表法计算方法的改变我们需要知道CRC的计算本质是多项式除法而每次处理一个字节时只有当前CRC的高8位会进入被除数的高位从而影响模2除法的余数。低8位在本次计算中只是左移不会直接影响余数计算它们会在后续字节处理时逐步影响。对于这两点的理解可以通过上面实例中两种算法标黄部分进行对比即可知道具体的论证请自行查找此处不予讨论。2.2、直接计算法程序uint16 crc16(uint8 *addr, uint16 num) { uint16 crc 0x0000; int i; for (; num 0; num--) /* 1 个1个字节的读取数据 */ { crc crc ^ (*addr 8); /* 从数据中读取一个字节左移8位后与16位的CRC异或*/ for (i 0; i 8; i) /*对每一字节的数模2运算进行8次*/ { if (crc 0x8000) crc (crc 1) ^ 0x8005; else crc 1; } crc 0xFFFF; } return(crc); }2.3、查表法代码// 初始化CRC表 void init_crc16_table() { unsigned short poly 0x8005; int i 0; int j 0; for (i 0; i 256; i) { unsigned short crc i 8; for (j 0; j 8; j) { if (crc 0x8000) crc (crc 1) ^ poly; else crc 1; } crc16_table[i] crc; } } // 计算CRC unsigned short calculate_crc16(unsigned char *data, int length) { unsigned short crc 0x0000; // 初始值 int i 0; for (i 0; i length; i) { crc (crc 8) ^ crc16_table[((crc 8) ^ data[i]) 0xFF]; } return crc; // 最终异或值 }2.4、计算验证通过在线CRC计算对0x12 0x34进行CRC16计算计算结果与手动计算一致。