简介
在数据储存或者数据传输过程经常需要对数据进行校验,以确保数据的准确性。本文介绍一些常用的CRC校验算法
和校验、异或校验
- 这两种校验方式在短数据传输过程应该是最常见的,实现过程很简单,这里不做过多的介绍
多项式与POLY
- CRC算法中必然会提到多项式,比如多项式“x8+x2+x+1”,即第8、2、1、0,bit为1。而POLY(生成项)计算中,最高位不参与,所以此多项式的POLY为0x07。
- 又如CRC-16-MODBUS,它的多项式为x16 + x15 + x2 + 1,所以此多项式的POLY为0x8005
CRC
- 实现CRC8,即实现了CRC4、CRC5、CRC6、CRC7以及CRC8-ITU、CRC8-ROHC等,不同的是它们的初值、多项式以及数据是否反转之间的配置不一样罢了,或者最终计算的结果异或某个值而已
- 同理实现CRC16,CRC32,即可实现大部分CRC算法的需求
算法
数据反转
/**
* @brief 数据反转(高低位调换的意思,将数据最高位调到最低位,次高位调到次低位)
* @note
* @param data:数据
* bitLen:数据位数
* @retval Reverse Result
*
*/
unsigned int Reverse(unsigned int data, unsigned char bitLen)
{
unsigned int i;
unsigned int buf=0;
for (i = 0; i<bitLen; i++) {
buf <<= 1;
if (data & 0x01) {
buf |= 1;
}
data >>= 1;
}
return buf;
}
CRC8算法
/**
* @brief CRC8 Calculate
* @note
* @param crcInit: CRC初始值
* poly: CRC多项式
* BlockStart: 数据段
* BlockLength: 数据长度(需要计算的长度)
* inRev: 输入数据是否反转 0:不反转 1:反转
* outRev: 输出数据是否反转 0:不反转 1:反转
* @retval CRC8 Calculate Result
*
*/
unsigned char CRC8(unsigned char crcInit, unsigned char poly, unsigned char *BlockStart, unsigned char BlockLength, unsigned char inRev, unsigned char outRev)
{
unsigned int i, j;
unsigned char CRC_VAL = crcInit;
unsigned char buf;
for (j = 0; j<BlockLength; j++) {
buf = *(BlockStart + j);
if (inRev != 0) {
buf = Reverse(buf,8);
}
CRC_VAL ^= buf;
for (i = 0; i<8; i++) {
if (CRC_VAL & 0x80) {
CRC_VAL = (CRC_VAL << 1) ^ poly;
}
else {
CRC_VAL <<= 1;
}
}
}
if (outRev != 0) {
CRC_VAL = Reverse(CRC_VAL,8);
}
return CRC_VAL & 0xFF;
}
CRC16算法
/**
* @brief CRC16 Calculate
* @note
* @param crcInit: CRC初始值
* poly: CRC多项式
* BlockStart: 数据段
* BlockLength: 数据长度(需要计算的长度)
* inRev: 输入数据是否反转 0:不反转 1:反转
* outRev: 输出数据是否反转 0:不反转 1:反转
* @retval CRC16 Calculate Result
*
*/
unsigned short CRC16(unsigned short crcInit, unsigned short poly, unsigned char *BlockStart, unsigned char BlockLength, unsigned char inRev, unsigned char outRev)
{
unsigned int i, j;
unsigned short CRC_VAL = crcInit;
unsigned char buf;
for (j = 0; j<BlockLength; j++) {
buf = *(BlockStart + j);
if (inRev != 0) {
buf = Reverse(buf,8);
}
CRC_VAL ^= ((unsigned short)buf << 8);
for (i = 0; i<8; i++) {
if (CRC_VAL & 0x8000) {
CRC_VAL = (CRC_VAL << 1) ^ poly;
}
else {
CRC_VAL <<= 1;
}
}
}
if (outRev != 0) {
CRC_VAL = Reverse(CRC_VAL,16);
}
return CRC_VAL & 0xFFFF;
}
CRC32算法
/**
* @brief CRC32 Calculate
* @note
* @param crcInit: CRC初始值
* poly: CRC多项式
* BlockStart: 数据段
* BlockLength: 数据长度(需要计算的长度)
* inRev: 输入数据是否反转 0:不反转 1:反转
* outRev: 输出数据是否反转 0:不反转 1:反转
* @retval CRC32 Calculate Result
*
*/
unsigned int CRC32(unsigned int crcInit, unsigned int poly, unsigned char *BlockStart, unsigned char BlockLength, unsigned char inRev, unsigned char outRev)
{
unsigned int i, j;
unsigned int CRC_VAL = crcInit;
unsigned char buf;
for (j = 0; j<BlockLength; j++) {
buf = *(BlockStart + j);
if (inRev != 0) {
buf = Reverse(buf, 8);
}
CRC_VAL ^= ((unsigned int)buf << 24);
for (i = 0; i<8; i++) {
if (CRC_VAL & 0x80000000) {
CRC_VAL = (CRC_VAL << 1) ^ poly;
}
else {
CRC_VAL <<= 1;
}
}
}
if (outRev != 0) {
CRC_VAL = Reverse(CRC_VAL, 32);
}
return CRC_VAL & 0xFFFFFFFF;
}
测试代码与输出
int main(void)
{
unsigned char test[] = { 0x01,0x03,0x00,0x00,0x00,0x01 };
unsigned char crc8_result=0;
unsigned short crc16_result=0;
unsigned int crc32_result = 0;
//CRC8
crc8_result = CRC8(0x00, 0x07, test, sizeof(test), 0, 0);
//CRC16 MODBUS
crc16_result = CRC16(0xFFFF, 0x8005, test, sizeof(test), 1, 1);
//CRC-32/MPEG-2
crc32_result = CRC32(0xFFFFFFFF,0x04C11DB7, test, sizeof(test), 0, 0);
printf("CRC8 result = 0x%02X\r\n", crc8_result);
printf("CRC16 result = 0x%04X\r\n", crc16_result);
printf("CRC32 result = 0x%08X\r\n", crc32_result);
while (1);
return 0;
}
输出
CRC8 result = 0x88
CRC16 result = 0x0A84
CRC32 result = 0xFE84042A
常见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 |
版权声明:本文为WaliTool原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。