2021/11/22串行口的相关问题

1.预备知识

原理

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

PART1:

1.简单查询方式实现一帧数据的传送

#include<reg52.h>

void DelayXms(unsigned int xms)
{
	unsigned int i,j;
	for(i=xms;i>0;i--)
		for(j=124;j>0;j--);
}

void UartInit(void)		//4800bps@11.0592MHz
{
	PCON &= 0x7F;		//波特率不倍速
	SCON = 0x50;		//8位数据,可变波特率 SM0 SM1 SM2 REN TB8 RB8 TI RI
	TMOD &= 0x0F;		//设置定时器1模式      0   1   0   1   0   0   0  0
	TMOD |= 0x20;		//设置定时器1为8位自动重载模式
	TL1 = 0xFA;		//设置定时初始值
	TH1 = 0xFA;		//设置定时重载值
	ET1 = 0;		//禁止定时器1中断
	TR1 = 1;		//定时器1开始计时
}

void main()
{
	UartInit();
	while(1)
	{
		//SBUF=0x88;//10位异步串口通信 0 88H 1
		//SBUF='a';//显示的是ASCALL码
		SBUF=55/10+'0';
		while(!TI);
		TI=0;
		DelayXms(1000);
	}
}

稍微改进一下:封装为传递函数sendBytes()

#include<reg52.h>

void DelayXms(unsigned int xms)
{
	unsigned int i,j;
	for(i=xms;i>0;i--)
		for(j=124;j>0;j--);
}
void sentByte(unsigned char dat)
{
	  SBUF=dat;
		while(!TI);
		TI=0;//手动置位
}
 
void UartInit(void)		//4800bps@11.0592MHz
{
	PCON &= 0x7F;		//波特率不倍速
	SCON = 0x50;		//8位数据,可变波特率 SM0 SM1 SM2 REN TB8 RB8 TI RI
	TMOD &= 0x0F;		//设置定时器1模式      0   1   0   1   0   0   0  0
	TMOD |= 0x20;		//设置定时器1为8位自动重载模式
	TL1 = 0xFA;		//设置定时初始值
	TH1 = 0xFA;		//设置定时重载值
	ET1 = 0;		//禁止定时器1中断
	TR1 = 1;		//定时器1开始计时
}

void main()
{
	UartInit();
	while(1)
	{
		sentByte(0x88);
		DelayXms(1000);
	}
}

在这里插入图片描述

2.中断方式实现一帧数据的发送

#include<reg52.h>

void DelayXms(unsigned int xms)
{
	unsigned int i,j;
	for(i=xms;i>0;i--)
		for(j=124;j>0;j--);
}
 
void UartInit(void)		//9600bps@11.0592MHz
{
	SCON = 0x50;		//8位数据,可变波特率
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x20;		//设置定时器模式
	TL1 = 0xFD;		//设置定时初始值
	TH1 = 0xFD;		//设置定时重载值
	ET1 = 0;		//禁止定时器%d中断
	TR1 = 1;		//定时器1开始计时
	ES=1;
	EA=1;
}
void uart_ISR() interrupt 4
{
	if(TI)
	{
		TI=0;
	}
}

void main()
{
	UartInit();
	while(1)
	{
		SBUF=0x88;
		DelayXms(2000);
	}
}

在这里插入图片描述

3.简单查询实现一串数据传输

#include<reg52.h>

void DelayXms(unsigned int xms)
{
	unsigned int i,j;
	for(i=xms;i>0;i--)
		for(j=124;j>0;j--);
}
 
void UartInit(void)		//9600bps@11.0592MHz
{
	SCON = 0x50;		//8位数据,可变波特率
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x20;		//设置定时器模式
	TL1 = 0xFD;		//设置定时初始值
	TH1 = 0xFD;		//设置定时重载值
	ET1 = 0;		//禁止定时器%d中断
	TR1 = 1;		//定时器1开始计时
}
void sentByte(unsigned char dat)
{
	  SBUF=dat;
		while(!TI);
		TI=0;//手动置位
}
void sentString(unsigned char *dat)
{
	while(*dat!='\0')
	{
		sentByte(*dat++);
	}
}
void main()
{
	UartInit();
	while(1)
	{
//		sentByte('8');
//		sentByte('\r');//回车
//		sentByte('\n');//换行
		sentString("Hello World!\r\n");
		DelayXms(1000);
	}
}

在这里插入图片描述

4.重定向printf

首先了解C语言51单片机里面的printf不同数据类型输出格式

#include <stdio.h>

void tst_printf (void) {
  char a = 1;
  int b  = 12365;
  long c = 0x7FFFFFFF;

  unsigned char x = 'A';
  unsigned int y  = 54321;
  unsigned long z = 0x4A6F6E00;

  float f = 10.0;
  float g = 22.95;

  char buf [] = "Test String";
  char *p = buf;

  printf ("char %bd int %d long %ld\n",a,b,c);
  printf ("Uchar %bu Uint %u Ulong %lu\n",x,y,z);
  printf ("xchar %bx xint %x xlong %lx\n",x,y,z);
  printf ("String %s is at address %p\n",buf,p);
  printf ("%f != %g\n", f, g);
  printf ("%*f != %*g\n", (int)8, f, (int)8, g);
}

正式开始

#include<reg52.h>
#include<stdio.h>
void DelayXms(unsigned int xms)
{
	unsigned int i,j;
	for(i=xms;i>0;i--)
		for(j=124;j>0;j--);
}
 
