CRC 8/16/32通用算法(C 语言版)
CRC 8/16/32通用算法(C 语言版)
计算原理
略
函数接口
只需要知道所需CRC的模型,调用相应接口即可得到结果,文末附上常用CRC模型
/*** @brief 计算CRC通用算法* @param data 数据地址* @param lenth 数据长度* @param POLY 生成项的简写,以16进制表示。例如:CRC-32即是0x04C11DB7,忽略了最高位的"1",即完整的生成项是0x104C11DB7* @param INIT 这是算法开始时寄存器(crc)的初始化预置值,十六进制表示* @param XOROUT 计算结果与此参数异或后得到最终的CRC值* @param REFIN 待测数据的每个字节是否按位反转,True或False* @param REFOUT 在计算后之后,异或输出之前,整个数据是否按位反转,True或False*/
uint8_t crc8_universal(uint8_t *data, uint32_t lenth, uint8_t POLY, uint8_t INIT, \uint8_t XOROUT, bool REFIN, bool REFOUT);uint16_t crc16_universal(uint8_t *data, uint32_t lenth, uint16_t POLY, uint16_t INIT, \uint16_t XOROUT, bool REFIN, bool REFOUT);uint32_t crc32_universal(uint8_t *data, uint32_t lenth, uint32_t POLY, uint32_t INIT, \uint32_t XOROUT, bool REFIN, bool REFOUT);
接口使用示例
计算CRC16-MODBUS的模型如下
CRC算法名称 | 多项式公式 | 宽度 | 多项式 | 初始值 | 结果异或值 | 输入反转 | 输出反转 |
---|---|---|---|---|---|---|---|
CRC-16/MODBUS | x16 + x15 + x2 + 1 | 16 | 8005 | FFFF | 0000 | true | true |
接口使用方法如下
#include <stdio.h>
#include "crc_universal.h"uint16_t crc16_modbus(uint8_t *data, uint32_t lenth)
{return crc16_universal(data, lenth, 0x8005, 0xFFFF, 0x0000, true, true);
}int main(int argc, char const *argv[])
{uint8_t data[] = {0x56, 0x76, 0x88};uint16_t crc16;crc16 = crc16_modbus(data, 3);printf("crc = %04X\r\n", crc16);return 0;
}// 输出crc = D6B7
与网上提供的工具计算结果相同
源码
crc_universal.h
#ifndef __CRC_UNIVERSAL__
#define __CRC_UNIVERSAL__#include <stdint.h>
#include <stdbool.h>/*** @brief 计算CRC通用算法* @param data 数据地址* @param lenth 数据长度* @param POLY 生成项的简写,以16进制表示。例如:CRC-32即是0x04C11DB7,忽略了最高位的"1",即完整的生成项是0x104C11DB7* @param INIT 这是算法开始时寄存器(crc)的初始化预置值,十六进制表示* @param XOROUT 计算结果与此参数异或后得到最终的CRC值* @param REFIN 待测数据的每个字节是否按位反转,True或False* @param REFOUT 在计算后之后,异或输出之前,整个数据是否按位反转,True或False*/
uint8_t crc8_universal(uint8_t *data, uint32_t lenth, uint8_t POLY, uint8_t INIT, \uint8_t XOROUT, bool REFIN, bool REFOUT);uint16_t crc16_universal(uint8_t *data, uint32_t lenth, uint16_t POLY, uint16_t INIT, \uint16_t XOROUT, bool REFIN, bool REFOUT);uint32_t crc32_universal(uint8_t *data, uint32_t lenth, uint32_t POLY, uint32_t INIT, \uint32_t XOROUT, bool REFIN, bool REFOUT);#endif
crc_universal.c
#include "crc_universal.h"/*** @brief 字节按位逆序 1100 0101 -> 1010 0011*/
static uint8_t bit8_reverse(uint8_t x)
{x = ((x >> 1) & 0x55) | ((x & 0x55) << 1); x = ((x >> 2) & 0x33) | ((x & 0x33) << 2);return ( x >> 4) | (x << 4);
}static uint16_t bit16_reverse(uint16_t x)
{x = ((x >> 1) & 0x5555) | ((x & 0x5555) << 1); x = ((x >> 2) & 0x3333) | ((x & 0x3333) << 2);x = ((x >> 4) & 0x0f0f) | ((x & 0x0f0f) << 4); return((x >> 8) | (x << 8));
}static uint32_t bit32_reverse(uint32_t x)
{x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1));x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2));x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4));x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8));return((x >> 16) | (x << 16));
}uint8_t crc8_universal(uint8_t *data, uint32_t lenth, uint8_t POLY, uint8_t INIT, \uint8_t XOROUT, bool REFIN, bool REFOUT)
{uint8_t i, new_data;uint8_t crc;crc = INIT;for (; lenth> 0; lenth--){new_data = REFIN? bit8_reverse(*(data++)) : (*(data++));crc = crc ^ (new_data);for (i = 0; i < 8; i++) {if (crc & 0x80) crc = (crc << 1) ^ POLY; else crc <<= 1; }}crc = REFOUT? bit8_reverse(crc) : crc;crc ^= XOROUT;return(crc);
}uint16_t crc16_universal(uint8_t *data, uint32_t lenth, uint16_t POLY, uint16_t INIT, \uint16_t XOROUT, bool REFIN, bool REFOUT)
{uint8_t i, new_data;uint16_t crc;crc = INIT;for (; lenth> 0; lenth--){new_data = REFIN? bit8_reverse(*(data++)) : (*(data++));crc = crc ^ (new_data << 8);for (i = 0; i < 8; i++) {if (crc & 0x8000) crc = (crc << 1) ^ POLY; else crc <<= 1; }}crc = REFOUT? bit16_reverse(crc) : crc;crc ^= XOROUT;return(crc);
}uint32_t crc32_universal(uint8_t *data, uint32_t lenth, uint32_t POLY, uint32_t INIT, \uint32_t XOROUT, bool REFIN, bool REFOUT)
{uint8_t i, new_data;uint32_t crc;crc = INIT;for (; lenth> 0; lenth--){new_data = REFIN? bit8_reverse(*(data++)) : (*(data++));crc = crc ^ (new_data << 24);for (i = 0; i < 8; i++) {if (crc & 0x80000000) crc = (crc << 1) ^ POLY; else crc <<= 1; }}crc = REFOUT? bit32_reverse(crc) : crc;crc ^= XOROUT;return(crc);
}
常用CRC模型
CRC算法名称 | 多项式公式 | 宽度 | 多项式 | 初始值 | 结果异或值 | 输入反转 | 输出反转 |
---|---|---|---|---|---|---|---|
CRC-4/ITU | x4 + x + 1 | 4 | 03 | 00 | 00 | true | true |
CRC-5/EPC | x5 + x3 + 1 | 5 | 09 | 09 | 00 | false | false |
CRC-5/ITU | x5 + x4 + x2 + 1 | 5 | 15 | 00 | 00 | true | true |
CRC-5/USB | x5 + x2 + 1 | 5 | 05 | 1F | 1F | true | true |
CRC-6/ITU | x6 + x + 1 | 6 | 03 | 00 | 00 | true | true |
CRC-7/MMC | x7 + x3 + 1 | 7 | 09 | 00 | 00 | false | false |
CRC-8 | x8 + x2 + x + 1 | 8 | 07 | 00 | 00 | false | false |
CRC-8/ITU | x8 + x2 + x + 1 | 8 | 07 | 00 | 55 | false | false |
CRC-8/ROHC | x8 + x2 + x + 1 | 8 | 07 | FF | 00 | true | true |
CRC-8/MAXIM | x8 + x5 + x4 + 1 | 8 | 31 | 00 | 00 | true | true |
CRC-16/IBM | x16 + x15 + x2 + 1 | 16 | 8005 | 0000 | 0000 | true | true |
CRC-16/MAXIM | x16 + x15 + x2 + 1 | 16 | 8005 | 0000 | FFFF | true | true |
CRC-16/USB | x16 + x15 + x2 + 1 | 16 | 8005 | FFFF | FFFF | true | true |
CRC-16/MODBUS | x16 + x15 + x2 + 1 | 16 | 8005 | FFFF | 0000 | true | true |
CRC-16/CCITT | x16 + x12 + x5 + 1 | 16 | 1021 | 0000 | 0000 | true | true |
CRC-16/CCITT-FALSE | x16 + x12 + x5 + 1 | 16 | 1021 | FFFF | 0000 | false | false |
CRC-16/X25 | x16 + x12 + x5 + 1 | 16 | 1021 | FFFF | FFFF | true | true |
CRC-16/XMODEM | x16 + x12 + x5 + 1 | 16 | 1021 | 0000 | 0000 | false | false |
CRC-16/DNP | x16 + x13 + x12 + x11 + x10 + x8 + x6 + x5 + x2 + 1 | 16 | 3D65 | 0000 | FFFF | true | true |
CRC-32 | x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 1 | 32 | 04C11DB7 | FFFFFFFF | FFFFFFFF | true | true |
CRC-32/MPEG-2 | x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 1 | 32 | 04C11DB7 | FFFFFFFF | 00000000 | false | false |