串口通信(7)判断数据帧头来接收一串数据

本文为博主 日月同辉,与我共生,csdn原创首发。希望看完后能对你有所帮助,不足之处请指正!一起交流学习,共同进步!

> 发布人:@日月同辉,与我共生_单片机-CSDN博客

> 欢迎你为独创博主日月同辉,与我共生点赞❤❤❤+关注👍+收藏🌹+评论☺。

系列专栏: CSDN-单片机串口通信学习系列🎁

> 我的格言是:"尽最大努力,做最好的自己!💪

要转载,请提前告知!!!

版权声明:本文为CSDN博主「日月同辉,与我共生」的原创文章,CSDN独一份。

目录

一、码元、波特率

1.1码元

1.2波特率

二、数据帧

2.1起始位

2.2停止位

2.3数据-帧头

三、系统设计

3.1设计要求

3.2系统原理

3.3硬件设计

3.3.1串口设计

3.3.2LED电路

3.4软件设计

3.4.1发送数据

3.4.2串口初始化

3.4.3接收中断

3.4.4定时器初始化

3.4.5定时器中断模块

3.4.6处接收数据理模块

四、结果

4.1发送两个字符串

4.2LED灯亮

4.3LED灯灭

一、码元、波特率

1.1码元

用相同时间间隔的符号来表示一个二进制数,一般来说,码元≠比特(1个二进制数相当于1个比特,用1bit表示),例如,有4种状态(0、1、2、3),分别用二进制数表示,即为00、01、10、11,因此1码元=2比特,特殊地,如果是2种状态(0、1),可以用0、1两个二进制数分别表示两种状态,此时1码元=1比特。在串口通信中,每次发送数据都是一个一个地发送,因此串口通信码元=比特。

1.2波特率

单位时间内发送的码元数,称为波特率,单位为b/s。

我们常用9600b/s,每发送1比特需要的时间为1s/9600=104us

二、数据帧

2.1起始位

1位,表示一次通信的开始,给接收器时钟一个同步,告知接收端开始接收数据。

2.2停止位

1位,一次通信的结束。

2.3数据-帧头

串口通信帧头(也称为帧起始标志)是用来标识一个串口通信帧的开始位置的特殊字符。它的作用是让接收端能够正确地识别数据帧的开始位置,以便接收端能够正确地解析整个数据帧。帧头通常是++一个固定的特定字符或字符组合++。

三、系统设计

3.1设计要求

++本次设计,最开始,单片机com1发送Wait for Serial Communication Tset Start.和Please Send a string of data:这两个字符串到虚拟串口com3,然后由虚拟串口com3发送数据给单片机com1,单片机接收数据后能够重新发回给com3。发送的数据由帧头+数据组成,帧头为AA 55 AA 55,数据有2种情况,当数据为01 02时,接P1^0的LED灯亮,当数据为02 01时,接P1^0的LED灯灭,当数据错误时,LED灯无反应(已近亮了无法灭,已近灭的无法亮)。另外,虚拟终端能接收到单片机发送的数据。++

3.2系统原理

串口发送数据不是一次性发送,而是一个一个字符/字节发送。波特率为9600b/s,发送一个比特需要时间要104us,定时器可以定时1ms,若是定时时间超过5ms(规定值,一般是3ms-8ms),则说明接收数据完成,因此可以定义定时计数变量recv_timer_cnt,该变量每+1,定时累加1ms,如果该变量值超过5,则定时超过5ms,则接收完成,每接收一个数据,定时计数变量recv_timer_cnt清0,接收的数据存储到数组recv_buf。

接收完成后要判断数据是否正确并对正确数据进行解析,可以设定一个帧头变量recv_move_index,判断数组recv_buf每一个数据是否正确,有错误的,跳出该判断,将帧头变量+1,然后继续重头判断,直到判断到正确的一串数据或结束,判断到正确的一串数据,就开始对数据进行解析(处理LED)。

3.3硬件设计

3.3.1串口设计

3.3.2LED电路

LED灯采用共阳极接法,左端接电源,右端先接电阻再接到P1^0。

3.4软件设计

3.4.1发送数据

cpp 复制代码
void sendByte(unsigned char dat) //发送一帧数据功能函数
{
	SBUF=dat;
	while(!TI);
	TI=0;
}

void sendString(unsigned char *dat)//发送字符串函数
{
	while(*dat != '\0')
	{
		sendByte(*dat++);
	}
}

3.4.2串口初始化

cpp 复制代码
void UartInit(void)		//9600bps@11.0592MHz
{
	PCON &= 0x7F;		//波特率不倍速
	SCON = 0x50;		//8位数据,可变波特率
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x20;		//设置定时器模式
	TL1 = 0xFD;			//设置定时初始值
	TH1 = 0xFD;			//设置定时重载值
	ET1 = 0;			  //禁止定时器中断
	ES=1;           //串口中断打开
	TR1 = 1;			  //定时器1开始计时
}

3.4.3接收中断

