ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

CRC8检验算法(C语言实现)

CRC8检验算法(C语言实现) 本文仅用于本人学习记录参考摘录了以下大佬的文章CRC8算法_算法_简单的过客-GitCode 开源社区 (csdn.net)CRC算法原理、推导及实现 - QIYUEXIN - 博客园 (cnblogs.com)本文实现的是width8, poly0x31, init0x00, refinfalse, refoutfalse, xorout0x00 的 MSB-first CRC-8 实现。目录1.CRC-8 常用生成多项式2.CRC校验算法3.算法推导3.1 仿人算方法4.直接计算法5.查表法1.CRC-8 常用生成多项式CRC-8 x8x5x41 0x310x131 CRC-8 x8x2x11 0x070x107 CRC-8 x8x6x4x3x2x1 0x5E0x15E注“CRC-8”不是单一标准除了多项式还要指定init、refin、refout、xorout。不同参数组合会得到不同的 CRC 结果实际使用时应以协议文档为准。代码中记录的poly通常省略最高项x^8例如0x31表示完整生成多项式x^8 x^5 x^4 1。最高项并非“不参与运算”而是在移位反馈实现中被隐式处理。2.CRC校验算法CRC 本质是在 GF(2) 上对消息多项式进行模生成多项式除法加减法等价于 XOR。实现中的 MSB-first 与 LSB-first 是不同的位序/反射方式必须与协议规定的refin、refout、初值和最终异或一起确定。对于MSB:XOR从数据的高位开始,暂时定义为顺序异或对于LSB:XOR从数据的低位开始,暂时定义为反序异或两种不同的异或方式仅有相同poly不足以保证结果一致init、refin、refout和xorout任一不同都可能得到不同 CRC。3.算法推导CRC的算法是基于除法但不能直接使用除法运算由于待校验的数据可能会很长而MCU可能并没有这么大的寄存器3.1 仿人算方法现在我们假设一个消息数据为1101011011选取除数为10011使用CRC算法将消息除以poly1100001010 Quotient (nobody cares about the quotient) _______________ 10011 ) 11010110110000 Augmented message (1101011011 0000) Poly 10011,,.,,..|. -----,,.,,|... 10011,.,,|.|. 10011,.,,|... -----,.,,|.|. 10110... 10011.|. -----... 010100. 10011. -----. 01110 00000 ----- 1110 Remainder THE CHECKSUM!!!!在数学表示中生成多项式包含最高项。例如0x131表示x^8x^5x^41。在 8 位左移反馈实现中代码仅保存低 8 位反馈常量0x31当寄存器最高位移出时代码通过与0x31异或来隐式完成最高项对应的反馈。因此MSB-first 实现每处理一位先判断当前 CRC 的最高位若为 1左移后再与0x31异或若为 0则只左移。这样无需保存完整的 9 位多项式。转换成算法的思路就是你也可以理解成一长串的数据不断的从右边移位到寄存器中当寄存器最左边溢出的数值是1的时候那么当前寄存器的数据就可以和poly异或运算了用算法表示大概是这样3 2 1 0 Bits ------------ Pop! -- | | | | | ----- Augmented message ------------ 1 0 0 1 1 The Poly4.直接计算法typedef unsigned char uint8_t; typedef unsigned short int uint16_t; #define CRC8_POLYNOMIAL 0x31 /*计算多个字节CRC8校验值的函数*/ uint8_t cal_bytes_crc8(uint8_t *data, uint8_t len){ uint8_t crc8 0x00; /* 计算的初始crc值 */ uint8_t i ; while(len--){ crc8 ^ *data; /* 每次先与需要计算的数据异或,计算完指向下一数据 */ for (i 8; i 0; --i) { /* 下面这段计算过程与计算一个字节crc一样 */ crc8 ( crc8 0x80 ) ? (crc8 1) ^ CRC8_POLYNOMIAL : (crc8 1); } } return crc8 ; }上面的crc计算是纯采用逻辑运行的方式可以看到需要的运行量也是不少的每一个字节都需要进行8次判断、移位、或异或操作。可以采用查表法大大减少计算量先计算0x00~0xFF每一个字节的crc校验结果后面就可以通过表来查出每个字节的crc结果大大减少计算量。5.查表法uint8_t cal_table_high_first(uint8_t value) { uint8_t i, crc0x00; crc value; /* 数据往左移了8位需要计算8次 */ for (i8; i0; --i){ crc ( crc 0x80 ) /* 判断最高位是否为1 */ /* 最高位为1不需要异或往左移一位然后与0x31异或 */ /* 0x31(多项式x8x5x41100110001)最高位不需要异或直接去掉 */ ? (crc 1) ^ CRC8_POLYNOMIAL /* 最高位为0时不需要异或整体数据往左移一位 */ : (crc 1); } return crc; } // 下面是一个表生成程序: void create_crc_table(void) { uint16_t i; uint8_t j; for (i0; i0xFF; i) { if (0 (i%16)) printf(\n); j i0xFF; printf(0x%.2x, , cal_table_high_first (j)); /*依次计算每个字节的crc校验值*/ } } // 按照多项式 x^8 x^5 x^4 1poly0x31生成。 static const unsigned int crc8_table[256] { 0x00, 0x31, 0x62, 0x53, 0xc4, 0xf5, 0xa6, 0x97, 0xb9, 0x88, 0xdb, 0xea, 0x7d, 0x4c, 0x1f, 0x2e, 0x43, 0x72, 0x21, 0x10, 0x87, 0xb6, 0xe5, 0xd4, 0xfa, 0xcb, 0x98, 0xa9, 0x3e, 0x0f, 0x5c, 0x6d, 0x86, 0xb7, 0xe4, 0xd5, 0x42, 0x73, 0x20, 0x11, 0x3f, 0x0e, 0x5d, 0x6c, 0xfb, 0xca, 0x99, 0xa8, 0xc5, 0xf4, 0xa7, 0x96, 0x01, 0x30, 0x63, 0x52, 0x7c, 0x4d, 0x1e, 0x2f, 0xb8, 0x89, 0xda, 0xeb, 0x3d, 0x0c, 0x5f, 0x6e, 0xf9, 0xc8, 0x9b, 0xaa, 0x84, 0xb5, 0xe6, 0xd7, 0x40, 0x71, 0x22, 0x13, 0x7e, 0x4f, 0x1c, 0x2d, 0xba, 0x8b, 0xd8, 0xe9, 0xc7, 0xf6, 0xa5, 0x94, 0x03, 0x32, 0x61, 0x50, 0xbb, 0x8a, 0xd9, 0xe8, 0x7f, 0x4e, 0x1d, 0x2c, 0x02, 0x33, 0x60, 0x51, 0xc6, 0xf7, 0xa4, 0x95, 0xf8, 0xc9, 0x9a, 0xab, 0x3c, 0x0d, 0x5e, 0x6f, 0x41, 0x70, 0x23, 0x12, 0x85, 0xb4, 0xe7, 0xd6, 0x7a, 0x4b, 0x18, 0x29, 0xbe, 0x8f, 0xdc, 0xed, 0xc3, 0xf2, 0xa1, 0x90, 0x07, 0x36, 0x65, 0x54, 0x39, 0x08, 0x5b, 0x6a, 0xfd, 0xcc, 0x9f, 0xae, 0x80, 0xb1, 0xe2, 0xd3, 0x44, 0x75, 0x26, 0x17, 0xfc, 0xcd, 0x9e, 0xaf, 0x38, 0x09, 0x5a, 0x6b, 0x45, 0x74, 0x27, 0x16, 0x81, 0xb0, 0xe3, 0xd2, 0xbf, 0x8e, 0xdd, 0xec, 0x7b, 0x4a, 0x19, 0x28, 0x06, 0x37, 0x64, 0x55, 0xc2, 0xf3, 0xa0, 0x91, 0x47, 0x76, 0x25, 0x14, 0x83, 0xb2, 0xe1, 0xd0, 0xfe, 0xcf, 0x9c, 0xad, 0x3a, 0x0b, 0x58, 0x69, 0x04, 0x35, 0x66, 0x57, 0xc0, 0xf1, 0xa2, 0x93, 0xbd, 0x8c, 0xdf, 0xee, 0x79, 0x48, 0x1b, 0x2a, 0xc1, 0xf0, 0xa3, 0x92, 0x05, 0x34, 0x67, 0x56, 0x78, 0x49, 0x1a, 0x2b, 0xbc, 0x8d, 0xde, 0xef, 0x82, 0xb3, 0xe0, 0xd1, 0x46, 0x77, 0x24, 0x15, 0x3b, 0x0a, 0x59, 0x68, 0xff, 0xce, 0x9d, 0xac }; //采用查表法计算crc代码如下: uint8_t cal_crc_table(uint8_t *data, uint8_t len){ uint8_t crc8 0x00; while (len --){ crc8 crc8_table[crc8 ^ *data]; } return crc8 ; }
返回列表