关于STM32单片机串口通信只能读取上位机传输的第一个字节

一.问题提出

最近在学习STM32串口通信的时候,对照正点原子的代码,自己写了一个简易的串口通信的协议来练练手,代码长这样:

主程序

#include "HeadFile.h"
int main(void)
{		

	HardwareInit();
	while(1)
	{
		if(USART1_state==2)
		{
			u8 i;
			printf("get: ");
			for(i=0;i<counter;i++)
			{
				printf("%c",USART_RX_BUF[i]);
			}
			printf("\n");
			counter=0;
			USART1_state=0;
		}
	}
}

串口配置(正点原子的代码,没有改动)

void ConfigureUART1(u32 bound)
{
	
//GPIO端口设置
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟

	//USART1_TX   GPIOA.9
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
	GPIO_Init(GPIOA, &GPIO_InitStructure);			//初始化GPIOA.9

	//USART1_RX	  GPIOA.10初始化
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;			  //PA10
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
	GPIO_Init(GPIOA, &GPIO_InitStructure);				  //初始化GPIOA.10

	//Usart1 NVIC 配置
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; //抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		  //子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			  //IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);							  //根据指定的参数初始化VIC寄存器

	//USART 初始化设置

	USART_InitStructure.USART_BaudRate = bound;										//串口波特率
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;						//字长为8位数据格式
	USART_InitStructure.USART_StopBits = USART_StopBits_1;							//一个停止位
	USART_InitStructure.USART_Parity = USART_Parity_No;								//无奇偶校验位
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件数据流控制
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;					//收发模式

	USART_Init(USART1, &USART_InitStructure);	   //初始化串口1
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //开启串口接受中断
	USART_Cmd(USART1, ENABLE);					   //使能串口1
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
}

串口中断函数

void USART1_IRQHandler(void)                	//串口1中断服务程序
{
	u8 Res;
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断
	{
		printf("Interrupt entered\n\n");
		Res =USART_ReceiveData(USART1);	//读取接收到的数据
		if(Res==0xAA)
		{
			USART1_state=1;
			printf("STATE1 ENTERED\n\n");
		}
		else
		{
			if(USART1_state==1&&Res!=0xFC)
			{
				USART_RX_BUF[counter++]=Res;
				printf("READING char:%c\n",Res);
			}
			if(Res==0xFC)
			{
				USART1_state=2;
				printf("STATE2 ENTERED\n\n");
			}
		}
	}
}

原因分析:

按照我的预期,这个简单的串口协议解析程序应该是这样工作的:

  • 电脑通过串口助手使用CH340连接单片机发送一串数据,比如: 0xAA 0xBB 0xCC 0xDD 0xFC
  • 单片机收到数据并处理,将处理过程通过串口打印出来
  • 如果解析成功,会向上位机把数据串echo出来

然而,它是这样工作的(发送的是0xAA 0xB5 0xC3 0xFC):
请添加图片描述
正常状态下,应该会返回:“get:得”

这意味着程序顺利的进入了串口中断,收到了帧头,却没有解析后面的数据,确切来说,根本没有进入else部分.程序只解析到了0xAA,其后的数据被丢失.

利用串口助手多字符串发送工具一个字符一个字符的发送数据,每个字符之间间隔1ms:
发现程序正常,解析成功.
请添加图片描述
思考人生…看来不是协议本身的问题…

查阅了资料,有建议说串口中断接收并存储数据之后就不要干其他事情,否则中断函数耗时过多,容易使数据丢失,导致解析失败.意识到debug用的printf会占用大量的处理时间,可能是导致程序只能读取识别帧头的原因.

将所有串口中断内printf删掉,编译烧录,发送数据,解析成功…


解决方案:

串口中断里,不要加入任何数据解析之外的逻辑
比如:延时,串行输出,浮点数计算…如果硬是要debug,建议用keil或者在中断里点个不同颜色的灯表示运行状态
另外,用printf函数debug是一个坏习惯…今天我又给我这个喜欢在代码里面加一堆printf来debug的人上了一课.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值