cpp 复制代码
void ES_timers() interrupt 4 //接收中断
{
	if(RI)
	{ 
		RI=0; 
		start_timer=1;//1.开定时器标志位置1
    if(recv_cnt<MAX_REX_NUM)	//在规定字符长度范围内接收数据	
		{
			recv_buf[recv_cnt]=SBUF; //2.接收数据
			recv_cnt++; 
		}
		else
		{
			recv_cnt=MAX_REX_NUM;
		}
		recv_timer_cnt=0; //3.每接收一帧数据就计数清0
	}
}

3.4.4定时器初始化

cpp 复制代码
void Timer0_Init(void)		//1毫秒@11.0592MHz
{
	TMOD &= 0xF0;			//设置定时器模式
	TMOD |= 0x01;			//设置定时器模式
	TL0 = 0x66;				//设置定时初始值
	TH0 = 0xFC;				//设置定时初始值
	TF0 = 0;				//清除TF0标志
	ET0=1;          //定时器0中断打开
	TR0 = 1;				//定时器0开始计时
}

3.4.5定时器中断模块

cpp 复制代码
void T0_timer() interrupt 1 //利用1ms计数,判断是否接收完成
{
	TR0=0;
	if(start_timer == 1)//软件定时器打开
	{
		recv_timer_cnt++;//计数加1
		if(recv_timer_cnt>MAX_timer_cnt) //计数值超过规定范围说明接收完成
	  {
		  recv_timer_cnt=0;//计数重新置0 
		  
		  recv_flag=1;//接收完成标志位置1
	  }
	}
	TL0 = 0x66;				//设置定时初始值
	TH0 = 0xFC;				//设置定时初始值
	TR0=1;
}

3.4.6处接收数据理模块

cpp 复制代码
void uart_service(unsigned char *buf) //完成对接收正确性的判断及相应解析
{
	unsigned char recv_move_index;//帧头变量的定义
	if(recv_flag)//接收完成开始解析
		{
			start_timer=0;//接收完成要关闭软件定时器
			recv_flag=0;//接收完成标志位置0,以便下次接收
			sendString(buf);//发送接收缓冲区的数据
			while((recv_cnt>=6)&&(recv_move_index<=recv_cnt))//数据字节大于等于6,帧头不能超过数据字节
			{
				if((buf[recv_move_index+0]==0xAA)&&(buf[recv_move_index+1]==0x55)&&(buf[recv_move_index+2]==0xAA)&&(buf[recv_move_index+3]==0x55))
					    //满足帧头 AA 55 AA 55
				{
						if((buf[recv_move_index+4]==0x01)&&(buf[recv_move_index+5]==0x02))
							//帧头后数据为01 02时LED亮
						{
							LED=0;
						}
						if((buf[recv_move_index+4]==0x02)&&(buf[recv_move_index+5]==0x01))
							//帧头后数据为02 01时LED灭
						{
							LED=1;
						}
						break;//满足帧头和数据退出while循环
				}
				recv_move_index++;//帧头移动1位
			}
			recv_cnt=0;
            clr_recvbuffer(buf);//清除缓冲函数
		}
}

四、结果

4.1发送两个字符串

4.2LED灯亮

4.3LED灯灭

下一文将着重++串口中断即时解析数据帧头的通信程序++ ,亲爱的读者敬请期待,下一文更精彩!!!

一日不读书,胸臆无佳想。我叫不白吃,喜欢我的,可以支持我,博主名叫 @日月同辉,与我共生

@日月同辉,与我共生_单片机基础,单片机串口通信-CSDN博客@日月同辉,与我共生擅长单片机基础,单片机串口通信,等方面的知识,@日月同辉,与我共生关注stm32,c语言,51单片机,proteus,单片机领域.https://blog.csdn.net/LIN___IT?spm=1000.2115.3001.5343

相关推荐
鸿喵小仙女37 分钟前
C# WPF读写STM32/GD32单片机Flash数据
stm32·单片机·c#·wpf
lucy153027510791 小时前
MCU 功耗基准测试
科技·单片机·嵌入式硬件·智能家居·信号处理·工控主板
汤姆和佩琦2 小时前
2024-12-25-sklearn学习(20)无监督学习-双聚类 料峭春风吹酒醒,微冷,山头斜照却相迎。
学习·聚类·sklearn
m0_748240912 小时前
OpenMV与STM32通信全面指南
stm32·单片机·嵌入式硬件
好学近乎知o2 小时前
正则表达式(学习Django过程中可能涉及的)
学习·正则表达式·django
雨中奔跑的小孩2 小时前
爬虫学习案例8
爬虫·学习
jieshenai2 小时前
使用 VSCode 学习与实践 LaTeX:从插件安装到排版技巧
ide·vscode·学习
Cchengzu4 小时前
阿里巴巴2017实习生笔试题(二)
stm32·单片机·嵌入式硬件
灰太狼不爱写代码5 小时前
CUDA11.4版本的Pytorch下载
人工智能·pytorch·笔记·python·学习
重生之我是数学王子7 小时前
单片机 STM32入门
stm32·单片机·嵌入式硬件