## 介绍 数据在传输过程中可能会因为各种原因导致产生了差错,为了能够控制传输过程的差错,通信系统往往会采用数据校验来保证数据的完整性。 常见的数据校验算法就包含,求和校验、奇偶校验、异或校验、LRC校验、CRC校验,这里也给出了常用的校验算法的代码。 ## 接口 ```c uint8_t check_sum(uint8_t* data, uint32_t len); // 求和校验算法 uint8_t check_parity(uint8_t* data, uint32_t len); // 奇偶校验 uint8_t check_lrc(uint8_t* data, uint32_t len); // LRC校验 uint8_t check_xor(uint8_t* data, uint32_t len); // 异或校验 ``` 这几种校验算法使用方法一致,都是传入数据地址和数据长度,返回计算出来的校验值。 ### 通用crc ```c // 通用CRC算法 uint32_t check_crc(uint8_t* data, uint32_t len, uint8_t width, uint32_t poly, uint32_t init, uint8_t refin, uint8_t refout, uint32_t xorout); ``` 这个CRC算法是32byte以内的通用CRC算法,除了传入数据地址和数据长度,后面依次跟着CRC校验码宽度、多项式、初始值、输入翻转、输出翻转、异或输出。 这个算法和 [CRC(循环冗余校验)在线计算](http://www.ip33.com/crc.html) 的使用方法一致。 在`check_crc`随机计算个crc,与在线工具对比 ```c printf("crc 0x%X\r\n", check_crc("Hello", 5, 8, 0x5A, 0xAA, 1, 0, 0x4A)); ``` 结果都是 ``` crc 0xE0 ``` 根据常用的crc算法,可以通过`check_crc`宏定义实现 ```c /* |-------------------------------------------------------------------------------------------| |CRC name | width | poly | init | xorout | refin | refout | |-------------------------------------------------------------------------------------------| |CRC-4/ITU | 4 | 03 | 00 | 00 | true | true | |CRC-5/EPC | 5 | 9 | 09 | 00 | false | false | |CRC-5/ITU | 5 | 5 | 00 | 00 | true | true | |CRC-5/USB | 5 | 5 | 1F | 1F | true | true | |CRC-6/ITU | 6 | 3 | 00 | 00 | true | true | |CRC-7/MMC | 7 | 9 | 00 | 00 | false | false | |CRC-8 | 8 | 7 | 00 | 00 | false | false | |CRC-8/ITU | 8 | 7 | 00 | 55 | false | false | |CRC-8/ROHC | 8 | 7 | FF | 00 | true | true | |CRC-8/MAXIM | 8 | 1 | 00 | 00 | true | true | |CRC-16/IBM | 16 | 005 | 0000 | 0000 | true | true | |CRC-16/MAXIM | 16 | 005 | 0000 | FFFF | true | true | |CRC-16/USB | 16 | 005 | FFFF | FFFF | true | true | |CRC-16/MODBUS | 16 | 005 | FFFF | 0000 | true | true | |CRC-16/CCITT | 16 | 021 | 0000 | 0000 | true | true | |CRC-16/CCITT-FALSE | 16 | 021 | FFFF | 0000 | false | false | |CRC-16/X25 | 16 | 021 | FFFF | FFFF | true | true | |CRC-16/XMODEM | 16 | 021 | 0000 | 0000 | false | false | |CRC-16/DNP | 16 | D65 | 0000 | FFFF | true | true | |CRC-32 | 32 | 4C11DB7 | FFFFFFFF | FFFFFFFF | true | true | |CRC-32/MPEG-2 | 32 | 4C11DB7 | FFFFFFFF | 00000000 | false | false | |-------------------------------------------------------------------------------------------| */ #define check_crc4_itu(data, len) check_crc(data, len, 4, 0x03, 0x00, 1, 1, 0x00) #define check_crc5_epc(data, len) check_crc(data, len, 5, 0x09, 0x09, 0, 0, 0x00) #define check_crc5_usb(data, len) check_crc(data, len, 5, 0x05, 0x1F, 1, 1, 0x1F) #define check_crc6_itu(data, len) check_crc(data, len, 6, 0x03, 0x00, 1, 1, 0x00) #define check_crc7_mmc(data, len) check_crc(data, len, 7, 0x09, 0x00, 0, 0, 0x00) #define check_crc8(data, len) check_crc(data, len, 8, 0x07, 0x00, 0, 0, 0x00) #define check_crc8_itu(data, len) check_crc(data, len, 8, 0x07, 0x00, 0, 0, 0x55) #define check_crc8_rohc(data, len) check_crc(data, len, 8, 0x07, 0xFF, 1, 1, 0x00) #define check_crc8_maxim(data, len) check_crc(data, len, 8, 0x31, 0x00, 1, 1, 0x00) #define check_crc16_ibm(data, len) check_crc(data, len, 16, 0x8005, 0x0000, 1, 1, 0x0000) #define check_crc16_maxim(data, len) check_crc(data, len, 16, 0x8005, 0x0000, 1, 1, 0xFFFF) #define check_crc16_usb(data, len) check_crc(data, len, 16, 0x8005, 0xFFFF, 1, 1, 0xFFFF) #define check_crc16_modbus(data, len) check_crc(data, len, 16, 0x8005, 0xFFFF, 1, 1, 0x0000) #define check_crc16_ccitt(data, len) check_crc(data, len, 16, 0x1021, 0x0000, 1, 1, 0x0000) #define check_crc16_ccitt_false(data, len) check_crc(data, len, 16, 0x1021, 0xFFFF, 0, 0, 0x0000) #define check_crc16_x25(data, len) check_crc(data, len, 16, 0x1021, 0xFFFF, 1, 1, 0xFFFF) #define check_crc16_xmodem(data, len) check_crc(data, len, 16, 0x1021, 0x0000, 0, 0, 0x0000) #define check_crc16_dnp(data, len) check_crc(data, len, 16, 0x3D65, 0x0000, 1, 1, 0xFFFF) #define check_crc32(data, len) check_crc(data, len, 32, 0x04C11DB7, 0xFFFFFFFF, 1, 1, 0xFFFFFFFF) #define check_crc32_mpeg_2(data, len) check_crc(data, len, 32, 0x04C11DB7, 0xFFFFFFFF, 0, 0, 0x00000000) ``` ### 标准crc 如上述通用的crc也能实现标准的crc,但是运算起来效率必然有所下降,下面是根据标准crc进行的专有的实现 ```c uint8_t crc4_itu(uint8_t* data, uint32_t len); uint8_t crc5_epc(uint8_t* data, uint32_t len); uint8_t crc5_itu(uint8_t* data, uint32_t len); uint8_t crc5_usb(uint8_t* data, uint32_t len); uint8_t crc6_itu(uint8_t* data, uint32_t len); uint8_t crc7_mmc(uint8_t* data, uint32_t len); uint8_t crc8(uint8_t* data, uint32_t len); uint8_t crc8_itu(uint8_t* data, uint32_t len); uint8_t crc8_rohc(uint8_t* data, uint32_t len); uint8_t crc8_maxim(uint8_t* data, uint32_t len); uint16_t crc16_ibm(uint8_t* data, uint32_t len); uint16_t crc16_maxim(uint8_t* data, uint32_t len); uint16_t crc16_usb(uint8_t* data, uint32_t len); uint16_t crc16_modbus(uint8_t* data, uint32_t len); uint16_t crc16_ccitt(uint8_t* data, uint32_t len); uint16_t crc16_ccitt_false(uint8_t* data, uint32_t len); uint16_t crc16_x25(uint8_t* data, uint32_t len); uint16_t crc16_xmodem(uint8_t* data, uint32_t len); uint16_t crc16_dnp(uint8_t* data, uint32_t len); uint32_t crc32(uint8_t* data, uint32_t len); uint32_t crc32_mpeg_2(uint8_t* data, uint32_t len); ```