1)硬件电路组成
a) x^16 + x^12 + x^5 + 1
┌───────────┬─────────────────┬─────────────┐
↑ ┌─┬─┬─┬─┐ ↓ ┌─┬─┬─┬─┬─┬─┬─┐ ↓ ┌─┬─┬─┬─┬─┐ │
◎←│15│14│13│12│←◎←│11│10│09│08│07│06│05│←◎←│04│03│02│01│00│←┘
↑ └─┴─┴─┴─┘ └─┴─┴─┴─┴─┴─┴─┘ └─┴─┴─┴─┴─┘
in
b) x^8 + x^2 + x + 1
┌───────────────┬─────┬─────┐
↑ ┌─┬─┬─┬─┬─┬─┐ ↓ ┌─┐ ↓ ┌─┐ │
◎←│07│06│05│04│03│02│←◎←│01│←◎←│00│←┘
↑ └─┴─┴─┴─┴─┴─┘ └─┘ └─┘
in
2) 简单算法模型(按bit计算)
照以上的硬件电路来看,其工作原理就是:
如果原来CRC的最高位异或输入是1的话,那么絇OST并且异或生成多项式(图a为0x1021,图b为0x7).
如果原来CRC的最高位异或输入是高位异或输入是0的话,那么结果就是CRC左移一位.
那么可以得到以下的程序(以图a例)
U16 crc_cal(bit * in, U32 cnt)
{
U16 crc = 0;
while(cnt--)
{
bool tmp = (crc >> 15) ^ *in;
crc <<= 1;
if(tmp)
crc ^= 0x1021;
in ++;
}
return crc;
}
3) 查表(按字节计算)
很显然,按比特计算的方法,其效率是低下的.
下面介绍查表方法(按字节计算).
要知道为什么可以用查表的方法,需要一些预备知识.
以图b为例,假设当前的CRC值是1011 1001,现在要输入4比特数据1101,其生成多项式是:0000 0111
CRC = 1011 1001, in=1101 , G(X)= 0000 0111
<计算方法1> <计算方法2>
step: 1011 1001 0110 1001
1: 011 1001 0 110 1001 0
2: 11 1001 00 10 1001 00
^ 00 0001 11 ^00 0001 11 <1>
-------------- --------------
11 1000 11 10 1000 11
3: 1 1000 110 0 1000 110
^ 0 0000 111 ^0 0000 111 <2>
---------------- -------------
1 1000 001 0 1000 001
4: 1000 0010 1000 0010
<计算方法1>是硬件电路的完全模拟算法
step 1: 将crc左移一位,因为crc的最高位是1,输入也是1,所以不做处理.
step 2: 将crc左移一位,因为crc的最高位是0,输入是1,所以还需要异或G(X).
....
step 4: 将crc左移一位,因为crc的最高位是0,输入也是0,所以不做处理.
得到最终的结果 crc = 1000 0010
实际上,在crc左移以后,是否还要异或生成多项式的条件是: crc的最高位和输入位异或后的值.
那么是否可以预先将CRC(h)的值与要输入的4比特数据异或,作为是否判断条件呢.
答案是肯定的. CRC = 1011 1001, in=1101, CRC(h)^in = 0110
其计算过程见<计算方法2>
step 1: 将CRC左移一位,因为CRC的最高位是0,所以不做处理.
step 2: 将CRC左移一位,因为CRC的最高位是1,所以还需要异或G(X).
....
step 4: 将CRC左移一位,因为CRC的最高位是0,所以不做处理.
得到最终的结果 CRC = 1000 0010
虽然,上面的结果是一样的,可有证据证明无论什么情况下,结果都是对的?
静下来想想,你就是知道这2个方法确实能得出相同的结果.
当4比特的输入完成之后,整个CRC值左移了4位,原来的CRC(h)只是作为判断异或生成多项式的条件存在过.
最终的CRC值完全是G(X)和CRC(l)不停地(异或/移位)的结果.
虽然,在CRC计算的过程中,CRC不停的在变化着,但:
1. 如果在<方法1>中,由于CRC的最高位和输入异或后的结果等于0,那么CRC只是左移一位.
显然2个方法是一样的.
2. 如果在<方法1>中,由于CRC的最高位和输入异或后的结果等于1,那么CRC左移一位后,还需要异或G(X).
异或G(X)的过程中,可能使CRC的后续某位产生变化(也可能不变化,视生成多项式的值而定).
a.如果没发生变化,那当这位最后移到最高位,作为判断条件的时候,仍然是以前的这个值和输入位的异或.
显然2个计算方法是一样的.
b.如果变化过, 那当这位最后移到最高位,作为判断条件的时候,是变化过后的值和输入位的异或.
但如果<方法1>能引起后续某位的变化,<方法2>同样也会引起同一位的变化.
这样当这位最后移到最高位,作为判断条件的时候,2种方法的判断条件仍然是一致的.
* 关于这部分,我描述得不怎么清楚,那是因为我小时候地语文基础没打好,:).
如果你有更好地描述,请告诉我.
好了,预备知识完毕,现在开始探讨那个查找表是怎么来的.
请看<方法2>,最终的CRC的结果是: (CRC(l) << 4) ^ <1> ^ <2>
<计算方法2>
CRC = 1011 1001, in=1101 , G(X)= 0000 0111
|-----------------------> CRC(h)^in = 1011 ^ 1101 = 0110
|
| |------------------> CRC(l)
---- ----
0110 1001
110 1001 0
10 1001 00
^00 0001 11 <1>
--------------
10 1000 11
0 1000 110
^0 0000 111 <2>
-------------
0 1000 001
1000 0010
由于异或的可结合律,其结果等同于: (CRC(l) << 4) ^ ( <1> ^ <2> )
这说明, ( <1) ^ <2> )可以预先制作成表格,采用查表的方法计算CRC, 表的索引是 CRC(h) ^ in .
其结果是: ( CRC(l) << 4) ^ table[ CRC(h) ^ in ].
因为是4比特,表的大小是16.
表的内容可以根据G(X),预先计算.
这里举例用的4比特,基于字节的方法可以用同样的方法.
那么现在开始编程了.
U16 crc_tab[256]= {...};
U16 crc_cal(U8 * ptr, U32 cnt)
{
U16 crc = 0;
U8 da;
while (cnt--)
{
da = crc >> 8; // CRC(h)
crc <<= 8;
crc ^= crc_tab[da ^ *ptr++];
}
return crc;
}
既然你已经知道了查表的原理,那么编一个计算表值的程序不成问题了.
#define GX 0x1021
void CCrcDlg::OnButton1()
{
WORD table[256];
for(int i =0; i<256; i++)
{
WORD crc = i << 8;
for(int n=0; n<8; n++)
{
bool tmp = crc & (1<<15) ? true : false;
crc <<= 1;
if(tmp)
crc ^= GX;
}
table = crc;
}
}
那么你得到了这么个表:
U16 table[256]=
{
0X0000, 0X1021, 0X2042, 0X3063, 0X4084, 0X50A5, 0X60C6, 0X70E7,
0X8108, 0X9129, 0XA14A, 0XB16B, 0XC18C, 0XD1AD, 0XE1CE, 0XF1EF,
0X1231, 0X0210, 0X3273, 0X2252, 0X52B5, 0X4294, 0X72F7, 0X62D6,
0X9339, 0X8318, 0XB37B, 0XA35A, 0XD3BD, 0XC39C, 0XF3FF, 0XE3DE,
0X2462, 0X3443, 0X0420, 0X1401, 0X64E6, 0X74C7, 0X44A4, 0X5485,
0XA56A, 0XB54B, 0X8528, 0X9509, 0XE5EE, 0XF5CF, 0XC5AC, 0XD58D,
0X3653, 0X2672, 0X1611, 0X0630, 0X76D7, 0X66F6, 0X5695, 0X46B4,
0XB75B, 0XA77A, 0X9719, 0X8738, 0XF7DF, 0XE7FE, 0XD79D, 0XC7BC,
0X48C4, 0X58E5, 0X6886, 0X78A7, 0X0840, 0X1861, 0X2802, 0X3823,
0XC9CC, 0XD9ED, 0XE98E, 0XF9AF, 0X8948, 0X9969, 0XA90A, 0XB92B,
0X5AF5, 0X4AD4, 0X7AB7, 0X6A96, 0X1A71, 0X0A50, 0X3A33, 0X2A12,
0XDBFD, 0XCBDC, 0XFBBF, 0XEB9E, 0X9B79, 0X8B58, 0XBB3B, 0XAB1A,
0X6CA6, 0X7C87, 0X4CE4, 0X5CC5, 0X2C22, 0X3C03, 0X0C60, 0X1C41,
0XEDAE, 0XFD8F, 0XCDEC, 0XDDCD, 0XAD2A, 0XBD0B, 0X8D68, 0X9D49,
0X7E97, 0X6EB6, 0X5ED5, 0X4EF4, 0X3E13, 0X2E32, 0X1E51, 0X0E70,
0XFF9F, 0XEFBE, 0XDFDD, 0XCFFC, 0XBF1B, 0XAF3A, 0X9F59, 0X8F78,
0X9188, 0X81A9, 0XB1CA, 0XA1EB, 0XD10C, 0XC12D, 0XF14E, 0XE16F,
0X1080, 0X00A1, 0X30C2, 0X20E3, 0X5004, 0X4025, 0X7046, 0X6067,
0X83B9, 0X9398, 0XA3FB, 0XB3DA, 0XC33D, 0XD31C, 0XE37F, 0XF35E,
0X02B1, 0X1290, 0X22F3, 0X32D2, 0X4235, 0X5214, 0X6277, 0X7256,
0XB5EA, 0XA5CB, 0X95A8, 0X8589, 0XF56E, 0XE54F, 0XD52C, 0XC50D,
0X34E2, 0X24C3, 0X14A0, 0X0481, 0X7466, 0X6447, 0X5424, 0X4405,
0XA7DB, 0XB7FA, 0X8799, 0X97B8, 0XE75F, 0XF77E, 0XC71D, 0XD73C,
0X26D3, 0X36F2, 0X0691, 0X16B0, 0X6657, 0X7676, 0X4615, 0X5634,
0XD94C, 0XC96D, 0XF90E, 0XE92F, 0X99C8, 0X89E9, 0XB98A, 0XA9AB,
0X5844, 0X4865, 0X7806, 0X6827, 0X18C0, 0X08E1, 0X3882, 0X28A3,
0XCB7D, 0XDB5C, 0XEB3F, 0XFB1E, 0X8BF9, 0X9BD8, 0XABBB, 0XBB9A,
0X4A75, 0X5A54, 0X6A37, 0X7A16, 0X0AF1, 0X1AD0, 0X2AB3, 0X3A92,
0XFD2E, 0XED0F, 0XDD6C, 0XCD4D, 0XBDAA, 0XAD8B, 0X9DE8, 0X8DC9,
0X7C26, 0X6C07, 0X5C64, 0X4C45, 0X3CA2, 0X2C83, 0X1CE0, 0X0CC1,
0XEF1F, 0XFF3E, 0XCF5D, 0XDF7C, 0XAF9B, 0XBFBA, 0X8FD9, 0X9FF8,
0X6E17, 0X7E36, 0X4E55, 0X5E74, 0X2E93, 0X3EB2, 0X0ED1, 0X1EF0
};
---------------------------------- END ------------------------------------
联系客服