1、数据包
我们使用上位机个单片机发送数据包时,规定包头和包尾,将我们需要发送的数据放在中间,数据的长度我们也可以自己规定。一般情况下HEX数据包我们使用固定长度数据包。而文本数据包使用是可变长度数据包。
2、HEX数据包
2.1、HEX固定数据包收发
①UART.c文件的代码如下
/**
* 串口初始化,且开启中断
* 参数:波特率
*/
void UART_It_Init(unsigned int Baud)
{
/* 串口寄存器的配置 */
PCON &= 0x3F; //PCON = 00xx xxxx
SCON &= 0x0F;
SCON |= 0x50; //SCON = 0101 xxxx
/* 配置T1的寄存器 */
TMOD &= 0x0F;
TMOD |= 0x20; //TOMD = 0010 xxxx
TH1 = 256 - (28800/Baud);//配置波特率
TL1 = 256 - (28800/Baud);//配置波特率
ET1 = 0; //关闭T1溢出中断
TR1 = 1; //使能T1
/* 使能串口中断 */
ES = 1; //使能串口中断
EA = 1; //使能中断总开关
}
/***********中断服务函数*************/
/**
* 中断服务函数
*/
unsigned char Buffer[BUFF_Len]; //固定数据包缓存区
unsigned char Index = 0; //缓存区索引
unsigned char Flag2 = 0;
void UART_Routine(void) interrupt 4
{
static unsigned char Status = 0;//状态机变量
unsigned char ReceiveData;
/* 若接收数据完成中断 RI = 1*/
if(RI)
{
RI = 0;
ReceiveData = SBUF;
/* 使用状态机对数据包进行处理 */
switch(Status)
{
case 0:
if(ReceiveData == 0xFF)//是帧头0xFF
{
Status = 1;//改变状态变量
Index = 0;
}
else
{
Status = 0;//不是帧头
}
break;
case 1:
Buffer[Index++] = ReceiveData;//接收数据
if(Index >= BUFF_Len)
{
Status = 2;//改变状态变量
}
break;
case 2:
if(ReceiveData == 0xFE)//判断是否位帧尾0xFE
{
Flag2 = 1;//将标志位置1
}
else
{
memset(Buffer,0,4);//清空数据包缓存区
}
Status = 0;
break;
}
}
}
②UART.h文件的代码如下
#ifndef __UART_H
#define __UART_H
#include <reg51.h> //包含51头文件,里面全是寄存器地址
#include <stdio.h>
#include <string.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()重定向
void UART_It_Init(unsigned int Baud);//串口初始化(使能中断)
extern unsigned char Buffer[BUFF_Len];
extern unsigned char Flag2;
#endif
③main.c文件的代码如下
#include "UART.h"
void main(void)
{
UART_It_Init(9600); //9600波特率
while(1)
{
if(Flag2) //Flag = 1,数据处理完成
{
Flag2 = 0;
Send_Array(Buffer,BUFF_Len);//将数据发送出去
}
}
}
2.2、HEX可变数据包收发
①UART.c文件的代码如下
/**
* 串口初始化,且开启中断
* 参数:波特率
*/
void UART_It_Init(unsigned int Baud)
{
/* 串口寄存器的配置 */
PCON &= 0x3F; //PCON = 00xx xxxx
SCON &= 0x0F;
SCON |= 0x50; //SCON = 0101 xxxx
/* 配置T1的寄存器 */
TMOD &= 0x0F;
TMOD |= 0x20; //TOMD = 0010 xxxx
TH1 = 256 - (28800/Baud);//配置波特率
TL1 = 256 - (28800/Baud);//配置波特率
ET1 = 0; //关闭T1溢出中断
TR1 = 1; //使能T1
/* 使能串口中断 */
ES = 1; //使能串口中断
EA = 1; //使能中断总开关
}
/***********中断服务函数*************/
/**
* 中断服务函数
*/
unsigned char Buffer[BUFF_Len]; //固定数据包缓存区
unsigned char Index = 0; //缓存区索引
unsigned char Flag2 = 0;
void UART_Routine(void) interrupt 4
{
static unsigned char Status = 0;//状态机变量
unsigned char ReceiveData;
/* 若接收数据完成中断 RI = 1*/
if(RI)
{
RI = 0;
ReceiveData = SBUF;
/* 使用状态机对数据包进行处理 */
switch(Status)
{
case 0:
if(ReceiveData == 0xFF)//是帧头0xFF
{
Status = 1; //改变状态变量
Index = 0;
}
else
{
Status = 0; //不是帧头
}
break;
case 1:
if(ReceiveData == 0xFE)//判断是否为帧尾
{
Status = 0; //改变状态变量
Flag2 = 1; //将标志位置1
}
else//不是帧尾
{
Buffer[Index++] = ReceiveData;//对数据进行处理
}
break;
}
}
}
②UART.h文件的代码如下
#ifndef __UART_H
#define __UART_H
#include <reg51.h> //包含51头文件,里面全是寄存器地址
#include <stdio.h>
#include <string.h>
#define BUFF_Len 10
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()重定向
void UART_It_Init(unsigned int Baud);//串口初始化(使能中断)
extern unsigned char Buffer[BUFF_Len];
extern unsigned char Flag2;
extern unsigned char Index;
#endif
③main.c文件的代码如下
#include "UART.h"
void main(void)
{
UART_It_Init(9600); //9600波特率
while(1)
{
if(Flag2) //Flag = 1,数据处理完成
{
Flag2 = 0;
Send_Array(Buffer,Index);//将数据发送出去
}
}
}
3、文本数据包
3.1、文本定长数据包收发
①UART.c文件的代码如下
/**
* 串口初始化,且开启中断
* 参数:波特率
*/
void UART_It_Init(unsigned int Baud)
{
/* 串口寄存器的配置 */
PCON &= 0x3F; //PCON = 00xx xxxx
SCON &= 0x0F;
SCON |= 0x50; //SCON = 0101 xxxx
/* 配置T1的寄存器 */
TMOD &= 0x0F;
TMOD |= 0x20; //TOMD = 0010 xxxx
TH1 = 256 - (28800/Baud);//配置波特率
TL1 = 256 - (28800/Baud);//配置波特率
ET1 = 0; //关闭T1溢出中断
TR1 = 1; //使能T1
/* 使能串口中断 */
ES = 1; //使能串口中断
EA = 1; //使能中断总开关
}
/***********中断服务函数*************/
/**
* 中断服务函数
*/
unsigned char Buffer[BUFF_Len]; //固定数据包缓存区
unsigned char Index = 0; //缓存区索引
unsigned char Flag2 = 0;
void UART_Routine(void) interrupt 4
{
static unsigned char Status = 0;//状态机变量
unsigned char ReceiveData;
/* 若接收数据完成中断 RI = 1*/
if(RI)
{
RI = 0;
ReceiveData = SBUF;
/* 使用状态机对数据包进行处理 */
switch(Status)
{
case 0:
if(ReceiveData == '@')//是帧头'@'
{
Status = 1; //改变状态变量
Index = 0;
}
else
{
Status = 0; //不是帧头
}
break;
case 1:
Buffer[Index++] = ReceiveData;//对数据进行处理
if(Index >= 4)
{
Status = 2;
}
break;
case 2:
//判断是否为'\r'
if(ReceiveData == '\r')
{
Status = 3;
}
else
{
Status = 0;
memset(Buffer,0,4);//将缓冲区的数据清空
}
break;
case 3:
//判断是否为'\n'
if(ReceiveData == '\n')
{
Flag2 = 1;
}
else
{
memset(Buffer,0,4);//将缓冲区的数据清空
}
Status = 0;
break;
}
}
}
②UART.h文件的代码如下
#ifndef __UART_H
#define __UART_H
#include <reg51.h> //包含51头文件,里面全是寄存器地址
#include <stdio.h>
#include <string.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()重定向
void UART_It_Init(unsigned int Baud);//串口初始化(使能中断)
extern unsigned char Buffer[BUFF_Len];
extern unsigned char Flag2;
extern unsigned char Index;
#endif
③main.c文件的代码如下
#include "UART.h"
void main(void)
{
UART_It_Init(9600); //9600波特率
while(1)
{
if(Flag2) //Flag = 1,数据处理完成
{
Flag2 = 0;
Send_Array(Buffer,Index);//将数据发送出去
}
}
}
3.2、文本变长数据包收发
①UART.c文件的代码如下
/**
* 串口初始化,且开启中断
* 参数:波特率
*/
void UART_It_Init(unsigned int Baud)
{
/* 串口寄存器的配置 */
PCON &= 0x3F; //PCON = 00xx xxxx
SCON &= 0x0F;
SCON |= 0x50; //SCON = 0101 xxxx
/* 配置T1的寄存器 */
TMOD &= 0x0F;
TMOD |= 0x20; //TOMD = 0010 xxxx
TH1 = 256 - (28800/Baud);//配置波特率
TL1 = 256 - (28800/Baud);//配置波特率
ET1 = 0; //关闭T1溢出中断
TR1 = 1; //使能T1
/* 使能串口中断 */
ES = 1; //使能串口中断
EA = 1; //使能中断总开关
}
/***********中断服务函数*************/
/**
* 中断服务函数
*/
unsigned char Buffer[BUFF_Len]; //固定数据包缓存区
unsigned char Index = 0; //缓存区索引
unsigned char Flag2 = 0;
void UART_Routine(void) interrupt 4
{
static unsigned char Status = 0;//状态机变量
unsigned char ReceiveData;
/* 若接收数据完成中断 RI = 1*/
if(RI)
{
RI = 0;
ReceiveData = SBUF;
/* 使用状态机对数据包进行处理 */
switch(Status)
{
case 0:
if(ReceiveData == '@')//是帧头'@'
{
Status = 1; //改变状态变量
Index = 0;
}
else
{
Status = 0; //不是帧头
}
break;
case 1:
if(ReceiveData == '\r')//接收的数据为\r,那么判断第二个数据是否为\n
{
Status = 2;//状态置2
}
else
{
Buffer[Index++] = ReceiveData;//对数据进行处理
}
break;
case 2:
if(ReceiveData == '\n')//若再次接收的数据是\n
{
Flag2 = 1;//则代表接收结束
Buffer[Index++] = '\0';//给接收到的数据添加结束符
Status = 0; //准备第二轮的接收
}
else//若数据不是\n
{
Buffer[Index++] = '\r';//将上一次的\r存储在缓冲区中
Buffer[Index++] = ReceiveData;//将这一次接收到的数据存储在缓冲区中
Status = 1;//状态置1
}
break;
}
}
}
②UART.h文件的代码如下
#ifndef __UART_H
#define __UART_H
#include <reg51.h> //包含51头文件,里面全是寄存器地址
#include <stdio.h>
#include <string.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()重定向
void UART_It_Init(unsigned int Baud);//串口初始化(使能中断)
extern unsigned char Buffer[BUFF_Len];
extern unsigned char Flag2;
extern unsigned char Index;
#endif
③main.c文件的代码如下
#include "UART.h"
void main(void)
{
UART_It_Init(9600); //9600波特率
while(1)
{
if(Flag2) //Flag = 1,数据处理完成
{
Flag2 = 0;
Send_String(Buffer);//将数据发送出去
}
}
}
4、定时器中断超时数据包收发
通过定时器中断计数延时来判断数据包是否完整。通过判断接收到数据包后面的超时时间,来辨别数据包是否接受完整。例如:规定数据包的间隔为10ms。上位机发送4个字节的数据包。单片机接受到4个字节后,通过定时器中断计数,若在10ms后没有在接受到数据,那么这个数据包就是4个字节的数据。时间的间隔 > 1/波特率 * 数据帧位个数
①UART.c文件的代码如下
/**
* 串口初始化,且开启中断
* 参数:波特率
*/
void UART_It_Init(unsigned int Baud)
{
/* 串口寄存器的配置 */
PCON &= 0x3F; //PCON = 00xx xxxx
SCON &= 0x0F;
SCON |= 0x50; //SCON = 0101 xxxx
/* 配置T1的寄存器 */
TMOD &= 0x0F;
TMOD |= 0x20; //TOMD = 0010 xxxx
TH1 = 256 - (28800/Baud);//配置波特率
TL1 = 256 - (28800/Baud);//配置波特率
ET1 = 0; //关闭T1溢出中断
TR1 = 1; //使能T1
/* 使能串口中断 */
ES = 1; //使能串口中断
EA = 1; //使能中断总开关
}
/***********中断服务函数*************/
/**
* 中断服务函数
*/
unsigned char Buffer[BUFF_Len]; //固定数据包缓存区
unsigned char Index = 0; //缓存区索引
unsigned char Flag2 = 0;
unsigned char start_time = 0;
unsigned char time_cnt = 0;
void UART_Routine(void) interrupt 4
{
unsigned char ReceiveData;
/* 若接收数据完成中断 RI = 1*/
if(RI)
{
start_time = 1;//打开软件定时器开始计数
RI = 0;
Buffer[Index++] = SBUF;//对数据进行处理
if(Index >= BUFF_Len)//数据缓存区满了
{
Index = BUFF_Len;
}
time_cnt = 0;//接收一位数据,让它置0,不让定时器中断让它变大
}
}
②UART.h文件的代码如下
#ifndef __UART_H
#define __UART_H
#include <reg51.h> //包含51头文件,里面全是寄存器地址
#include <stdio.h>
#include <string.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()重定向
void UART_It_Init(unsigned int Baud);//串口初始化(使能中断)
extern unsigned char Buffer[BUFF_Len];
extern unsigned char Flag2;
extern unsigned char Index;
#endif
③time.c文件的代码如下
#include "Time.h"
/**
* 定时器T0的初始化,且开启中断
*/
void Time0It_Init(void)
{
/* 设置T0的计数器为16,且时钟来源为晶振 TMOD = xxxx 0001 */
TMOD &= 0xF0; //将低4位置0
TMOD |= 0x01; //最低位置1
/* 设置定时计数器的初始值,定时1ms */
TH0 = ((65536 - 1000) >> 8);
TL0 = (65536 - 1000) & 0x00FF;
/* 启动T0 */
TF0 = 0; //清除标志位
TR0 = 1;
/* 开启中断 */
ET0 = 1; //使能定时器溢出中断
EA = 1; //开启总开关
}
/********中断服务函数*******/
/**
* T0的中断服务函数
*/
extern unsigned char Flag2;
extern unsigned char start_time;
extern unsigned char time_cnt;
void Time0_Rountine(void) interrupt 1
{
//这里不用清除标志位,硬件会自动清除
TH0 = ((65536 - 1000) >> 8);
TL0 = (65536 - 1000) & 0x00FF;
if(start_time == 1)//表示串口开始接收数据
{
time_cnt++;
if(time_cnt >= 10)//表示串口没有在接收数据了
{
start_time = 0;//关闭软件定时器
time_cnt = 0;
Flag2 = 1;
}
}
}
④main.c文件的代码如下
#include "UART.h"
#include "Time.h"
void main(void)
{
UART_It_Init(9600); //9600波特率
Time0It_Init();
while(1)
{
if(Flag2) //Flag = 1,数据处理完成
{
Flag2 = 0;
Send_Array(Buffer,Index);//将数据发送出去
Index = 0;
memset(Buffer,0,Index);//清除缓存区
}
}
}