2024年4月27日发(作者:)

CRC16校验C语言程序源码 (附完整的可执行的 C语言代码)

//CRC16校验在通讯中应用广泛,这里不对其理论进行讨论,只对常见的

//实现方法进行测试。

方法一:查表法(256长度的校验表)

速度快,准确,但是对于单片机设备存储占用大,且校验表长度大,输入时容易岀现错误

//--POPULAR POLYNOMIALS ....................

..................

// CCITT:

x

A

16 + x

A

12 + x

A

5 + x

A

0

2种

(0x1021

)

)

// CRC-16:

#defi ne

x

A

16 + xA15 + xA2 + xA0

CRC_16_POLYNOMIALS 0x8005

// CRC 高位字节值表

(0x8005

const BYTE chCRCHTalbe[]=

{

0x00, 0xC1, 0x81, 0x40, 0x01, OxCO, 0x80, 0x41,

0x00, 0xC1, 0x81, 0x40, 0x01,0xC0, 0x80, 0x41,

0x00, 0xC1, 0x81, 0x40, 0x01,0xC0, 0x80, 0x41,

0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,

0x00, 0xC1, 0x81, 0x40, 0x01,0xC0, 0x80, 0x41,

0x00, 0xC1, 0x81, 0x40, 0x01,0xC0, 0x80, 0x41,

0x00, 0xC1, 0x81, 0x40, 0x01,0xC0, 0x80, 0x41,

0x01, OxCO, 0x80, 0x41,

0x00, 0xC1,0x81,0x40,

0x01, 0xC0, 0x80, 0x41,

0x01, 0xC0, 0x80, 0x41,

0x01, 0xC0, 0x80, 0x41,

0x00, 0xC1,0x81,0x40,

0x00, 0xC1,0x81,0x40,

0x01, 0xC0, 0x80, 0x41,0x01,0xC0, 0x80, 0x41, 0x00, 0xC1,0x81,0x40,

0x00, 0xC1, 0x81, 0x40, 0x01,0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,

0x00, 0xC1, 0x81, 0x40, 0x01,0xC0, 0x80, 0x41, 0x00, 0xC1,0x81,0x40,

0x00, 0xC1, 0x81, 0x40, 0x01,0xC0, 0x80, 0x41,

0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,

0x00, 0xC1, 0x81, 0x40, 0x01,0xC0, 0x80, 0x41,

0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,

0x01,

0x01,

0x01,

0x01,

0xC0, 0x80, 0x41,

0xC0, 0x80, 0x41,

0xC0, 0x80, 0x41,

0xC0, 0x80, 0x41,

0x01, 0xC0, 0x80, 0x41,0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,0x80, 0x41,

0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,

0x00, 0xC1, 0x81, 0x40, 0x01,0xC0, 0x80, 0x41,

0x00, 0xC1, 0x81, 0x40, 0x01,0xC0, 0x80, 0x41,

0x00, 0xC1, 0x81, 0x40, 0x01,0xC0, 0x80, 0x41,

0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,

0x00, 0xC1, 0x81, 0x40, 0x01,0xC0, 0x80, 0x41,

0x00, 0xC1, 0x81, 0x40

}

con st BYTE chCRCLTalbe[] =

{

0x00, 0xC0, 0xC1,0x01,0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7,

0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B,

0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1代 0x1E, 0xDE, 0xDF, 0x1F,

0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,

0x11, OxD1, OxDO, 0x10, OxFO, 0x30, 0x31, OxF1,0x33, 0xF3, 0xF2, 0x32,

0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D,

// CRC 低位字节值表

0x01,

0x01,

0xC0, 0x80, 0x41,

0xC0, 0x80, 0x41,

0x00, 0xC1,0x81,0x40,

0x01,

0x01,

0x01,

0xC0, 0x80, 0x41,

0xC0, 0x80, 0x41,

0xC0, 0x80, 0x41,

1 / 5

0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38,

0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF,

0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,

0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61,0xA1,

0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4,

0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB,

0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA,

0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,

0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0,

0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97,

0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E,

0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89,

0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,

0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83,

0x41, 0x81, 0x80, 0x40

}

WORD CRC16_1(BYTE* pchMsg, WORD wDataLe n)

{

BYTE chCRCHi = 0xFF; //

BYTE chCRCLo = 0xFF; //

WORD win dex;

高 CRC字节初始化

低 CRC字节初始化

// CRC 循环中的索引

while (wDataLe n--)

{

// 计算CRC

win dex = chCRCLo

A

*pchMsg++ ;

chCRCLo = chCRCHi

A

chCRCHTalbe[wl ndex]; chCRCHi =

chCRCLTalbe[wi ndex];

}

return ((chCRCHi << 8) | chCRCLo);

}

方法一:列表法(简单表)

con st WORD wCRCTalbeAbs[]=

{

0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401, 0xA001, 0x6C00, 0x7800,

0xB401,0x5000, 0x9C01,0x8801,0x4400,

}

WORD CRC16_2(BYTE* pchMsg, WORD wDataLe n)

{

WORD wCRC = OxFFFF;

2 / 5

WORD i;

BYTE chChar;

for (i = 0; i < wDataLe n; i++)

{

chChar = *pchMsg++;

wCRC = wCRCTalbeAbs[(chChar

A

wCRC)& 15]

A

(wCRC>> 4);

wCRC = wCRCTalbeAbs[((chChar >> 4)

A

wCRC) & 15]

A

(wCRC >> 4);

}

return wCRC;

}

方法二:定义法

根据CRC16/MODBUS理直接计算,算法简单但对单片机计算压力大。

WORD CRC16_3(BYTE* pchMsg, WORD wDataLe n)

{

BYTE i, chChar;

WORD wCRC = OxFFFF;

while (wDataLe n--)

{

chChar = *pchMsg++;

chChar = Bytel nvert(chChar);

wCRC

A

= (((WORD) chChar) << 8);

for (i = 0; i < 8; i++)

{

if (wCRC & 0x8000)

wCRC = (wCRC << 1)

A

CRC_16_POLYNOMIALS;

else

wCRC <<= 1;

}

}

wCRC = WordI nvert(wCRC);

return wCRC;

}

//试验数据:

//

采用

Metrowerks CodeWarrior

在DSP56F80X平台上

对这3种方法

//进行了性能测试。

3 / 5

// --

//

代码大小

额外存储空间

// --

//

字)

