CRC16常見幾個標(biāo)準(zhǔn)的算法及C語言實現(xiàn)
校驗碼的計算多項式為(X16 + X15 + X2 + 1)。具體CRC16碼的計算方法是:
1.預(yù)置1個16位的寄存器為十六進制FFFF(即全為1);稱此寄存器為CRC寄存器;
2.把第一個8位二進制數(shù)據(jù) (既通訊信息幀的第一個字節(jié))與16位的CRC寄存器的低8位相異或,把結(jié)果放于CRC寄存器;
3.把CRC寄存器的內(nèi)容右移一 位(朝低位)用0填補最高位,并檢查右移后的移出位;
4.如果移出位為0:重復(fù)第3步(再次右移一位);
如果移出位為1:CRC寄存器與多項式A001(1010 0000 0000 0001)進行異或;(Modbus)
5.重復(fù)步驟3和4,直到右移8次,這樣整個8位數(shù)據(jù)全部進行了處理;
6.重復(fù)步驟2到步驟5,進行通訊信息幀下一個字節(jié)的處理;
7.將該通訊信息幀所有字節(jié)按上述步驟計算完成后,得到的16位CRC寄存器的高、低字節(jié)進行交換;
8.最后得到的CRC寄存器內(nèi)容即為:CRC碼。
CRC16常見的標(biāo)準(zhǔn)有以下幾種,被用在各個規(guī)范中,其算法原理基本一致,就是在數(shù)據(jù)的輸入和輸出有所差異,下邊把這些標(biāo)準(zhǔn)的差異列出,并給出C語言的算法實現(xiàn)。
CRC16_CCITT:多項式x16+x12+x5+1(0x1021),初始值0x0000,低位在前,高位在后,結(jié)果與0x0000異或
CRC16_CCITT_FALSE:多項式x16+x12+x5+1(0x1021),初始值0xFFFF,低位在后,高位在前,結(jié)果與0x0000異或
CRC16_XMODEM:多項式x16+x12+x5+1(0x1021),初始值0x0000,低位在后,高位在前,結(jié)果與0x0000異或
CRC16_X25:多項式x16+x12+x5+1(0x1021),初始值0x0000,低位在前,高位在后,結(jié)果與0xFFFF異或
CRC16_MODBUS:多項式x16+x15+x2+1(0x8005),初始值0xFFFF,低位在前,高位在后,結(jié)果與0x0000異或
CRC16_IBM:多項式x16+x15+x2+1(0x8005),初始值0x0000,低位在前,高位在后,結(jié)果與0x0000異或
CRC16_MAXIM:多項式x16+x15+x2+1(0x8005),初始值0x0000,低位在前,高位在后,結(jié)果與0xFFFF異或
CRC16_USB:多項式x16+x15+x2+1(0x8005),初始值0xFFFF,低位在前,高位在后,結(jié)果與0xFFFF異或
模式 | 多項式 | 初始值 | 數(shù)據(jù)位序 | 結(jié)果處理 |
CRC16_CCITT | x16+x12+x5+1(0x1021) | 0x0000 | 低位在前,高位在后 | 與0x0000異或 |
CRC16_CCITT_FALSE | x16+x12+x5+1(0x1021) | 0xFFFF | 低位在后,高位在前 | 與0x0000異或 |
CRC16_XMODEM | x16+x12+x5+1(0x1021) | 0x0000 | 低位在后,高位在前 | 與0x0000異或 |
CRC16_X25 | x16+x12+x5+1(0x1021) | 0x0000 | 低位在后,高位在前 | 與0xFFFF異或 |
CRC16_ MODBUS | x16+x15+x2+1(0x8005) | 0xFFFF | 低位在前,高位在后 | 與0x0000異或 |
CRC16_ IBM | x16+x15+x2+1(0x8005) | 0x0000 | 低位在前,高位在后 | 與0x0000異或 |
CRC16_ MAXIM | x16+x15+x2+1(0x8005) | 0x0000 | 低位在前,高位在后 | 與0xFFFF異或 |
CRC16_ USB | x16+x15+x2+1(0x8005) | 0xFFFF | 低位在前,高位在后 | 與0xFFFF異或 |
多項式產(chǎn)生:
如x16+x12+x5+1
x16表示第16位為1,x5表示第5位為1
(1 << 16) | (1 << 12) | (1 << 5) | (1) = 0x11021
但是CRC16只取低16位,寫成16進制數(shù)就是 0x1021
CRC16的算法原理:
1.根據(jù)CRC16的標(biāo)準(zhǔn)選擇初值CRCIn的值。
2.將數(shù)據(jù)的第一個字節(jié)與CRCIn高8位異或。
3.判斷最高位,若該位為 0 左移一位,若為 1 左移一位再與多項式Hex碼異或。
4.重復(fù)3直至8位全部移位計算結(jié)束。
5.重復(fù)將所有輸入數(shù)據(jù)操作完成以上步驟,所得16位數(shù)即16位CRC校驗碼。
根據(jù)算法原理與標(biāo)準(zhǔn)要求就能簡單的寫出具體程序:
unsigned short CRC16_CCITT(unsigned char *puchMsg, unsigned int usDataLen)
{
unsigned short wCRCin = 0x0000;
unsigned short wCPoly = 0x1021;
unsigned char wChar = 0;
while (usDataLen--)
{
wChar = *(puchMsg++);
InvertUint8(&wChar,&wChar);
wCRCin ^= (wChar << 8);
for(int i = 0;i < 8;i++)
{
if(wCRCin & 0x8000)
wCRCin = (wCRCin << 1) ^ wCPoly;
else
wCRCin = wCRCin << 1;
}
}
InvertUint16(&wCRCin,&wCRCin);
return (wCRCin) ;
}
unsigned short CRC16_CCITT_FALSE(unsigned char *puchMsg, unsigned int usDataLen)
{
unsigned short wCRCin = 0xFFFF;
unsigned short wCPoly = 0x1021;
unsigned char wChar = 0;
while (usDataLen--)
{
wChar = *(puchMsg++);
wCRCin ^= (wChar << 8);
for(int i = 0;i < 8;i++)
{
if(wCRCin & 0x8000)
wCRCin = (wCRCin << 1) ^ wCPoly;
else
wCRCin = wCRCin << 1;
}
}
return (wCRCin) ;
}
unsigned short CRC16_XMODEM(unsigned char *puchMsg, unsigned int usDataLen)
{
unsigned short wCRCin = 0x0000;
unsigned short wCPoly = 0x1021;
unsigned char wChar = 0;
while (usDataLen--)
{
wChar = *(puchMsg++);
wCRCin ^= (wChar << 8);
for(int i = 0;i < 8;i++)
{
if(wCRCin & 0x8000)
wCRCin = (wCRCin << 1) ^ wCPoly;
else
wCRCin = wCRCin << 1;
}
}
return (wCRCin) ;
}
unsigned short CRC16_X25(unsigned char *puchMsg, unsigned int usDataLen)
{
unsigned short wCRCin = 0xFFFF;
unsigned short wCPoly = 0x1021;
unsigned char wChar = 0;
while (usDataLen--)
{
wChar = *(puchMsg++);
InvertUint8(&wChar,&wChar);
wCRCin ^= (wChar << 8);
for(int i = 0;i < 8;i++)
{
if(wCRCin & 0x8000)
wCRCin = (wCRCin << 1) ^ wCPoly;
else
wCRCin = wCRCin << 1;
}
}
InvertUint16(&wCRCin,&wCRCin);
return (wCRCin^0xFFFF) ;
}
unsigned short CRC16_MODBUS(unsigned char *puchMsg, unsigned int usDataLen)
{
unsigned short wCRCin = 0xFFFF;
unsigned short wCPoly = 0x8005;
unsigned char wChar = 0;
while (usDataLen--)
{
wChar = *(puchMsg++);
InvertUint8(&wChar,&wChar);
wCRCin ^= (wChar << 8);
for(int i = 0;i < 8;i++)
{
if(wCRCin & 0x8000)
wCRCin = (wCRCin << 1) ^ wCPoly;
else
wCRCin = wCRCin << 1;
}
}
InvertUint16(&wCRCin,&wCRCin);
return (wCRCin) ;
}
unsigned short CRC16_IBM(unsigned char *puchMsg, unsigned int usDataLen)
{
unsigned short wCRCin = 0x0000;
unsigned short wCPoly = 0x8005;
unsigned char wChar = 0;
while (usDataLen--)
{
wChar = *(puchMsg++);
InvertUint8(&wChar,&wChar);
wCRCin ^= (wChar << 8);
for(int i = 0;i < 8;i++)
{
if(wCRCin & 0x8000)
wCRCin = (wCRCin << 1) ^ wCPoly;
else
wCRCin = wCRCin << 1;
}
}
InvertUint16(&wCRCin,&wCRCin);
return (wCRCin) ;
}
unsigned short CRC16_MAXIM(unsigned char *puchMsg, unsigned int usDataLen)
{
unsigned short wCRCin = 0x0000;
unsigned short wCPoly = 0x8005;
unsigned char wChar = 0;
while (usDataLen--)
{
wChar = *(puchMsg++);
InvertUint8(&wChar,&wChar);
wCRCin ^= (wChar << 8);
for(int i = 0;i < 8;i++)
{
if(wCRCin & 0x8000)
wCRCin = (wCRCin << 1) ^ wCPoly;
else
wCRCin = wCRCin << 1;
}
}
InvertUint16(&wCRCin,&wCRCin);
return (wCRCin^0xFFFF) ;
}
unsigned short CRC16_USB(unsigned char *puchMsg, unsigned int usDataLen)
{
unsigned short wCRCin = 0xFFFF;
unsigned short wCPoly = 0x8005;
unsigned char wChar = 0;
while (usDataLen--)
{
wChar = *(puchMsg++);
InvertUint8(&wChar,&wChar);
wCRCin ^= (wChar << 8);
for(int i = 0;i < 8;i++)
{
if(wCRCin & 0x8000)
wCRCin = (wCRCin << 1) ^ wCPoly;
else
wCRCin = wCRCin << 1;
}
}
InvertUint16(&wCRCin,&wCRCin);
return (wCRCin^0xFFFF) ;
}void InvertUint8(unsigned char *dBuf,unsigned char *srcBuf)
{
int i;
unsigned char tmp[4];
tmp[0] = 0;
for(i=0;i< 8;i++)
{
if(srcBuf[0]& (1 << i))
tmp[0]|=1<<(7-i);
}
dBuf[0] = tmp[0];
}
void InvertUint16(unsigned short *dBuf,unsigned short *srcBuf)
{
int i;
unsigned short tmp[4];
tmp[0] = 0;
for(i=0;i< 16;i++)
{
if(srcBuf[0]& (1 << i))
tmp[0]|=1<<(15 - i);
}
dBuf[0] = tmp[0];
}
void InvertUint32(unsigned int *dBuf,unsigned int *srcBuf)
{
int i;
unsigned int tmp[4];
tmp[0] = 0;
for(i=0;i< 32;i++)
{
if(srcBuf[0]& (1 << i))
tmp[0]|=1<<(15 - i);
}
dBuf[0] = tmp[0];
}具體驗證使用這個工具,內(nèi)含CRC算法的計算,和后邊的博客中提到的其他算法的工具合集
在這個基礎(chǔ)上也加入CRC32 的校驗算法
/CRC32算法:
unsigned int CRC32(unsigned char *puchMsg, unsigned int usDataLen)
{
int i;
unsigned int wCRCin = 0xFFFFFFFF;
unsigned int wCPoly = 0x04C11DB7;
unsigned int wChar = 0;
while (usDataLen--)
{
wChar = *(puchMsg++);
InvertUint8((unsigned char *)&wChar,(unsigned char *)&wChar);
wCRCin ^= (wChar << 24);
for(i = 0;i < 8;i++)
{
if(wCRCin & 0x80000000)
wCRCin = (wCRCin << 1) ^ wCPoly;
else
wCRCin = wCRCin << 1;
}
}
InvertUint32(&wCRCin,&wCRCin);
return (wCRCin ^ 0xFFFFFFFF) ;
}對于CRC32可能還有其他的多項式和初始值和結(jié)果值是否需要異或以及輸入數(shù)據(jù)是否需要位序倒轉(zhuǎn)等要求在源碼中修改
*博客內(nèi)容為網(wǎng)友個人發(fā)布,僅代表博主個人觀點,如有侵權(quán)請聯(lián)系工作人員刪除。