void UartInit(void)		//9600bps@11.0592MHz
{
	SCON = 0x50;		//8位数据,可变波特率
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x20;		//设置定时器模式
	TL1 = 0xFD;		//设置定时初始值
	TH1 = 0xFD;		//设置定时重载值
	ET1 = 0;		//禁止定时器%d中断
	TR1 = 1;		//定时器1开始计时
}
void sentByte(unsigned char dat)
{
	  SBUF=dat;
		while(!TI);
		TI=0;//手动置位
}
void sentString(unsigned char *dat)
{
	while(*dat!='\0')
	{
		sentByte(*dat++);
	}
}
char putchar(char c)
{
	sentByte(c);
	return c;	
}
void main()
{
	unsigned char dat=88;
	UartInit();
	while(1)
	{
//		sentByte('8');
//		sentByte('\r');//回车
//		sentByte('\n');//换行
		//sentString("Hello World!\r\n");
		printf("Hello World!\r\n");
		printf("dat=%bu\r\n",dat);
		DelayXms(1000);
	}
}

在这里插入图片描述

PART 2:

1. 单片机串行口从上位机接受数据帧

#include<reg52.h>
#include<stdio.h>
unsigned char recv_data;
//void DelayXms(unsigned int xms)
//{
//	unsigned int i,j;
//	for(i=xms;i>0;i--)
//		for(j=124;j>0;j--);
//}
 
void UartInit(void)		//9600bps@11.0592MHz
{
	SCON = 0x50;		//8位数据,可变波特率
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x20;		//设置定时器模式
	TL1 = 0xFD;		//设置定时初始值
	TH1 = 0xFD;		//设置定时重载值
	ET1 = 0;		//禁止定时器%d中断
	ES=1;
	EA=1;
	TR1 = 1;		//定时器1开始计时
}

void uart_ISR() interrupt 4
{
	if(RI)
	{
		RI=0;
		recv_data=SBUF;//接收数据
		recv_data=recv_data+1;
		SBUF=recv_data;//重新发送数据
	}
	if(TI)
	{
		TI=0;
	}
}
//void sentByte(unsigned char dat)
//{
//	  SBUF=dat;
//		while(!TI);
//		TI=0;//手动置位
//}
//void sentString(unsigned char *dat)
//{
//	while(*dat!='\0')
//	{
//		sentByte(*dat++);
//	}
//}
//char putchar(char c)
//{
//	sentByte(c);
//	return c;	
//}
void main()
{
	UartInit();
	while(1)
	{
	}
}

在这里插入图片描述

传送一帧数据改进(拓展一下):

#include<reg52.h>
#include<stdio.h>
unsigned char recv_data;
unsigned char recv_flag=0;
//void DelayXms(unsigned int xms)
//{
	//unsigned int i,j;
	//for(i=xms;i>0;i--)
		//for(j=124;j>0;j--);
//}
 
void UartInit(void)		//9600bps@11.0592MHz
{
	SCON = 0x50;		//8位数据,可变波特率
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x20;		//设置定时器模式
	TL1 = 0xFD;		//设置定时初始值
	TH1 = 0xFD;		//设置定时重载值
	ET1 = 0;		//禁止定时器%d中断
	ES=1;
	EA=1;
	TR1 = 1;		//定时器1开始计时
}

void uart_ISR() interrupt 4
{
	if(RI)
	{
		RI=0;
		recv_data=SBUF;//接收数据
		recv_flag=1;
//		recv_data=recv_data+1;
//		SBUF=recv_data;//发送数据
	}
	if(TI)
	{
		TI=0;
	}
}
void sentByte(unsigned char dat)
{
	  SBUF=dat;
		while(!TI);
		TI=0;//手动置位
}
//void sentString(unsigned char *dat)
//{
//	while(*dat!='\0')
//	{
//		sentByte(*dat++);
//	}
//}
char putchar(char c)
{
	sentByte(c);
	return c;	
}
void main()
{
	UartInit();
	printf("Waitfor Serial Communication Test Strat.\r\n");
	printf("Please Send a  frame of data:\r\n");
	while(1)
	{
		if(recv_flag==1)
		{
			recv_flag=0;
			recv_data=recv_data+1;
			sentByte(recv_data);
			printf("\r\n");
			printf("%bd\r\n",recv_data);
		}
	}
}

在这里插入图片描述

简单实现串行口输入控制LED点亮

#include<reg52.h>
#include<stdio.h>
unsigned char recv_data;
unsigned char recv_flag=0;
sbit LED1=P1^0;
sbit LED2=P1^1;
sbit LED3=P1^2;
sbit LED4=P1^3;
void DelayXms(unsigned int xms)
{
	unsigned int i,j;
	for(i=xms;i>0;i--)
		for(j=124;j>0;j--);
}
 
void UartInit(void)		//9600bps@11.0592MHz
{
	SCON = 0x50;		//8位数据,可变波特率
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x20;		//设置定时器模式
	TL1 = 0xFD;		//设置定时初始值
	TH1 = 0xFD;		//设置定时重载值
	ET1 = 0;		//禁止定时器%d中断
	ES=1;
	EA=1;
	TR1 = 1;		//定时器1开始计时
}

void uart_ISR() interrupt 4
{
	if(RI)
	{
		RI=0;
		recv_data=SBUF;//接收数据
		recv_flag=1;
//		recv_data=recv_data+1;
//		SBUF=recv_data;//发送数据
	}
	if(TI)
	{
		TI=0;
	}
}
void sentByte(unsigned char dat)
{
	  SBUF=dat;
		while(!TI);
		TI=0;//手动置位
}
//void sentString(unsigned char *dat)
//{
//	while(*dat!='\0')
//	{
//		sentByte(*dat++);
//	}
//}
char putchar(char c)
{
	sentByte(c);
	return c;	
}
void main()
{
	UartInit();
	printf("Waitfor Serial Communication Test Strat.\r\n");
	printf("Please Send a  command:\r\n");
	while(1)
	{
		if(recv_flag==1)
		{
			recv_flag=0;
			switch(recv_data)
			{
				case 0x1:LED1=0;break;
				case 0x2:LED2=0;break;
				case 0x3:LED3=0;break;
				case 0x4:LED4=0;break;
				default:break;
			}
		}
	}
}

