1. 奇偶校验
奇偶校验是检错中比较常见的一种方法。它利用数据中的1的个数作为检错的标志位,若1的个数为奇数个,则错误检测的标志位为1,若1的个数为偶数,则错误检测的标志位为0。在发送端和接收端同时检测奇偶位,若得到相同的结果,则说明数据传输过程无错误发生;若得到不同的结果,则说明数据传输过程中有错误发生,此时下位机可以发送一个错误重传的信号,让上位机再次发送数据。目前网上很多的串口收发工具,不具有奇偶校验功能,所以大多数使用。
2.异或校验又称异或和校验或者BCC校验
BCC check是比较常用的串口数据校验。检验和的概念一般体现在8bit长度的字符数组 ,
注意 :异或校验是异或运算,需要先强制把字符转换成整形数据。
NIOS串口程序异或校验
static void uart_ISR(void)
{
alt_u8 data_temp;
alt_u8 add_temp;
while( !(UART->STATUS.BITS.RRDY));
data_temp = UART->RXDATA.BITS.RECEIVE_DATA;
// uart_send_byte(UART->RXDATA.BITS.RECEIVE_DATA);
if( data_temp == 0x7e &&my_uart.receive_count == 0 )
{
my_uart.receive_buffer[0] =0x7e;
my_uart.receive_count = 1;
}
else if( my_uart.receive_count == 1 )
{
if( data_temp == 0xff)
{
my_uart.receive_buffer[1]= 0xff;
my_uart.receive_count= 2;
}
else
my_uart.receive_count= 0;
}
else if( my_uart.receive_count > 1 && my_uart.receive_count< 8 )
{
my_uart.receive_buffer[my_uart.receive_count++]= data_temp;
if(my_uart.receive_count== 8)
{
add_temp = my_uart.receive_buffer[1]^my_uart.receive_buffer[2]^my_uart.receive_buffer[3]^my_uart.receive_buffer[4]^my_uart.receive_buffer[5];
// uart_send_string(5,my_uart.receive_buffer );
if( my_uart.receive_buffer[6]== add_temp && my_uart.receive_buffer[7] == 0xe7 )
{
my_uart.receive_flag= 1;
}
my_uart.receive_count= 0;
}
}
UART->STATUS.WORD=0;
}
3.和校验又称累加和校验
a.RFC1071源码
unsigned short csum(unsigned char *addr, int count){
register long sum = 0;
while( count > 1 ){
sum += * (unsigned short) addr++;
count -= 2;
}
if( count > 0 )
sum += * (unsigned char *) addr;
while (sum>>16)
sum = (sum & 0xffff) + (sum >> 16);
return ~sum;
}
第一个while循环是做普通加法(2进制补码加法),因为IP包头和TCP整个报文段比较短(没达到2^17数量级),所以不可能导致4字节的sum溢出(unsigned long 一般至少为4字节)).
紧接着的一个判断语句是为了能处理输入数据是奇数个字节的这种情况.再接着的数据循环是实现反码算法(在前面的普通加法得到的数据的基础上),由反码和的高位溢出加到低位的性质,可得到"32位的数据的高位比特移位16
比特,再加上原来的低16比特,不影响最终结果" 这个等价运算,因为sum的最初值(刚开始循环时)可能很大,所以这个等价运算需循环进行,直到sum的高比特(16比特以上)全为0.对于32 位的 sum,
事实上这个运算循环至多只有两轮,所以也有程序直接用两条"sum = (sum & 0xffff) + (sum >> 16);"代
替了整个循环.最后,对和取反返回.
b.对数据长度没限制的实现
unsigned short cksum (struct ip *ip, int len){
long sum = 0;
while ( len >1 ){
sum += *((unsigned short *) ip)++;
if (sum & 8x00000000)
sum = (sum & 0xFFFF) + (sum>> 16)
len -= 2;
}
if ( len )
sum += ( unsigned short ) * (unsignedl char *) ip;
while ( sum >> 16)
sum =(sum & 0xFFFF) + (sum>> 16);
return ~sum;
}
这个实现与前面的一个的最大的不同是对数据的长度没什么限制了,因为它在第一个循环的加法运算中实时检测sum的高位的值,一旦发现其有溢出的危险,就及时运用等价运算关系消除了这个危险.