?? 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 + -