在这里插入图片描述

在这里插入图片描述

简单实现串口数据从上位机接受一串固定长度数据(长度已知)

#include<reg52.h>
#include<stdio.h>
#define MAX_REV_NUM 10
unsigned char recv_data;
unsigned char recv_flag=0;
unsigned char recv_buf[MAX_REV_NUM];
//void DelayXms(unsigned int xms)
//{
//	unsigned int i,j;
//	for(i=xms;i>0;i--)
//		for(j=124;j>0;j--);
//}
// 
void UartInit(void)		//9600bps@11.0592MHz
{
	SCON = 0x50;		//8位数据,可变波特率
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x20;		//设置定时器模式
	TL1 = 0xFD;		//设置定时初始值
	TH1 = 0xFD;		//设置定时重载值
	ET1 = 0;		//禁止定时器%d中断
	ES=1;
	EA=1;
	TR1 = 1;		//定时器1开始计时
}

void uart_ISR() interrupt 4
{
	static unsigned char recv_cnt=0;
	if(RI)
	{
		RI=0;
		recv_buf[recv_cnt]=SBUF;
		recv_cnt++;
		if(recv_cnt==8)//固定长度的
		{
			recv_flag=1;
			recv_cnt=0;
		}
	}
}
void sentByte(unsigned char dat)
{
	  SBUF=dat;
		while(!TI);
		TI=0;//手动置位
}
void sentString(unsigned char *dat)
{
	while(*dat!='\0')
	{
		sentByte(*dat++);
	}
}
char putchar(char c)
{
	sentByte(c);
	return c;	
}
void main()
{
	UartInit();
	printf("Waitfor Serial Communication Test Strat.\r\n");
	printf("Please Send a  command:\r\n");
	while(1)
	{
		if(recv_flag==1)
		{
			recv_flag=0;
			sentString(recv_buf);
		}
	}
}

在这里插入图片描述

简单实现串口数据从上位机接受一串不固定长度数据(长度不固定)(缺点:当0D 作为数据是传不过去的,因为会被认为是结束符号,可以选一个不常用的符号,另外包括结束符在内的数据长度需要<=缓冲区长度)

#include<reg52.h>
#include<stdio.h>
#define MAX_REV_NUM 15
#define REV_CNT 10
unsigned char recv_data;
unsigned char recv_flag=0;
unsigned char recv_length;
unsigned char recv_buf[MAX_REV_NUM];
//void DelayXms(unsigned int xms)
//{
//	unsigned int i,j;
//	for(i=xms;i>0;i--)
//		for(j=124;j>0;j--);
//}
// 
void UartInit(void)		//9600bps@11.0592MHz
{
	SCON = 0x50;		//8位数据,可变波特率
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x20;		//设置定时器模式
	TL1 = 0xFD;		//设置定时初始值
	TH1 = 0xFD;		//设置定时重载值
	ET1 = 0;		//禁止定时器%d中断
	ES=1;
	EA=1;
	TR1 = 1;		//定时器1开始计时
}

void uart_ISR() interrupt 4
{
	static unsigned char recv_cnt=0;
	unsigned char temp;
	if(RI)
	{
		RI=0;
		temp=SBUF;
		if(temp!=0x0D)//是否为回车符
		{
			recv_buf[recv_cnt]=temp;
			recv_cnt++;
			if(recv_cnt>MAX_REV_NUM)
			{
				recv_cnt=MAX_REV_NUM;
			}
			else
			{
				recv_flag=1;
				recv_length=recv_cnt;
				recv_cnt=0;
			}
		}
	}
}
void sentByte(unsigned char dat)
{
	  SBUF=dat;
		while(!TI);
		TI=0;//手动置位
}
void sentString(unsigned char *dat)
{
	while(*dat!='\0')
	{
		sentByte(*dat++);
	}
}
char putchar(char c)
{
	sentByte(c);
	return c;	
}
void main()
{
	unsigned char i;
	UartInit();
	printf("Waitfor Serial Communication Test Strat.\r\n");
	printf("Please Send a  command:\r\n");
	while(1)
	{
		if(recv_flag==1)
		{
			recv_flag=0;
			//sentString(recv_buf);
			for(i=0;i<recv_length;i++)
			{
				sentByte(recv_buf[i]);
			}
		}
	}
}

在这里插入图片描述

Part3:串口+定时器超时检测实现接收一串数据

#include<reg52.h>
#include<stdio.h>
#define MAX_REV_NUM 20
#define REV_CNT 10
#define MAX_REV_TIME 5
unsigned char recv_flag=0;
unsigned char recv_timer_cnt;
unsigned char start_timer=0;
unsigned char recv_cnt;
unsigned char recv_buf[MAX_REV_NUM];
//void DelayXms(unsigned int xms)
//{
//	unsigned int i,j;
//	for(i=xms;i>0;i--)
//		for(j=124;j>0;j--);
//}
// 
//串口初始化和串口中断服务函数
void UartInit(void)		//9600bps@11.0592MHz
{
	SCON = 0x50;		//8位数据,可变波特率
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x20;		//设置定时器模式
	TL1 = 0xFD;		//设置定时初始值
	TH1 = 0xFD;		//设置定时重载值
	ET1 = 0;		//禁止定时器%d中断
	ES=1;
	TR1 = 1;		//定时器1开始计时
}

