一.问题提出
最近在学习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_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
USART_InitStructure.USART_BaudRate = bound;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
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);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
USART_Cmd(USART1, ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
}
串口中断函数
void USART1_IRQHandler(void)
{
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的人上了一课.
|