在
做项目过程中,对方传输CRC16校验函数是C++代码写的,而自己从串口接收数据用java语言,不得不看懂
他们的代码。然后自己用java代码来实现。
由于正确帧格式是以#开头,以;结束,中间前19位为传输位,后4位为校验位。形如"#12345678912345678912345;"这样的格式才算正确。像多位,少位的情况直接忽视,因为传输的肯定不正确。而对于这种正确格式,我就需要用他们提供的CRC16位校验函数计算校验码与接收的校验码对比,如果完全相同,ok。传输正确,并把数据
解析插入数据库。
//计算校验码
u32 CRC_Convert(u8 *toConvert, u16 length) //后面要根据帧的不同设置不同的长度
{
u32 crc = 0;
u8 i;
u8 *ptr = toConvert + 1;
while(length--)
{
for(i = 0x80; i != 0; i = i >> 1)
{
if((crc & 0x8000) != 0)
{
crc = crc << 1;
crc = crc ^ 0x11021;
}
else
{
crc = crc << 1;
}
if((*ptr & i) != 0)
{
crc = crc ^ 0x1021;// 0x10000 ^ 0x11021
}
}
ptr++;
}
return crc;
}
//提取校验码
u16 HexString_To_UnsignedShort(u8 hexString[4])
{
u8 *ptr = hexString; //根据帧类型判断要加几
u16 crc = 0;
u16 i;
//将校验位的字符转换为相应的十六进制数
for(i = 0; i < 4; i++)
{
crc <<= 4;
if(*(ptr + i) >= 'A' && *(ptr + i) <= 'F')
{
crc |= *(ptr + i) - 'A' + 10;
}
else if(*(ptr + i) >= '0' && *(ptr + i) <= '9')
{
crc |= *(ptr + i) - '0';
}
else if(*(ptr + i) >= 'a' && *(ptr + i) <= 'f')
{
crc |= *(ptr + i) - 'a' + 10;
}
else
{
return 0;
}
}
return crc;
}
上面的C++代码实现,我改写的java代码如下。
public class testCRC {
public static void main(String args[]){
String oldStr ="#12345678912345678912345;";
String str = oldStr.substring(1,20);
String valStr = oldStr.substring(20,24);
System.out.println(valStr);
//System.out.println(str);
//String str="1234567891234567891";
int aa = CRC_Convert(str,str.length());
// System.out.println(aa);
String bb = Integer.toHexString(aa);
// System.out.printf("%x",aa);
System.out.println(bb);
if(bb.equals(valStr))
{
System.out.println("传输正确");
}
}
public static int CRC_Convert(String str, int length) //后面要根据帧的不同设置不同的长度
{
int crc = 0;
int i;
char[] ptr = new char[length];
for(int k=0;k<length;k++){
ptr[k] = str.charAt(k);
for(i = 0x80; i != 0; i = i >> 1)
{
if((crc & 0x8000) != 0)
{
crc = crc << 1;
crc = crc ^ 0x11021;
}
else
{
crc = crc << 1;
}
if((ptr[k] & i) != 0)
{
crc = crc ^ 0x1021;// 0x10000 ^ 0x11021
}
}
}
return crc;
}
}
总结:在CRC16位校验中,一般都是采用从起始位循环异或右移,直至最后一位结束。