void uart_ISR() interrupt 4
{
	//static unsigned char recv_cnt=0;
	if(RI)
	{
		RI=0;
		start_timer=1;//1.每接收第一帧数据的时候,打开软件定时器去计数
		if(recv_cnt<MAX_REV_NUM)
		{
			recv_buf[recv_cnt]=SBUF;//2.接收数据到数据缓冲区,注意缓冲区的大小范围问题
			recv_cnt++;
		}
		else
		{
			recv_cnt=MAX_REV_NUM;
		}
		recv_timer_cnt=0;//3.每接收一帧数据,记得把定时计数器清零,相当于信号                 //但是在定时中断里面会不断累加
	}
	if(TI)
	{
		TI=0;
	}
}
/**************************************************/
/**************************************************/


//定时器0的初始化和中断服务函数
void Timer0Init(void)		//1毫秒@11.0592MHz
{
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x66;		//设置定时初始值
	TH0 = 0xFC;		//设置定时初始值
	TF0 = 0;		//清除TF0标志
	ET0=1;
	TR0 = 1;		//定时器0开始计时
}
void timer0_ISR() interrupt 1
{
	TR0=0;
	if(start_timer==1)
	{
		recv_timer_cnt++;//1.累加定时时间计算器
		if(recv_timer_cnt>MAX_REV_TIME)//2.判断定时时间是否超过约定的最大阈值,超过则说明等待一段时间后没有新的数据到			                              
		{  			我们判断一包数据接收完毕
			recv_timer_cnt=0;//3.清除定时计数器,处理数据,清除buffer(放到数据处理之后)
			recv_cnt=0;
			recv_flag=1;
		}
	}
	TL0 = 0x66;		//设置定时初始值
	TH0 = 0xFC;		//设置定时初始值
	TR0=1;
}
/**************************************************/
/**************************************************/


//传一位数据
void sentByte(unsigned char dat)
{
	  SBUF=dat;
		while(!TI);
		TI=0;//手动置位
}
/**************************************************/
/**************************************************/


//传一串数据
void sentString(unsigned char *dat)
{
	while(*dat!='\0')
	{
		sentByte(*dat++);
	}
}
/**************************************************/
/**************************************************/


//printf重定向
char putchar(char c)
{
	sentByte(c);
	return c;	
}
/**************************************************/
/**************************************************/


//清除缓冲区
void clr_recvbuffer(unsigned char *buf)
{
	unsigned char i;
	for(i=0;i<MAX_REV_NUM;i++)
	{
		buf[i]=0;
	}
}
/**************************************************/
/**************************************************/


/*主函数*/
void main()
{
	Timer0Init();
	UartInit();
	EA=1;
	printf("Waitfor Serial Communication Test Strat.\r\n");
	printf("Please Send a  command:\r\n");
	while(1)
	{
	  if(recv_flag)
		{
			recv_flag=0;
			start_timer=0;//关掉定时器
			sentString(recv_buf);//处理数据
			clr_recvbuffer(recv_buf);//清除缓冲buffer
		}
	}
}

在这里插入代码片

在这里插入图片描述
在这里插入图片描述

判读数据帧头来接收一串数据的串口通信程序编写

#include<reg52.h>
#include<stdio.h>
#define MAX_REV_NUM 20
#define REV_CNT 10
#define MAX_REV_TIME 5
sbit LED=P1^0;
unsigned char recv_flag=0;
unsigned char recv_timer_cnt;
unsigned char start_timer=0;
unsigned char recv_cnt;
unsigned char recv_buf[MAX_REV_NUM];
//void DelayXms(unsigned int xms)
//{
//	unsigned int i,j;
//	for(i=xms;i>0;i--)
//		for(j=124;j>0;j--);
//}
// 
//串口初始化和串口中断服务函数
void UartInit(void)		//9600bps@11.0592MHz
{
	SCON = 0x50;		//8位数据,可变波特率
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x20;		//设置定时器模式
	TL1 = 0xFD;		//设置定时初始值
	TH1 = 0xFD;		//设置定时重载值
	ET1 = 0;		//禁止定时器%d中断
	ES=1;
	TR1 = 1;		//定时器1开始计时
}

void uart_ISR() interrupt 4
{
	//static unsigned char recv_cnt=0;
	if(RI)
	{
		RI=0;
		start_timer=1;//1.每接收第一帧数据的时候,打开软件定时器去计数
		if(recv_cnt<MAX_REV_NUM)
		{
			recv_buf[recv_cnt]=SBUF;//2.接收数据到数据缓冲区,注意缓冲区的大小范围问题
			recv_cnt++;
		}
		else
		{
			recv_cnt=MAX_REV_NUM;
		}
		recv_timer_cnt=0;//3.每接收一帧数据,记得把定时计数器清零,相当于信号                 //但是在定时中断里面会不断累加
	}
	if(TI)
	{
		TI=0;
	}
}
/**************************************************/
/**************************************************/


//定时器0的初始化和中断服务函数
void Timer0Init(void)		//1毫秒@11.0592MHz
{
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x66;		//设置定时初始值
	TH0 = 0xFC;		//设置定时初始值
	TF0 = 0;		//清除TF0标志
	ET0=1;
	TR0 = 1;		//定时器0开始计时
}
void timer0_ISR() interrupt 1
{
	TR0=0;
	if(start_timer==1)
	{
		recv_timer_cnt++;//1.累加定时时间计算器
		if(recv_timer_cnt>MAX_REV_TIME)//2.判断定时时间是否超过约定的最大阈值,超过则说明等待一段时间后没有新的数据到			                              
		{  			我们判断一包数据接收完毕
			recv_timer_cnt=0;//3.清除定时计数器,处理数据,清除buffer(放到数据处理之后)
			//recv_cnt=0;
			recv_flag=1;
		}
	}
	TL0 = 0x66;		//设置定时初始值
	TH0 = 0xFC;		//设置定时初始值
	TR0=1;
}
/**************************************************/
/**************************************************/