字)

执行时间

周期数

方法1

32

512

540

//

方法2

57

16

1120

//

方法3

142*

0

4598

//

附一个完整的C语言代码

#in elude void In vertU in t8( un sig ned char *dBuf,u nsig ned char *srcBuf) {

int i;

un sig ned char tmp[4];

tmp[0] = 0;

for(i=0;i< 8;i++)

{

if(srcBuf[O] & (1 << i))

tmp[0]|=1<<(7-i);

}

dBuf[0] = tmp[0];

} void InvertUin t16( un sig ned short *dBuf,u nsig ned short *srcBuf) {

int i;

un sig ned short tmp[4]; tmp[0] = 0;

4 / 5

for(i=0;i< 16;i++)

{

}

if(srcBuf[0]& (1 << i)) tmp[0]|=1<<(15 - i);

dBuf[0] = tmp[0];

}

unsigned short CRC16_MODBUS(unsigned char *puchMsg, unsigned int usDataLen)

{

unsigned short wCRCin = 0xFFFF;

unsigned short wCPoly = 0x8005;

unsigned char wChar = 0;

int i;

while (usDataLen--)

{

wChar = *(puchMsg++); InvertUint8(&wChar,&wChar);

wCRCin

A

= (wChar << 8);

for(i = 0;i < 8;i++)

{

if(wCRCin & 0x8000) wCRCin = (wCRCin << 1) A wCPoly;

else

wCRCin = wCRCin << 1;

}

}

InvertUint16(&wCRCin,&wCRCin);

return (wCRCin) ;

}

int main()

{

unsigned char puchMsg[10]="";

unsigned short result=CRC16_MODBUS(puchMsg,10);

// 字符串可直接用 %是输入,具 体应

用具体实现,但后面的 int 型参数

对应字符串长度必须正 确。

printf("%X",result);

5 / 5