上一篇文章简单叙述了串口通信的参数,这一篇讲叙串口通信的校验方式。
串口通信中的数据传输过程中,可能会受到多种干扰和误差,如电磁干扰、信号衰减、信号失真等。这些干扰和误差可能会导致数据的丢失、损坏、重复或错位等问题,从而导致数据传输错误。 因此,在串口通信中引入校验机制是必要的,它可以检测数据传输过程中出现的错误或损坏,从而保证数据的正确性和完整性。
串口通信中的校验码通常是通过在数据包的末尾附加一个固定长度的校验码来实现的,发送方在发送数据时计算校验码并将其附加在数据包的末尾,接收方在接收到数据后同样计算校验码,并与发送方发送的校验码进行比对,以判断数据传输是否正确。
校验码的长度应该根据具体的应用场景和数据传输速率来确定,长度过短可能会导致误判,长度过长则会增加通信开销。同时,不同的校验方法具有不同的校验效率和可靠性,可以根据具体的需求选择合适的校验方法。
常用的校验方法包括奇偶校验、校验和和循环冗余校验(CRC)。
在每个数据字节的最高位或最低位添加一个校验位,使得每个数据字节的1的个数为奇数或偶数,从而检测数据传输过程中是否发生了单个位错误。
假设我们要传输一个8位的二进制数据10110010
public class ParityCheck {
public static boolean checkParity(byte b) {
int ones = 0; // 记录字节中二进制位为1的个数
for (int i = 0; i < 8; i++) {
if (((b >> i) & 1) == 1) {
ones++;
}
}
return ones % 2 == 0; // 如果二进制位为1的个数是偶数,返回true,否则返回false
}
}
将要发送的所有数据字节相加,然后将和的低8位作为校验码发送。接收端也将收到的所有数据字节相加,然后与接收到的校验码相加,如果和的低8位为0,则认为数据传输正确。
假设要对以下4个十六进制数进行校验和计算:0x12, 0x34, 0x56, 0x78。
public class Checksum {
public static short calculateChecksum(byte[] bytes) {
int sum = 0; // 记录所有字节的累加和
for (byte b : bytes) {
sum += b;
}
// 将累加和的高16位和低16位相加,直到高16位为0
while ((sum >> 16) > 0) {
sum = (sum & 0xFFFF) + (sum >> 16);
}
return (short) (~sum & 0xFFFF); // 对累加和取反并截取低16位作为校验和
}
}
是一种基于二进制除法的循环冗余校验方法,使用异或和移位运算,能够检测多达32位的传输错误。
假设需要对数据0x12, 0x34, 0x56, 0x78进行CRC校验,生成多项式为CRC-16多项式0x8005:
/**
* 计算crc校验
*
* @param sendData 发送的数据
* @param length 发送的数据长度
* @return crc校验值
*/
public static int calculateCrc(int[] sendData, int length) {
int crc = 0xffff;
for (int i = 0; i < length; i++) {
int value = sendData[i];
int realValue = value;
if (value < 0) {
realValue += 0x100;
}
crc ^= realValue;
for (int j = 0; j < 8; j++) {
if ((crc & 0x01) > 0) {
crc = (crc >> 1) ^ 0xa001;
} else {
crc = crc >> 1;
}
}
}
return crc;
}
CBC校验的基本原理是将要传输的数据看成一个二进制数,然后进行多项式除法运算。具体来说,CBC校验将数据和一个固定的多项式进行异或运算,然后将异或运算的结果除以另一个固定的多项式,得到余数作为校验码。发送方将数据和校验码一起发送给接收方,接收方同样对收到的数据进行计算,得到校验码,如果两者一致,则说明数据传输正确。
假设需要对数据0x12, 0x34, 0x56, 0x78进行校验,校验码的初始值为0x00:
private static byte calculateCbc(byte[] data) {
byte checksum = 0;
for (int i = 0; i < data.length; i++) {
checksum ^= data[i];
}
return checksum;
}
在串口通信中,数据通常以字节为单位进行传输。有时候,为了保证数据的完整性和正确性,需要在数据中添加一些特殊的字节来进行补位。补位的方式有很多种,下面介绍两种常用的补位方式。
填充字节补位的方式是在数据中插入一个特殊的字节,例如0x00,来进行补位。如果在数据中出现了0x00字节,那么在这个字节前面再插入一个0x01字节。这样,在数据中就不会出现连续的两个0x00字节,避免了数据的混淆。
包长度补位的方式是在数据包头中添加一个指示数据包长度的字段。这个字段通常是一个字节或者两个字节,用来表示数据包的长度。这样,在接收端就可以通过读取数据包头中的长度字段来确定数据包的长度,从而避免了数据的丢失或混淆。
在进行补位时,需要保证发送端和接收端的补位方式相同,否则会导致数据的错误或者丢失。同时,在进行补位时还需要注意数据的效率和实时性,避免过多的数据传输延迟。