//传一位数据
void sentByte(unsigned char dat)
{
	  SBUF=dat;
		while(!TI);
		TI=0;//手动置位
}
/**************************************************/
/**************************************************/


//传一串数据
void sentString(unsigned char *dat)
{
	while(*dat!='\0')
	{
		sentByte(*dat++);
	}
}
/**************************************************/
/**************************************************/


//printf重定向
char putchar(char c)
{
	sentByte(c);
	return c;	
}
/**************************************************/
/**************************************************/


//清除缓冲区
void clr_recvbuffer(unsigned char *buf)
{
	unsigned char i;
	for(i=0;i<MAX_REV_NUM;i++)
	{
		buf[i]=0;
	}
}
/**************************************************/
/**************************************************/
void uart_service(unsigned char *buf)
{
	unsigned char recv_move_index;
	if(recv_flag)
		{
			recv_flag=0;
			start_timer=0;//关掉定时器
			sentString(buf);//处理数据
      while((recv_cnt>=5)&&(recv_move_index<=recv_cnt))
			{
				if((buf[recv_move_index+0]==0x55)&&(buf[recv_move_index+1]==0xAA)&&(buf[recv_move_index+2]==0x55))
				{
					if((buf[recv_move_index+3]==0x01)&&(buf[recv_move_index+4]==0x02))
					{
						LED=0;
						break;
					}
					if((buf[recv_move_index+3]==0x02)&&(buf[recv_move_index+4]==0x01))
					{
						LED=1;
						break;
					}
				}
			}
			recv_cnt=0;
			clr_recvbuffer(recv_buf);//清除缓冲buffer
		}
}

/*主函数*/
void main()
{
	Timer0Init();
	UartInit();
	EA=1;
	printf("Waitfor Serial Communication Test Strat.\r\n");
	printf("Please Send a  command:\r\n");
	while(1)
	{
		uart_service(recv_buf);
	}
}

在这里插入图片描述

串口中断中即时解析数据帧头的通信程序(<帧头>AA 55 +01或02+两位数据+0D<帧尾>)

#include<reg52.h>
#include<stdio.h>
#define MAX_REV_NUM 20
#define REV_CNT 10
#define MAX_REV_TIME 5
sbit LED=P1^0;
sbit BUZZER=P3^7;
unsigned char recv_flag=0;
unsigned char recv_timer_cnt;
unsigned char start_timer=0;
unsigned char recv_cnt;
unsigned char machine_step;
unsigned char recv_buf[MAX_REV_NUM];
unsigned int led_data;
unsigned int beep_data;
unsigned int led_cnt;
unsigned int beep_cnt;
void DelayXms(unsigned int xms)
{
	unsigned int i,j;
	for(i=xms;i>0;i--)
		for(j=124;j>0;j--);
}
 
//串口初始化和串口中断服务函数
void UartInit(void)		//9600bps@11.0592MHz
{
	SCON = 0x50;		//8位数据,可变波特率
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x20;		//设置定时器模式
	TL1 = 0xFD;		//设置定时初始值
	TH1 = 0xFD;		//设置定时重载值
	ET1 = 0;		//禁止定时器%d中断
	ES=1;
	TR1 = 1;		//定时器1开始计时
}

void uart_ISR() interrupt 4
{
	
	if(RI)
	{
		RI=0;
		switch(machine_step)
		{
			case 0:recv_buf[0]=SBUF;
			  if(recv_buf[0]==0xAA)
				{
					machine_step=1;
				}
				else
				{
					machine_step=0;
				}
			  break;
			case 1:recv_buf[1]=SBUF;
				if(recv_buf[1]==0x55)
				{
					machine_step=2;
					recv_cnt=2;
				}
				else
				{
					machine_step=0;
				}
			  break;
			case 2:recv_buf[recv_cnt]=SBUF;
				recv_cnt++;
				if(recv_cnt>4)
				{
					machine_step=3;
				}
				else
				{
					machine_step=2;
				}
				break;
			case 3:recv_buf[recv_cnt]=SBUF;
				if(recv_buf[recv_cnt]==0x0D)
				{
					switch(recv_buf[2])
					{
						case 1:led_data=recv_buf[3];
						       led_data=led_data<<8;
						       led_data=led_data+recv_buf[4];
						       led_cnt=0;//目的是使得LED点亮上述接收数据时间
						       break;
						case 2:beep_data=recv_buf[3];
						       beep_data=beep_data<<8;
						       beep_data=beep_data+recv_buf[4];
						       beep_cnt=beep_data;
						       break;
						default:break;
					}
					machine_step=0;
					recv_cnt=0;
					recv_flag=1;//接收完一串数据,标志为1
				}
				break;
			default:break;	
		}
	}
	if(TI)
	{
		TI=0;
	}
}
/**************************************************/
/**************************************************/


//定时器0的初始化和中断服务函数
void Timer0Init(void)		//1毫秒@11.0592MHz
{
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x66;		//设置定时初始值
	TH0 = 0xFC;		//设置定时初始值
	TF0 = 0;		//清除TF0标志
	ET0=1;
	TR0 = 1;		//定时器0开始计时
}
void timer0_ISR() interrupt 1
{
	TR0=0;
	if(led_cnt<led_data)
	{
		led_cnt++;
		LED=0;
	}
	else{
		LED=1;
	}
	if(beep_cnt!=0)
	{
		beep_cnt--;
		BUZZER=~BUZZER;
	}

	TL0 = 0x66;		//设置定时初始值
	TH0 = 0xFC;		//设置定时初始值
	TR0=1;
}
/**************************************************/
/**************************************************/


//传一位数据
void sentByte(unsigned char dat)
{
	  SBUF=dat;
		while(!TI);
		TI=0;//手动置位
}
/**************************************************/
/**************************************************/


