收发数据包+数据校验
1、和校验+异或校验
和校验:将接收到的数据全部相加后,取结果的最后一个字节的数据
异或校验:将接收到的数据全部相异或后,取结果的最后一个字节的数据
在线计算和校验/异或校验工具:链接: link
例如:
对 0x33 0x56 0x14 0x32 这4个数据求和校验数据为:0xCF
对 0x33 0x56 0x14 0x32 这4个数据求异或校验数据为:0x43
1.1、HEX固定长度数据包校验
创建工程名为29_UART_Send_Receive_CheckFixedPage
①UART.c文件的代码如下
c
#include "UART.h"
/**
* 串口初始化
* 参数:波特率
*/
void UART_Init(unsigned int Baud)
{
/* 串口寄存器的配置 */
PCON &= 0x3F; //PCON = 00xx xxxx
SCON &= 0x0F;
SCON |= 0x50; //SCON = 0101 xxxx
/* 配置T1的寄存器 */
TMOD &= 0x0F;
TMOD |= 0x20; //TOMD = 0010 xxxx:8位自动重装载
TH1 = 256 - (28800/Baud);//配置波特率
TL1 = 256 - (28800/Baud);//配置波特率
ET1 = 0; //关闭T1溢出中断
TR1 = 1; //使能T1
/* 使能串口中断 */
ES = 1; //使能串口中断
EA = 1; //使能中断总开关
}
/**
* 发送一个字节的数据
*/
void Send_Char(unsigned char ch)
{
SBUF = ch; //给SBUF写入一个字节数据
while(!TI); //等待数据发送完成(未完成TI = 0,完成TI = 1)
TI = 0; //手动清0
}
/**
* 发送多个字节的数据
*/
void Send_Array(unsigned char* Array,unsigned char Len)
{
unsigned char i;
for(i = 0; i<Len; i++)
{
Send_Char(*(Array+i));
}
}
/**
* 发送字符串
*/
void Send_String(unsigned char* str)
{
while(*str != '\0')
{
Send_Char(*str++);
}
}
/**
* 对printf函数进行重定向
*/
char putchar(char ch)
{
Send_Char(ch);
return ch;
}
/***********中断服务函数*************/
/**
* 中断服务函数:接收固定长度为4的HEX数据包,且进行和校验与异或校验
* HEX数据包格式:0xFF x x x x 和校验字符 异或校验字符 0xFE
*/
unsigned char Buffer[BUFF_Len]; //固定数据包缓存区
unsigned char Index = 0; //缓存区索引
unsigned char Receive_Flag = 0; //接收完成标志
void UART_Routine(void) interrupt 4
{
static unsigned char Status = 0; //状态机变量
static unsigned char Sum_Check = 0; //和校验变量
static unsigned char X0r_Check = 0; //异或校验变量
unsigned char ReceiveData; //暂存数据变量
/* 若是发送完成中断:TI = 1*/
if(TI)
{
//一般情况下不使用你中断进行发送数据
TI = 0;
}
/* 若接收数据完成中断 RI = 1*/
if(RI && !Receive_Flag) //Receive_Flag = 0表示上一次接收的数据处理完成
{
RI = 0;
ReceiveData = SBUF;
switch(Status)
{
case 0: //判断帧头0xFF
if(ReceiveData == 0xFF)
{
Status = 1;//改变状态变量
Index = 0;
}
else
{
Status = 0;
}
break;
case 1: //接收数据
Sum_Check += ReceiveData; //每接收到一个字节的数据就计算出和校验字符
X0r_Check ^= ReceiveData; //每接收到一个字节的数据就计算出异或校验字符
Buffer[Index++] = ReceiveData;
if(Index >= BUFF_Len) //接收到4个数据帧
{
Status = 2; //改变状态变量
}
break;
case 2: //进行和校验比对
if(Sum_Check == ReceiveData)
{
Status = 3;
}
else //进行和校验比对,校验比对失败
{
Send_Char(0XE0);//返回发送0xE0
Status = 0;
memset(Buffer,0,4);//清空数据包缓存区
}
Sum_Check = 0;//和校验变量清零
break;
case 3: //进行异或校验比对
if(X0r_Check == ReceiveData)//异或校验比对成功
{
Status = 4;
}
else
{
Send_Char(0XE1);//返回发送0xE1
Status = 0;
memset(Buffer,0,4);//清空数据包缓存区
}
X0r_Check = 0;//和校验变量清零
break;
case 4: //判断帧尾部
if(ReceiveData == 0xFE)
{
Receive_Flag = 1; //接收完成
}
else
{
memset(Buffer,0,4);//清空数据包缓存区
}
Status = 0; //将状态变量置0,便于下次数据包的接收
break;
default:break;
}
}
}
②UART.h文件的代码如下
c
#ifndef __UART_H
#define __UART_H
#include <REGX52.H> //包含51头文件,里面全是寄存器地址
#include <string.h>
#include <stdio.h>
#define BUFF_Len 4 //数据缓存区长度
void UART_Init(unsigned int Baud);
void Send_Char(unsigned char ch);//发送一个字节的数据
void Send_Array(unsigned char* Array,unsigned char Len);//发送多个字节的数据
void Send_String(unsigned char* str);//发送字符串
char putchar(char ch);//printf()重定向
extern unsigned char Buffer[BUFF_Len]; //固定数据包缓存区
extern unsigned char Receive_Flag;
extern unsigned char Index;
#endif
③main.c文件的代码如下
c
#include "UART.h"
void main(void)
{
UART_Init(9600); //9600波特率
printf("Code Runing\r\n");
while(1)
{
if(Receive_Flag) //Receive_Flag = 1,数据接收完成
{
Receive_Flag = 0;
Send_Array(Buffer,Index);//将数据发送出去
}
}
}

