锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

crc16-Modbus C语言实现

时间:2023-06-26 11:07:00 继电器3e4

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 

相关文章