//传一串数据
void sentString(unsigned char *dat)
{
	while(*dat!='\0')
	{
		sentByte(*dat++);
	}
}
/**************************************************/
/**************************************************/


//printf重定向
char putchar(char c)
{
	sentByte(c);
	return c;	
}
/**************************************************/
/**************************************************/


//清除缓冲区
void clr_recvbuffer(unsigned char *buf)
{
	unsigned char i;
	for(i=0;i<MAX_REV_NUM;i++)
	{
		buf[i]=0;
	}
}
/**************************************************/
/**************************************************/



/*主函数*/
void main()
{
	Timer0Init();
	UartInit();
	EA=1;
	printf("Waitfor Serial Communication Test Strat.\r\n");
	printf("Please Send a  command:\r\n");
	DelayXms(10);
	BUZZER=0;
	while(1)
	{
		if(recv_flag==1)
		{
			recv_flag=0;
			sentString(recv_buf);
			clr_recvbuffer(recv_buf);
		}
	}
}

在这里插入图片描述
在这里插入图片描述

Part 3:串口中断即时解析用户自定义通讯协议(接收数据字节固定)的编程实现(固定长度)

点击这里可以进行校验的计算

#include<reg52.h>
#include<stdio.h>
#define MAX_REV_NUM 20
#define REV_CNT 10
#define MAX_REV_TIME 5
sbit LED=P1^0;
sbit BUZZER=P3^7;
unsigned char recv_flag=0;
unsigned char recv_timer_cnt;
unsigned char start_timer=0;
unsigned char recv_cnt;
unsigned char machine_step;
unsigned char recv_buf[MAX_REV_NUM];
unsigned int led_data;
unsigned int beep_data;
unsigned int led_cnt;
unsigned int beep_cnt;
void DelayXms(unsigned int xms)
{
	unsigned int i,j;
	for(i=xms;i>0;i--)
		for(j=124;j>0;j--);
}
/**************************************************/
/**************************************************/


//传一位数据
void sentByte(unsigned char dat)
{
	  SBUF=dat;
		while(!TI);
		TI=0;//手动置位
}
/**************************************************/
/**************************************************/

 
//printf重定向
char putchar(char c)
{
	sentByte(c);
	return c;	
}
/**************************************************/
/**************************************************/


//传一串数据
void sentString(unsigned char *dat)
{
	while(*dat!='\0')
	{
		sentByte(*dat++);
	}
}



/**************************************************/
/**************************************************/


//清除缓冲区
void clr_recvbuffer(unsigned char *buf)
{
	unsigned char i;
	for(i=0;i<MAX_REV_NUM;i++)
	{
		buf[i]=0;
	}
}
/**************************************************/
/**************************************************/

//串口初始化和串口中断服务函数
void UartInit(void)		//9600bps@11.0592MHz
{
	SCON = 0x50;		//8位数据,可变波特率
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x20;		//设置定时器模式
	TL1 = 0xFD;		//设置定时初始值
	TH1 = 0xFD;		//设置定时重载值
	ET1 = 0;		//禁止定时器%d中断
	ES=1;
	TR1 = 1;		//定时器1开始计时
}

void uart_ISR() interrupt 4
{
	
	unsigned char recv_data;//接收数据的中间变量
	static unsigned char sum_check;
	static unsigned char xor_check;
	if(RI)
	{
		RI=0;
		recv_data=SBUF; 
		
		switch(machine_step)
		{
			case 0:
			  if(recv_data==0x55)
				{
					machine_step=1;
					sentByte('A');
					
				}
				else
				{
					machine_step=0;
				}
			  break;
			case 1:
				if(recv_data==0xAA)
				{
					machine_step=2;
					sentByte('A');
					recv_cnt=0;
				}
				else
				{
					machine_step=0;
				}
			  break;
			case 2://开始和校验,异或校验
				sum_check+=recv_data;
			  xor_check^=recv_data;
			  recv_buf[recv_cnt]=recv_data;
				recv_cnt++;
			  sentByte('A');
				if(recv_cnt>2)//数据固定长度,可以手动设置
				{
					machine_step=3;
				}
				else
				{
					machine_step=2;
				}
				break;
			case 3:
				  if(sum_check==recv_data)//和校验正确
					{
						machine_step=4;
					}
					else
					{
						machine_step=0;
						printf("SUM CHECK ERROR!\r\n");
					}
					break;
			case 4:
				  if(xor_check==recv_data)//异或校验正确
					{
						recv_flag=1;//正确接收一串数据
						sentByte('A');
					}
					else
					{
						printf("XOR CHECK ERROR!\r\n");
					}
					machine_step=0;
					recv_cnt=0;
          sum_check=0;
					xor_check=0;
				break;
			default:break;	
		}
	}
	if(TI)
	{
		TI=0;
	}
}
/**************************************************/
/**************************************************/


//定时器0的初始化和中断服务函数
void Timer0Init(void)		//1毫秒@11.0592MHz
{
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x66;		//设置定时初始值
	TH0 = 0xFC;		//设置定时初始值
	TF0 = 0;		//清除TF0标志
	ET0=1;
	TR0 = 1;		//定时器0开始计时
}
void timer0_ISR() interrupt 1
{
	TR0=0;
	if(led_cnt<led_data)
	{
		led_cnt++;
		LED=0;
	}
	else{
		LED=1;
	}
	if(beep_cnt!=0)
	{
		beep_cnt--;
		BUZZER=~BUZZER;
	}

	TL0 = 0x66;		//设置定时初始值
	TH0 = 0xFC;		//设置定时初始值
	TR0=1;
}


