USART串口收发数据中遇到的数据丢失问题

1.串口初始化配置

//串口二初始化配置
void usart2_init(u32 bound)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	//开启GPIO时钟和串口2时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
	
	//配置串口2参数
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;//PA2:发送
	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_3;//PA3:接收
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	//串口参数设置
	USART_InitStructure.USART_BaudRate = bound;//波特率
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  USART_InitStructure.USART_Parity = USART_Parity_No;
  USART_Init(USART2, &USART_InitStructure);
	USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启中断,中断处理函数用于接收数据
  USART_Cmd(USART2, ENABLE);                    //使能串口 
	
	//NVIC内部中断向量管理配置
  NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化NVIC寄存器
}

2.利用串口发送数据

//发送一个字符
void Usart_SendByte(USART_TypeDef* pUSARTx, uint8_t ch)
{
	//发送一个字节数据到USART
	USART_SendData(pUSARTx, ch);
	
	//等待发送数据寄存器为空
	while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}

//发送一个字符串
void Usart_SendString(USART_TypeDef* pUSARTx, char* str)
{
	unsigned int k = 0;
	do
	{
		//逐个字节发送
		Usart_SendByte(pUSARTx, *(str + k));
		k++;
	}while(*(str + k) != '\0');
	
	//等待发送完成
	while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TC) == RESET);
}

3.串口发送数据重定向到串口调试助手,输出调试信息。

//重定义fputc函数 
int fputc(int ch, FILE *f)
{      
	while((USART2->SR&0X40)==0);//循环发送,直到发送完毕   
        USART2->DR = (u8) ch;      
	return ch;
}

4.串口接收数据

u8 USART2_RX_BUF[USART_REC_LEN];   //串口二接收数据缓存
u16 USART2_RX_STA = 0;//接收到的有效字节数目
void USART2_IRQHandler(void)                    //串口2中断服务程序
{
    u8 tmp;
    if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  //接收中断
    {
        tmp = USART_ReceiveData(USART2);  //读取接收到的数据
        if(tmp != 0x00)
        {
            USART2_RX_BUF[USART2_RX_STA] = tmp;
            USART2_RX_STA++;
        }
  }
} 

这里需要定义两个全局变量,第一个是接收数据的缓存,第二个是数据计数器,用来统计接收到的数据的数量。注意,有人可能会想到我可不可以直接在中断处理函数内部做一些处理操作,我的建议是不要,而是通过上诉最简单的方式。原因有两个,第一,这种方式思路清晰,第二,这种方式不会出现数据因为处理延时而丢失的问题,毕竟串口通信还是比较快的过程,如果花费过多的时间在中断处理函数中,可能导致意想不到的后果。另外,调试串口接收数据的时候,可能会出现问题,因为调试的过程中你的程序中途暂停执行了,但是不能保证发送方也暂停执行,所以会漏掉部分信息,常见的就是调试的时候只出现了第一个字节的数据,这是因为前面说的,毕竟串口通信还是比较快的。另外,串口接收的基础是在串口初始化的时候将接收中断打开。

//主函数中通过串口发送数据,同时检测是否有数据到来,如果有判断是否为OK,如果是,则退出循环,否则再次发送,直到发送成功
do
{
	//发送数据
	Usart_SendString(USART2, "AT");
				
	//等待接收成功后回应的结果
	delay_ms(3000);
				
	printf("send status:");
	//判断是否发送成功
	while(j < USART2_RX_STA)
	{
		printf("%c", USART2_RX_BUF[j]);
		if((USART2_RX_BUF[j-1] == 'O' || USART2_RX_BUF[j-1] == 'o') && (USART2_RX_BUF[j] == 'K' || USART2_RX_BUF[j] == 'k'))
		{
			flag = 1;//发送成功
			USART2_RX_STA = 0;
			j = 0;
			break;
		}
		j++;
	}
}while(flag == 0);

其中flag是一个标志,flag==0代表数据发送失败,flag==1代表数据发送成功,此时将退出循环发送程序。

最后,硬件平台:stm32f103zet6

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值