串口数据帧

本文介绍了一种基于STM32平台的串口通信数据帧解析方法,通过使用中断服务函数来处理特定格式的数据帧,并详细说明了如何通过判断帧头、帧尾以及数据长度来确定数据的有效性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

任务要求

在这里插入图片描述

思路

1 a5 01 b4 有效01
2 a5 a5/b4 b4 有效a5/b4
3 01 b4 a5 01 报错
4 a5 01 02 b4 报错
5 随机无效 a5 01 b4 随机无效 有效01

有效数据就是你需要得到的有用数据
帧头 帧尾是固定的
无效数据就是不符合帧头+有效数据+帧尾三字节格式的
一个字节是十进制0~255也就是十六进制0x00到0xff
一串任意长度的数据,只要里面有三个字节是 帧头+一字节数据+帧尾 那就是有效数据
数据长度不匹配,帧头或帧尾不匹配,都是无效数据
再给大家一些方向,串口的中断服务函数每当串口接收到一个字节的时候就会被调用一次,每次中断获取一个字节,但是任务要求判断一个多字节的数据帧,所以必然需要把接收到的数据先保存起来
使用静态变量static或者全局变量来临时保存数据,必须使用中断,学有余力可以使用dma
查询式串口接收毫无意义

主要使用的串口是usart1 28-33
在这里插入图片描述
使用的是30-31
TX发送端口 RX接受端口
查询中断 disable
在这里插入图片描述
在这里插入图片描述
enable
在这里插入图片描述
想要接受多组数据需要定义一个数组,然后把数据一次放入数组中

现在只能实现前四种情况:

完成代码:

main.c

int main (void){//主程序
delay_ms(500); //上电时等待其他器件就绪
	RCC_Configuration(); //系统时钟初始化 
//	RELAY_Init();//继电器初始化

	I2C_Configuration();//I2C初始化
	OLED0561_Init(); //OLED初始化
	OLED_DISPLAY_8x16_BUFFER(0,"   YoungTalk    "); //显示字符串
//	OLED_DISPLAY_8x16_BUFFER(3,"   True   "); //显示字符串

	
	LED_Init();//LED初始化
	
	USART1_Init(115200); //串口初始化,参数中写波特率
	USART1_RX_STA=0xC000; //初始值设为有回车的状态,即显示一次欢迎词
	while(1){
		if(USART1_RX_STA&0xC000){ //如果标志位是0xC000表示收到数据串完成,可以处理。
			if((USART1_RX_STA&0x3FFF)==0){ //单独的回车键再显示一次欢迎词
				printf("\033[1;47;33m\r\n"); //设置颜色(参考超级终端使用)
//				printf(" 1y--开LED1灯      1n--关LED1灯 \r\n");
//				printf(" 2y--开LED2灯      2n--关LED2灯 \r\n");
				printf(" 请输入控制指令,按回车键执行! \033[0m\r\n");
			}else if((USART1_RX_STA&0x3FFF)==6 && USART1_RX_BUF[0]=='5' && USART1_RX_BUF[1]=='a'&&USART1_RX_BUF[4]=='b'&&USART1_RX_BUF[5]=='4'){ //判断数据是不是2个,第一个数据是不是“1”,第二个是不是“y”
				OLED_DISPLAY_8x16_BUFFER(1,"  TRUE:");
	
		OLED_DISPLAY_8x16(1,8*8,USART1_RX_BUF[0]);//显示有效数据
		OLED_DISPLAY_8x16(1,9*8,USART1_RX_BUF[1]);//
		OLED_DISPLAY_8x16(1,10*8,USART1_RX_BUF[2]);//
		OLED_DISPLAY_8x16(1,11*8,USART1_RX_BUF[3]);//
		OLED_DISPLAY_8x16(1,12*8,USART1_RX_BUF[4]);//
		OLED_DISPLAY_8x16(1,13*8,USART1_RX_BUF[5]);//
		
				printf("命令有效!\r\n");
			

			}else{ //如果以上都不是,即是错误的指令。
			   	OLED_DISPLAY_8x16_BUFFER(1,"  FALSE:          ");
	
				printf("指令错误!\r\n"); 
			}
			USART1_RX_STA=0; //将串口数据标志位清0
		}
	}
}

此方法只是把三个字节的长度固定,然后把第一个和最后一个做头帧尾帧处理,如果不符合数据长度以及头尾匹配的,都是错误的。
中断函数用了原有的判断回车

中断里面是原有的判断回车的,因为洋桃视频里就是用了超级终端,他没有发送键所以是需要判断回车,所以用其他的串口助手因为有发送键所以需要有发送新行来判断是否有回车

usart.c

void USART1_IRQHandler(void){ //串口1中断服务程序(固定的函数名不能修改)	
	u8 Res;
	//以下是字符串接收到USART_RX_BUF[]的程序,(USART_RX_STA&0x3FFF)是数据的长度(不包括回车)
	//当(USART_RX_STA&0xC000)为真时表示数据接收完成,即超级终端里按下回车键。
	//在主函数里写判断if(USART_RX_STA&0xC000),然后读USART_RX_BUF[]数组,读到0x0d 0x0a即是结束。
	//注意在主函数处理完串口数据后,要将USART_RX_STA清0
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET){  //接收中断(接收到的数据必须是0x0d 0x0a结尾)		
		Res =USART_ReceiveData(USART1);//(USART1->DR);	//读取接收到的数据
		printf("%c",Res); //把收到的数据以 a符号变量 发送回电脑		
		if((USART1_RX_STA&0x8000)==0){//接收未完成			
			if(USART1_RX_STA&0x4000){//接收到了0x0d				
				if(Res!=0x0a)USART1_RX_STA=0;//接收错误,重新开始
				else USART1_RX_STA|=0x8000;	//接收完成了 
			}else{ //还没收到0X0D					
				if(Res==0x0d)USART1_RX_STA|=0x4000;
				else{
					USART1_RX_BUF[USART1_RX_STA&0X3FFF]=Res ; //将收到的数据放入数组
					USART1_RX_STA++;	//数据长度计数加1
					if(USART1_RX_STA>(USART1_REC_LEN-1))USART1_RX_STA=0;//接收数据错误,重新开始接收	  
				}		 
			}
		}   		 
	} 
} 

另外的一种方法:
在这里插入图片描述

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hey pear!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值