/*主函数*/
void main()
{
	Timer0Init();
	UartInit();
	EA=1;
	printf("Waitfor Serial Communication Test Strat.\r\n");
	printf("Please Send a  command:\r\n");
	DelayXms(10);
	BUZZER=0;
	while(1)
	{
		if(recv_flag==1)
		{
			recv_flag=0;
			sentString(recv_buf);
      switch(recv_buf[0])
			{
					case 1:led_data=recv_buf[1];
						     led_data=led_data<<8;
						     led_data=led_data+recv_buf[2];
						     led_cnt=0;//目的是使得LED点亮上述接收数据时间
						     break;
				  case 2:beep_data=recv_buf[1];
						     beep_data=beep_data<<8;
						     beep_data=beep_data+recv_buf[2];
						     beep_cnt=beep_data;
						     break;
				 default:
					 	clr_recvbuffer(recv_buf);
				 break;
			}
		}
	}
}

在这里插入图片描述

串口中断即时解析用户自定义通讯协议(协议内带字节长度及接收应答处理)的编程实现

#include<reg52.h>
#include<stdio.h>
#define MAX_REV_NUM 20
#define REV_CNT 10
#define MAX_REV_TIME 5
sbit LED=P1^0;
sbit BUZZER=P3^7;
#define GPIO_DIG P0  //断码IO口
#define GPIO_PLACE P2  //位选IO口
#define N  4           //数码管个数
unsigned char LEDBUF[]={0,0,0,0};//数据显示缓冲区
unsigned char code PLACE_CODE[]={0x01,0x02,0x04,0x08};//位信号
unsigned char recv_flag=0;
unsigned char recv_timer_cnt;
unsigned char start_timer=0;
unsigned char recv_cnt;
unsigned char machine_step;
unsigned char recv_buf[MAX_REV_NUM];
unsigned char recv_length;
unsigned char code recv_correct[]={0x55,0xAA,0x80,0x0,0x80,0x80};
unsigned char code sum_check_error[]={0x55,0xAA,0x81,0x0,0x81,0x81};
unsigned char code xor_check_error[]={0x55,0xAA,0x82,0x0,0x82,0x82};
unsigned char leddata[]={ 

						0xC0,  //"0"
						0xF9,  //"1"
						0xA4,  //"2"
						0xB0,  //"3"
						0x99,  //"4"
						0x92,  //"5"
						0x82,  //"6"
						0xF8,  //"7"
						0x80,  //"8"
						0x90,  //"9"
						0x88,  //"A"
						0x83,  //"B"
						0xC6,  //"C"
						0xA1,  //"D"
						0x86,  //"E"
						0x8E,  //"F"
						0x89,  //"H"
						0xC7,  //"L"
						0xC8,  //"n"
						0xC1,  //"u"
						0x8C,  //"P"
						0xA3,  //"o"
						0xBF,  //"-"
						0xFF,  //熄灭
};
/**************************************************/
/**************************************************/


void DelayXms(unsigned int xms)
{
	unsigned int i,j;
	for(i=xms;i>0;i--)
		for(j=124;j>0;j--);
}
/**************************************************/
/**************************************************/


void Display()
{
	 unsigned char i;
	//unsigned char i;
	//1,送段码
	
	//2.送位选
	
	//3.延时1ms<10ms
	
	//4.消隐
	switch(i)
	{
		case 0:
		  GPIO_DIG=leddata[LEDBUF[0]];
		  GPIO_PLACE=PLACE_CODE[0];
		  DelayXms(1);
		  GPIO_DIG=0xff;
		  i++;
		  break;
			
		case 1:
		  GPIO_DIG=leddata[LEDBUF[1]];
		  GPIO_PLACE=PLACE_CODE[1];
		  DelayXms(1);
		  GPIO_DIG=0xff;
		  i++;
		  break;
			
		case 2:
		  GPIO_DIG=leddata[LEDBUF[2]];
		  GPIO_PLACE=PLACE_CODE[2];
		  DelayXms(1);
		  GPIO_DIG=0xff;
		  i++;
		  break;
			
		case 3:
		  GPIO_DIG=leddata[LEDBUF[3]];
		  GPIO_PLACE=PLACE_CODE[3];
		  DelayXms(1);
		  GPIO_DIG=0xff;
		  i=0;
		  break;	
		default:break;
	}
}

//传一位数据
void sentByte(unsigned char dat)
{
	  SBUF=dat;
		while(!TI);
		TI=0;//手动置位
}
/**************************************************/
/**************************************************/

 
//printf重定向
char putchar(char c)
{
	sentByte(c);
	return c;	
}
/**************************************************/
/**************************************************/


//传一串数据
void sentString(unsigned char *dat)
{
	while(*dat!='\0')
	{
		sentByte(*dat++);
	}
}
/**************************************************/
/**************************************************/


//清除缓冲区
void clr_recvbuffer(unsigned char *buf)
{
	unsigned char i;
	for(i=0;i<MAX_REV_NUM;i++)
	{
		buf[i]=0;
	}
}
/**************************************************/
/**************************************************/

//串口初始化和串口中断服务函数
void UartInit(void)		//9600bps@11.0592MHz
{
	SCON = 0x50;		//8位数据,可变波特率
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x20;		//设置定时器模式
	TL1 = 0xFD;		//设置定时初始值
	TH1 = 0xFD;		//设置定时重载值
	ET1 = 0;		//禁止定时器%d中断
	ES=1;
	TR1 = 1;		//定时器1开始计时
}