1.2、HEX不固定长度数据包校验
创建工程名为30_UART_Send_Receive_CheckChangePage
①UART.c文件的代码如下
c
#include "UART.h"
/**
* 串口初始化
* 参数:波特率
*/
void UART_Init(unsigned int Baud)
{
/* 串口寄存器的配置 */
PCON &= 0x3F; //PCON = 00xx xxxx
SCON &= 0x0F;
SCON |= 0x50; //SCON = 0101 xxxx
/* 配置T1的寄存器 */
TMOD &= 0x0F;
TMOD |= 0x20; //TOMD = 0010 xxxx:8位自动重装载
TH1 = 256 - (28800/Baud);//配置波特率
TL1 = 256 - (28800/Baud);//配置波特率
ET1 = 0; //关闭T1溢出中断
TR1 = 1; //使能T1
/* 使能串口中断 */
ES = 1; //使能串口中断
EA = 1; //使能中断总开关
}
/**
* 发送一个字节的数据
*/
void Send_Char(unsigned char ch)
{
SBUF = ch; //给SBUF写入一个字节数据
while(!TI); //等待数据发送完成(未完成TI = 0,完成TI = 1)
TI = 0; //手动清0
}
/**
* 发送多个字节的数据
*/
void Send_Array(unsigned char* Array,unsigned char Len)
{
unsigned char i;
for(i = 0; i<Len; i++)
{
Send_Char(*(Array+i));
}
}
/**
* 发送字符串
*/
void Send_String(unsigned char* str)
{
while(*str != '\0')
{
Send_Char(*str++);
}
}
/**
* 对printf函数进行重定向
*/
char putchar(char ch)
{
Send_Char(ch);
return ch;
}
/***********中断服务函数*************/
/**
* 中断服务函数:接收不固定长度的HEX数据包,且进行和校验与异或校验
* HEX数据包格式:0xFF x x x x 和校验字符 异或校验字符 0xFE
*/
unsigned char Buffer[BUFF_Len]; //固定数据包缓存区
unsigned char Index = 0; //缓存区索引
unsigned char Receive_Flag = 0; //接收完成标志
void UART_Routine(void) interrupt 4
{
static unsigned char Status = 0; //状态机变量
static unsigned char Sum_Check = 0; //和校验变量
static unsigned char X0r_Check = 0; //异或校验变量
unsigned char ReceiveData; //暂存数据变量
/* 若是发送完成中断:TI = 1*/
if(TI)
{
//一般情况下不使用你中断进行发送数据
TI = 0;
}
/* 若接收数据完成中断 RI = 1*/
if(RI && !Receive_Flag)
{
RI = 0;
ReceiveData = SBUF;
/* 使用状态机对数据包进行处理 */
switch(Status) //Receive_Flag = 0表示上一次接收的数据处理完成
{
case 0:
if(ReceiveData == 0xFF) //是帧头0xFF
{
Index = 0;
Status = 1; //改变状态变量
}
else
{
Status = 0; //不是帧头
}
break;
case 1:
if(ReceiveData == 0xFE) //判断是否为帧尾
{
Sum_Check -= Buffer[Index-1];
Sum_Check -= Buffer[Index-2];
X0r_Check ^= Buffer[Index-1];
X0r_Check ^= Buffer[Index-2];
/* 和校验与异或校验比对 */
if(Sum_Check == Buffer[Index-2]) //进行和校验比对
{
if(X0r_Check == Buffer[Index-1]) //进行异或校验比对
{
Index -= 2;
Receive_Flag = 1; //将标志位置1
}
else
{
Send_Char(0xE1); //返回发送0xE1
memset(Buffer,0,BUFF_Len); //清空数据包缓存区
}
}
else
{
Send_Char(0xE0); //返回发送0xE0
memset(Buffer,0,BUFF_Len); //清空数据包缓存区
}
Sum_Check = 0; //和校验变量置0
X0r_Check = 0; //异或校验变量置0
Status = 0; //将状态变量置0,便于下次数据包的接收
}
else//不是帧尾,接收数据
{
Sum_Check += ReceiveData; //每接收到一个字节的数据就计算出和校验字符
X0r_Check ^= ReceiveData; //每接收到一个字节的数据就计算出异或校验字符
Buffer[Index++] = ReceiveData; //对数据进行处理
}
break;
default:break;
}
}
}
②UART.h文件的代码如下
c
#ifndef __UART_H
#define __UART_H
#include <REGX52.H> //包含51头文件,里面全是寄存器地址
#include <string.h>
#include <stdio.h>
#define BUFF_Len 4 //数据缓存区长度
void UART_Init(unsigned int Baud);
void Send_Char(unsigned char ch);//发送一个字节的数据
void Send_Array(unsigned char* Array,unsigned char Len);//发送多个字节的数据
void Send_String(unsigned char* str);//发送字符串
char putchar(char ch);//printf()重定向
extern unsigned char Buffer[BUFF_Len]; //固定数据包缓存区
extern unsigned char Receive_Flag;
extern unsigned char Index;
#endif
③main.c文件的代码如下
c
#include "UART.h"
void main(void)
{
UART_Init(9600); //9600波特率
printf("Code Runing\r\n");
while(1)
{
if(Receive_Flag) //Receive_Flag = 1,数据接收完成
{
Receive_Flag = 0;
Send_Array(Buffer,Index);//将数据发送出去
}
}
}

2、CRC校验
在线CRC校验工具:链接: link