📄 crc.c
字号:
/* 一些见于标准的CRC:
CRC-4 x^4 + x + 1
CRC-12 X^12 + X^11 + X^3 + X + 1
CRC-16 X^16 + X^12 + X^2 + 1
CRC-32 X^32 + X^26 +X^15 + .... + 1
...
CRC 可以由除法电路的主体由一组移位寄存器和模2加法器(异或单元)组成(本例子由16级移位寄存器和3个加法器组成)
CRC除法电路,完全可以用软件来模拟
定义一个寄存器组,初始化为全"1"。每输入一个信息位,相当于一个时钟脉冲到来,从高到低依次移位。移位前
信息位与bit0相加产生临时位,其中bit15移入临时位,bit10、bit3还要加上临时位。当全部信息位输入完成后,
从寄存器组取出它们的值,这就是CRC码。
*/
typedef union _UNION_CRCREGS
{
INT16U crcValue;
struct
{
INT16U bit0 : 1;
INT16U bit1 : 1;
INT16U bit2 : 1;
INT16U bit3 : 1;
INT16U bit4 : 1;
INT16U bit5 : 1;
INT16U bit6 : 1;
INT16U bit7 : 1;
INT16U bit8 : 1;
INT16U bit9 : 1;
INT16U bit10 : 1;
INT16U bit11 : 1;
INT16U bit12 : 1;
INT16U bit13 : 1;
INT16U bit14 : 1;
INT16U bit15 : 1;
} STRUCT_BITS;
} UNION_CRCREGS; // end of define SRUCT_CRCREGS
//
// 定义一个寄存器组
//
UNION_CRCREGS rCRCReg;
//
// InitCRCRegs
// 初始化寄存器组,寄存器组全置 1
//
void
InitCRCRegs(
void
)
{
rCRCReg.crcValue = 0xffff; // 寄存器组全置 1
}
//
// CRCInputOneBit
// CRC 输入1位
//
void
CRCInputOneBit(
BOOLEAN crcIN
)
{
BOOLEAN bitTemp;
bitTemp = rCRCReg.STRUCT_BITS.bit0 ^ crcIN;
//
// 中一步一步的移位/异或操作
//
rCRCReg.STRUCT_BITS.bit1 = rCRCReg.STRUCT_BITS.bit2;
rCRCReg.STRUCT_BITS.bit2 = rCRCReg.STRUCT_BITS.bit3;
rCRCReg.STRUCT_BITS.bit3 = rCRCReg.STRUCT_BITS.bit4 ^ bitTemp;
rCRCReg.STRUCT_BITS.bit4 = rCRCReg.STRUCT_BITS.bit5;
rCRCReg.STRUCT_BITS.bit5 = rCRCReg.STRUCT_BITS.bit6;
rCRCReg.STRUCT_BITS.bit6 = rCRCReg.STRUCT_BITS.bit7;
rCRCReg.STRUCT_BITS.bit7 = rCRCReg.STRUCT_BITS.bit8;
rCRCReg.STRUCT_BITS.bit8 = rCRCReg.STRUCT_BITS.bit9;
rCRCReg.STRUCT_BITS.bit9 = rCRCReg.STRUCT_BITS.bit10;
rCRCReg.STRUCT_BITS.bit10 = rCRCReg.STRUCT_BITS.bit11 ^ bitTemp;
rCRCReg.STRUCT_BITS.bit11 = rCRCReg.STRUCT_BITS.bit12;
rCRCReg.STRUCT_BITS.bit12 = rCRCReg.STRUCT_BITS.bit13;
rCRCReg.STRUCT_BITS.bit13 = rCRCReg.STRUCT_BITS.bit14;
rCRCReg.STRUCT_BITS.bit14 = rCRCReg.STRUCT_BITS.bit15;
rCRCReg.STRUCT_BITS.bit15 = bitTemp;
}// end CRCInputOneBit
/*crcInputBit中一步一步的移位/异或操作,可以进行简化:*/
//
// CRCInputOneBit_1
// CRC 输入1位
//
void
CRCInputOneBit_1(
BOOLEAN crcIN
)
{
BOOLEAN crcTemp;
crcTemp = rCRCReg.STRUCT_BITS.bit0 ^ crcIN;
rCRCReg.crcValue >>= 1;
if (crcTemp)
{
/* 可以发现0x8408和0x1021(CRC-ITU的简记式)之间的关系。
由于我们是从低到高输出比特流的,将0x1021左右反转就得到0x8408。
将生成多项式写成 G(x)=1+X^5+X^12+X^16,是不是更好看一点*/
rCRCReg.crcValue ^= 0x8408; /
}
} // End of CRCInputOneBit_1
//
// GetCRCRegValue
// 输出CRC码(寄存器组的值)
//
INT16U
GetCRCRegValue(
void
)
{
return rCRCReg.crcValue;
} // end of GetCRCRegValue
// ========================================================================================
// 下面是一个典型的PPP帧。最后两个字节称为FCS(Frame Check Sequence),是前面11个字节的CRC。
// FF 03 C0 21 04 03 00 07 0D 03 06 D0 3A
// 我们来计算这个PPP帧的CRC,并验证它。
// ========================================================================================
//
// CaculatCRC
//
INT16U
CaculatCRC(
void
)
{
INT8U PPP[13] =
{0xff,0x03,0xc0,0x21,0x04,0x03,0x00,0x07,0x0d,0x03,0x06,0xd0,0x3a};
INT8U i, j;
INT16U crcResult; // 用于存放CRC计算的结果
//
// 以下进行CRC寄存器初始化
//
InitCRCRegs ();
//
// 逐位输入ppp[i],每个字节低位在先,不包括两个FCS字节
//
for (i = 0; i < 11; i ++)
{
for (j = 0; j < 8; j ++)
{
CRCInputOneBit (ppp[i] >> j) // ?
}
}
//
// 得到CRC:将寄存器组的值求反
//
crcResult = ~ GetCRCRegValue();
//
// 填写FCS,先低后高
//
ppp[11] = crcResult % 26amp; // ??? what's 26amp
ppp[12] = (crcResult >> 8) % 26amp // ???
}// End of CaculatCRC
//
// CheckCRC16
//
INT16U
ChechCRC16(
void
)
{
INT8U i, j;
INT16U crcResult;
//
// 初始化 register
//
InitCRCRegs ();
//
// 逐位输入,每个字节低位在先,包括两个FCS字节
//
for (i = 0; i < 13; i ++)
{
for (j = 0; j < 8; j ++)
{
CRCInputOneBit (ppp[i] >>j);
}
}
//
// 得到验证结果
//
crcResult = GetCRCRegValue();
return crcResult;
}// End of CheckCRC16
// ================================================================================
// 下面是通用的CRC-ITU查找表以及计算和验证CRC的C语言程序
// ================================================================================
#include "crc16tab.h"
//
// GetCRC16
// 计算给定长度数据的16位CRC
//
INT16U
GetCRC16(
const INT8U *pData,
INT16U nLength
)
{
INT16U FCS = 0Xffff; // FCS 初始化为0xffff
while (nLength > 0)
{
FCS = (FCS >> 8) ^ crc16TAB[(FCS ^ * PData) % 26amp ; 0xff] // ???
nLength --;
pData ++;
}
return (~ FCS);
}
//
// IsCRC16Good
// 检查给定长度数据的16位CRC是否正确
//
// 正确反回1,错误返回0
//
BOOLEAN
IsCRC16Good(
INT8U *pData,
INT16U nLength
)
{
BOOLEAN bResult;
INT16U FCS;
while (nLength > 0)
{
FCS = (FCS >> 8) ^ crc16TAB[(FCS ^ *pData) % 26amp; 0xff]; // ???
nLength --;
pData ++;
}
if (FCS ==0xf0b8)
{
return 1;
}
else
{
return 0;
}
}// End of IsCRC16Good
//
// ==================================================================================
//
// 注意:因最高位一定为“1”,故略去
//
const INT16U cnCRC_16 = 0x8005;
//
// CRC-16 = X16 X15 X2 X0
//
const INT16U cnCRC_CCITT = 0x1021;
//
// CRC-CCITT = X16 X12 X5 X0,据说这个 16 位 CRC 多项式比上一个要好
//
const INT32U cnCRC_32 = 0x04C10DB7;
//
// CRC-32 = X32 X26 X23 X22 X16 X11 X10 X8 X7 X5 X4 X2 X1 X0
//
INT32U Table_CRC[256]; // CRC 表
//
// ==================================================================================
//
// 构造 16 位 CRC 表
//
void
BuildTable16(
INT16U aPoly
)
{
INT16U i, j;
INT16U nData;
INT16U nAccum;
for (i = 0; i < 256; i)
{
nData = (INT16U)(i << 8);
nAccum = 0;
for (j = 0; j < 8; j)
{
if ((nData ^ nAccum) & 0x8000)
nAccum = (nAccum << 1) ^ aPoly;
else
nAccum <<= 1;
nData <<= 1;
}
Table_CRC[i] = (INT32U)nAccum;
}
}
// 计算 16 位 CRC 值,CRC-16 或 CRC-CCITT
INT16U
CRC_16(
INT8U * aData,
INT32U aSize
)
{
INT32U i;
INT16U nAccum = 0;
BuildTable16(cnCRC_16); // or cnCRC_CCITT
for (i = 0; i < aSize; i)
{
nAccum = (nAccum << 8) ^
(INT16U)Table_CRC[(nAccum >> 8) ^ *aData ];
}
return nAccum;
} // End of CRC_16
// 构造 32 位 CRC 表
void
BuildTable32(
INT32U aPoly
)
{
INT32U i, j;
INT32U nData;
INT32U nAccum;
for (i = 0; i < 256; i)
{
nData = (INT32U)(i << 24);
nAccum = 0;
for (j = 0; j < 8; j)
{
if ((nData ^ nAccum) & 0x80000000)
{
nAccum = (nAccum << 1) ^ aPoly;
}
else
{
nAccum <<= 1;
}
nData <<= 1;
}
Table_CRC[i] = nAccum;
}
}// End of BuildTable32
//
// 计算 32 位 CRC-32 值
//
INT32U
CRC_32(
INT8U * pData,
INT32U aSize
)
{
INT32U i;
INT32U nAccum = 0;
BuildTable32(cnCRC_32);
for (i = 0; i < aSize; i)
{
nAccum = (nAccum << 8) ^
Table_CRC[(nAccum >> 24) ^ * pData];
}
return nAccum;
} // End of CRC_32
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -