crc16-Modbus C语言实现
时间:2023-06-26 11:07:00
1.crc16-Modbus计算方法
-
crc16-modbus标准
多项式x16 x15 x2 1(0x8005),初始值0xFFFF,低位在前,高位在后,结果与0x0000异或
0x8005 = 0001 1000 0000 0000 0101取低16位 -
CRC16的算法原理:
1.根据CRC16的标准选择初值CRCIn的值。
2.将数据的第一个字节与CRCIn高8位异或。
3.判断最高位置,如果该位置为 0 左移一个,若为 1 左移一个再和多项式Hex码异或。
4.重复第三步,直到8位移位计算结束。
5.重复完成上述所有输入数据操作步骤,16位数为16位CRC校验码。
2.C语言实现
2.1 直接计算CRC
CRC算法参数模型解释: NAME:参数模型名称。 WIDTH:宽度,即CRC
比特数。 POLY:简写生成项,以16例如:CRC-32即是0x04C11DB7,忽略最高位置"1",即完整的生 成项是0x104C11DB7。 INIT:这是算法开始时的寄存器(crc)十六进制表示初始预置值。 REFIN:待测数据的每个字节是否按位反转,True或False。 REFOUT:计算后,整个数据是否在不同或输出前反转,True或False。 XOROUT:计算结果与此参数相差或最终得到CRC值。 Alias:别名及其应用范围。
/****************************Info********************************************** * Name: CRC-16/MODBUS x16 x15 x2 1 * Width: 16 * Poly: 0x8005 * Init: 0xFFFF * Refin: True * Refout: True * Xorout: 0x0000 * Note: *****************************************************************************/ #if 0 unsigned short CRC16_MODBUS(unsigned char *data, unsigned int datalen) {
unsigned short wCRCin = 0xFFFF; unsigned short wCPoly = 0x8005; unsigned char wChar = 0; while (datalen--) {
wChar = *(data ); 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);
}
#else
unsigned short CRC16_MODBUS(unsigned char *data, unsigned int datalen)
{
unsigned short wCRCin = 0xFFFF;
unsigned short wCPoly = 0x8005;
InvertUint16(&wCPoly,&wCPoly);
while (datalen--)
{
wCRCin ^= *(data++);
for(int i = 0;i < 8;i++)
{
if(wCRCin & 0x01)
wCRCin = (wCRCin >> 1) ^ wCPoly;
else
wCRCin = wCRCin >> 1;
}
}
return (wCRCin);
}
#endif
/****************************Info********************************************** * Name: InvertUint8 * Note: 把字节颠倒过来,如0x12变成0x48 0x12: 0001 0010 0x48: 0100 1000 *****************************************************************************/
void InvertUint8(unsigned char *dBuf,unsigned char *srcBuf)
{
int i;
unsigned char tmp[4]={
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]={
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]={
0};
for(i=0;i< 32;i++)
{
if(srcBuf[0]& (1 << i))
tmp[0]|=1<<(31 - i);
}
dBuf[0] = tmp[0];
}
测试.c文件
#include
/****************************Info********************************************** * Name: InvertUint8 * Note: 把字节颠倒过来,如0x12变成0x48 0x12: 0001 0010 0x48: 0100 1000 *****************************************************************************/
void InvertUint8(unsigned char *dBuf,unsigned char *srcBuf)
{
int i;
unsigned char tmp[4]={
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]={
0};
for(i=0;i< 16;i++)
{
if(srcBuf[0]& (1 << i))
tmp[0]|=1<<(15 - i);
}
dBuf[0] = tmp[0];
}
/****************************Info********************************************** * Name: CRC-16/MODBUS x16+x15+x2+1 * Width: 16 * Poly: 0x8005 * Init: 0xFFFF * Refin: True * Refout: True * Xorout: 0x0000 * Note: *****************************************************************************/
#if 0
unsigned short CRC16_MODBUS(unsigned char *data, unsigned int datalen)
{
unsigned short wCRCin = 0xFFFF;
unsigned short wCPoly = 0x8005;
unsigned char wChar = 0;
while (datalen--)
{
wChar = *(data++);
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);
}
#else
unsigned short CRC16_MODBUS(unsigned char *data, unsigned int datalen)
{
unsigned short wCRCin = 0xFFFF;
unsigned short wCPoly = 0x8005;
InvertUint16(&wCPoly,&wCPoly);
while (datalen--)
{
wCRCin ^= *(data++);
for(int i = 0;i < 8;i++)
{
if(wCRCin & 0x01)
wCRCin = (wCRCin >> 1) ^ wCPoly;
else
wCRCin = wCRCin >> 1;
}
}
return (wCRCin);
}
#endif
unsigned char buf[8] = {
0x04,0x01,0x00,0x00,0x00,0x04}; //16位数据的高字节在低位,低字节在高位
unsigned short crc16ModbusResult_u16Data;
int main(void)
{
printf("primary data : %02X %02X %02X %02X %02X %02X\r\n",buf[0],buf[1],buf[2],buf[3],buf[4],buf[5]);
crc16ModbusResult_u16Data = CRC16_MODBUS(buf,6);
printf("crc16 Modbus Result: %04X\r\n",crc16ModbusResult_u16Data);
buf[6] = (unsigned char)(crc16ModbusResult_u16Data&0x00FF);
buf[7] = (unsigned char)((crc16ModbusResult_u16Data&0xFF00)>>8);
printf("a frame of data : %02X %02X %02X %02X %02X %02X %02X %02X\r\n",buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7]);
return 0;
}
2.2 查长表法
- 用空间换时间
测试.c文件
#include
/* Table of CRC values for high–order byte */ const unsigned char auchCRCHi[] = { 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, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 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, 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, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 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, 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, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 }; /* Table of CRC values for low–order byte */ const unsigned char auchCRCLo[] = { 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, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, 0x11