void uart_ISR() interrupt 4
{
	
	unsigned char i;
	unsigned char recv_data;//接收数据的中间变量
	static unsigned char sum_check;
	static unsigned char xor_check;
	if(RI)
	{
		RI=0;
		recv_data=SBUF; 
		
		switch(machine_step)
		{
			case 0:
			  if(recv_data==0x55)
				{
					machine_step=1;
					
				}
				else
				{
					machine_step=0;
				}
			  break;
			case 1:
				if(recv_data==0xAA)
				{
					machine_step=2;
					recv_cnt=0;
				}
				else
				{
					machine_step=0;
				}
			  break;
			case 2://开始和校验,异或校验
				sum_check=recv_data;
			  xor_check=recv_data;
			  recv_buf[recv_cnt]=recv_data;
				recv_cnt++;
				machine_step=3;
				break;
			case 3:
				  sum_check+=recv_data;
			    xor_check^=recv_data;
				  recv_length=recv_data;
			    machine_step=4;
					break;
			case 4:
				  sum_check+=recv_data;
			    xor_check^=recv_data;
			    recv_buf[recv_cnt]=recv_data;
			    if(recv_cnt>=recv_length)
					{
						machine_step=5;
					}
					else
					{
						machine_step=4;
					}
					recv_cnt++;
					break;
			case 5:
				  if(sum_check==recv_data)
					{
						machine_step=6;
					}
					else
					{
						machine_step=0;
						for(i=0;i<6;i++)
						{
							sentByte(sum_check_error[i]);
						}
					}
				break;
			case 6:
				  if(xor_check==recv_data)
					{
						recv_flag=1;//正确接收一串数据
						for(i=0;i<6;i++)
						{
							sentByte(recv_correct[i]);
						}
					}
					else{
						for(i=0;i<6;i++)
						{
							sentByte(xor_check_error[i]);
						}
					}
					machine_step=0;
					recv_cnt=0;
					sum_check=0;
					xor_check=0;
					break;
		  default:break;	
		}
	}
	if(TI)
	{
		TI=0;
	}
}
/**************************************************/
/**************************************************/


//定时器0的初始化和中断服务函数
void Timer0Init(void)		//1毫秒@11.0592MHz
{
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x66;		//设置定时初始值
	TH0 = 0xFC;		//设置定时初始值
	TF0 = 0;		//清除TF0标志
	ET0=1;
	TR0 = 1;		//定时器0开始计时
}
void timer0_ISR() interrupt 1
{
	TR0=0;
	Display();
	TL0 = 0x66;		//设置定时初始值
	TH0 = 0xFC;		//设置定时初始值
	TR0=1;
}


/*主函数*/
void main()
{
	Timer0Init();
	UartInit();
	EA=1;
	printf("Waitfor Serial Communication Test Strat.\r\n");
	printf("Please Send a  command:\r\n");
	DelayXms(10);
	BUZZER=0;
	while(1)
	{
		if(recv_flag==1)
		{
			recv_flag=0;
			switch(recv_buf[0])
			{
				case 1:
					LEDBUF[0]=23;
				  LEDBUF[1]=23;
				  LEDBUF[2]=recv_buf[1]>>4;
				  LEDBUF[3]=recv_buf[1]&0x0F;
					break;
				case 2:
					LEDBUF[0]=recv_buf[1]>>4;
				  LEDBUF[1]=recv_buf[1]&0x0F;
				  LEDBUF[2]=recv_buf[2]>>4;
				  LEDBUF[3]=recv_buf[2]&0x0F;
					break;
				case 3:
					LEDBUF[0]=recv_buf[1]>>4;
				  LEDBUF[1]=recv_buf[1]&0x0F;
				  LEDBUF[2]=recv_buf[2]>>4;
				  LEDBUF[3]=recv_buf[2]&0x0F;
					break;
				default:break;
			}
     
		}
	}
}

在这里插入图片描述

在这里插入图片描述

#include<reg52.h>
#include<stdio.h>
unsigned char recv_data;
unsigned char recv_flag=0;
unsigned char *H=0x30;
unsigned char *Q=0x40;
//void DelayXms(unsigned int xms)
//{
	//unsigned int i,j;
	//for(i=xms;i>0;i--)
		//for(j=124;j>0;j--);
//}
 
void UartInit(void)		//9600bps@11.0592MHz
{
	SCON = 0x50;		//8位数据,可变波特率
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x20;		//设置定时器模式
	TL1 = 0xFD;		//设置定时初始值
	TH1 = 0xFD;		//设置定时重载值
	ET1 = 0;		//禁止定时器%d中断
	ES=1;
	EA=1;
	TR1 = 1;		//定时器1开始计时
}

void uart_ISR() interrupt 4
{
	if(RI)
	{
		RI=0;
		if(0xAA==SBUF)
		{
			while(H<=0x3F)
			{
				SBUF=*H;
				H++;
				while(!TI);
				TI=0;
			}
			H=0x30;
		}
		else if(0xE0==SBUF)
		{
			while(Q<=0x5F)
			{
				SBUF=*Q;
				Q++;
				while(!TI);
				TI=0;
			}
			Q=0x40;
		}
		else{
      recv_data=SBUF;//接收数据
      SBUF=recv_data;//发送数据
		}
		recv_flag=1;
	}
	if(TI)
	{
		TI=0;
	}
}
void sentByte(unsigned char dat)
{
	  SBUF=dat;
		while(!TI);
		TI=0;//手动置位
}
void sentString(unsigned char *dat)
{
	while(*dat!='\0')
	{
		sentByte(*dat++);
	}
}
char putchar(char c)
{
	sentByte(c);
	return c;	
}
void main()
{
	UartInit();
	sentString("Hello Server!\r\n");
	printf("Waitfor Serial Communication Test Strat.\r\n");
	printf("Please Send a  frame of data:\r\n");
	while(1)
	{
		if(recv_flag==1)
		{
			recv_flag=0;
			//sentByte(recv_data);
		}
	}
}

在这里插入图片描述

拓展:循环冗余校验

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值