STM32F103串口1和串口2不同波特率之间交换数据问题

本文介绍了一种在STM32F103上实现不同波特率串口间可靠数据交换的方法。通过使用环形队列(FIFO)结构,解决了高速串口向低速串口发送数据时产生的数据丢失问题。文章提供了具体的实现代码。

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


前几天写一个东西,要用到STM32F103的串口1和串口2以不同的波特率交换数据,也就是说串口1波特率为9600,串口2波特率为115200,串口1可以把接收到的数据通过串口2发送出去,串口2也可以把接收到的数据通过串口1发送出去。低波特率向高波特率发送数据没问题,高波特率向低波特率发送数据会丢数据,原因是低波特率的串口还没发送完数据高波特率的串口就又发数据过来了,处理不过来。在同事的在帮助下,写出一个先进先出环形队列(FIFO)程序。接收数据用中断,发送数据用在主函数中查询发送完成标志位。希望对大家有点帮助,可能程序不完美,但程序可以用。定义一个fifo.h部件和一个fifo.c文件。其他的都在主函数中调用。
#ifndef _FIFO_H_
#define _FIFO_H_

#include "stm32f10x.h"

#define FIFO_SIZE 256

typedef struct
{
    uint8_t Buf[FIFO_SIZE];	   //定义缓冲区,大小用FIFO_SIZE定义
    volatile uint32_t Read;	   //定义读取指针
    volatile uint32_t Write;   //定义写入指针
}FIFOTypeDef;

extern FIFOTypeDef USART1_fifo;
extern FIFOTypeDef USART2_fifo;

void PutChar(uint8_t c);
uint8_t GetChar(uint8_t *c);
void PutChar1(uint8_t c);
uint8_t GetChar1(uint8_t *c);

#endif
#include "fifo.h"

FIFOTypeDef USART1_fifo;   //定义串口1的队列fifo
FIFOTypeDef USART2_fifo;   //定义串口2的队列fifo

/*******************************************************************************
* Function Name : PutChar
* Description   : put a fifo value into fifo buffer
* Input         : c
* Output        : None
* Return        : None
*******************************************************************************/
void PutChar(uint8_t c)
{
  USART1_fifo.Buf[USART1_fifo.Write] = c;  //写入数据到缓冲区
  
  if(++USART1_fifo.Write >= FIFO_SIZE)	   //写入指针超出缓冲区最大值,返回最初位置
  {
    USART1_fifo.Write = 0;
  }
}

/*******************************************************************************
* Function Name  : GetChar
* Description    : read fifo value from fifo buffer with timeout feature
* Input          : c
* Output         : None
* Return         : 0 
*******************************************************************************/
uint8_t GetChar(uint8_t *c)
{

  if(USART1_fifo.Read == USART1_fifo.Write)	  //如果没有存入数据,则返回0
  {
    return 0;
  }
  else
  {
    *c = USART1_fifo.Buf[USART1_fifo.Read];	 //读取数据,传入到指针c
    
    if (++USART1_fifo.Read >= FIFO_SIZE)	 //读取指针超出缓冲区最大值,返回最初位置
    {
      USART1_fifo.Read = 0;
    }
	
    return 1;								 //成功读取数据返回1
  }
}

/*******************************************************************************
* Function Name : PutChar
* Description   : put a fifo value into fifo buffer
* Input         : c
* Output        : None
* Return        : None
*******************************************************************************/
void PutChar1(uint8_t c)
{
  USART2_fifo.Buf[USART2_fifo.Write] = c;
  
  if(++USART2_fifo.Write >= FIFO_SIZE)
  {
    USART2_fifo.Write = 0;
  }
}

/*******************************************************************************
* Function Name  : GetChar
* Description    : read fifo value from fifo buffer with timeout feature
* Input          : c
* Output         : None
* Return         : 0 
*******************************************************************************/
uint8_t GetChar1(uint8_t *c)
{

	if(USART2_fifo.Read == USART2_fifo.Write)
	{
	return 0;
	}
	else
  {
    *c = USART2_fifo.Buf[USART2_fifo.Read];
    
    if (++USART2_fifo.Read >= FIFO_SIZE)
    {
      USART2_fifo.Read = 0;
    }
	
    return 1;
  }
}



#include "stm32f10x.h"
#include "fifo.h"

/*******************************************************************************
* Function Name : UIF_Init 
* Description   : 初始化串口
* Input         : USARTx = USART1,2,3 
*               : BPS = 1200, 4800,,,
*               : STB = 1,5,2,15
* Return        : None 
*******************************************************************************/
void UIF_Init(USART_TypeDef* USARTx, uint32_t BPS, uint32_t STB)
{
  	uint32_t Dly;
  	USART_InitTypeDef USART_InitStruct;	 //定义串口结构体
	
	NVIC_InitTypeDef NVIC_InitStructure; //定义中断结构体

  
	USART_ClearFlag(USARTx, USART_FLAG_TC);
	USART_DeInit(USARTx);              //复位串口x
	
	USART_InitStruct.USART_BaudRate = BPS;
	USART_InitStruct.USART_WordLength = USART_WordLength_8b;  //8位字节长度数据
	if(STB == 1)
	USART_InitStruct.USART_StopBits = USART_StopBits_1;
	else if(STB == 5)
	USART_InitStruct.USART_StopBits = USART_StopBits_0_5;
	else if(STB == 15)
	USART_InitStruct.USART_StopBits = USART_StopBits_1_5;
	else
	USART_InitStruct.USART_StopBits = USART_StopBits_2;
	USART_InitStruct.USART_Parity = USART_Parity_No;         //无奇偶检验位
	USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
	USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //接收 发送模式
	USART_Init(USARTx, &USART_InitStruct);   //初始化串口x
	

	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //使能串口1中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; //先占优先级2级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //从优先级2级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
	NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
	
	NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; //使能串口2中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; //先占优先级2级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //从优先级2级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
	NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
 		
	if(USART_GetFlagStatus(USARTx, USART_FLAG_TC)==SET)
    USART_ClearFlag(USARTx, USART_FLAG_TC);
	USART_Cmd(USARTx, ENABLE);          //使能串口x
	for(Dly = 0; Dly < 0xFFFF; Dly++);
	USART_ClearFlag(USARTx, USART_FLAG_TC); 
	
	USART_ITConfig(USARTx,USART_IT_RXNE,ENABLE);   //开启接收中断
									 
}

/*******************************************************************************
* Function Name : GPIO_Config 
* Description   : 初始化IO
* Input         : None 
* Return        : None 
*******************************************************************************/
void GPIO_Config(void)
{
  GPIO_InitTypeDef GPIO_InitStruct;

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA
                       | RCC_APB2Periph_GPIOB
                       | RCC_APB2Periph_AFIO
                       | RCC_APB2Periph_USART1, ENABLE);
  
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); 

  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;

  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9; //USART1_TX Output 
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(GPIOA, &GPIO_InitStruct);

  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10; //USART1_RX Input  
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(GPIOA, &GPIO_InitStruct);
  
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2; //USART2_TX Output   
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(GPIOA, &GPIO_InitStruct);

  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3; //USART2_RX Input    
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(GPIOA, &GPIO_InitStruct);
   
}
/*******************************************************************************
* Function Name : NVIC_Configuration 
* Description   : 设置NVIC中断分组
* Input         : None 
* Return        : None 
*******************************************************************************/
void NVIC_Configuration(void)
{
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);	//设置NVIC中断分组2:2位抢占优先级,2位响应优先级
}
/*******************************************************************************
* Function Name : USART_SendByte 
* Description   : 发送一个字节
* Input         : USARTx = USART1,2,3 
 				  Data = 要发送的数据
* Return        : None 
*******************************************************************************/
void USART_SendByte(USART_TypeDef* USARTx, uint16_t Data)
{
	USARTx->DR = (Data & (uint16_t)0x01FF);;
	while(USART_GetFlagStatus(USARTx, USART_FLAG_TC) != SET);
}
/*******************************************************************************
* Function Name : main 
* Description   : 主函数
* Input         : None
* Return        : None 
*******************************************************************************/
int main(void)
{
		uint8_t byte;
		GPIO_Config();
		NVIC_Configuration();
		UIF_Init(USART1,115200,1);	 //串口1波特率115200,1位停止位
		UIF_Init(USART2,9600,1);	 //串口2波特主9600,1位停止位																									//使能串口
		while(1)
		{
 
			if(USART1_fifo.Write != USART1_fifo.Read) //如果读取指针不等于写入指针,说明缓冲区有数据
			{
				if(GetChar(&byte))		//如果读取数据成功,返回1
				{
					USART_SendByte(USART2,byte);	//把串口1的缓冲区数据通过串口2发送出去
				}
			}
			if(USART2_fifo.Read!=USART2_fifo.Write)  //如果读取指针不等于写入指针,说明缓冲区有数据
			{
				if(GetChar1(&byte))   //如果读取数据成功,返回1
				{		
			   		USART_SendByte(USART1,byte); //把串口2的缓冲区数据通过串口1发送出去
			   	}
			} 
		}
}

/*******************************************************************************
* Function Name : USART1_IRQHandler 
* Description   : 串口1中断服务程序
* Input         : None
* Return        : None 
*******************************************************************************/
void USART1_IRQHandler(void)
{	
	u8 res; 
 	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //如果接收到数据
	{
		USART_ClearITPendingBit(USART1,USART_IT_RXNE);//清空接收标志
	 	res = USART_ReceiveData(USART1);
		PutChar(res);	  //压入数据到串口1缓冲区
	}

	//溢出,如果发生溢出需要先读SR,再读DR寄存器则可清除不断入中断的问题
	if(USART_GetFlagStatus(USART1,USART_FLAG_ORE)==SET)
	{
		USART_ClearFlag(USART1,USART_FLAG_ORE); //读SR其实就是清除标志
		USART_ReceiveData(USART1);    //读DR
	}
}
/*******************************************************************************
* Function Name : USART2_IRQHandler 
* Description   : 串口2中断服务程序
* Input         : None
* Return        : None 
*******************************************************************************/
void USART2_IRQHandler(void)        
{
	u8 Res;

	if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  //接收中断
	{
		USART_ClearITPendingBit(USART2,USART_IT_RXNE);//清空接收标志
		Res =USART_ReceiveData(USART2);//(USART2->DR);	//读取接收到的数据
		PutChar1(Res);	     //压入数据到串口2缓冲区
    }

	//溢出,如果发生溢出需要先读SR,再读DR寄存器则可清除不断入中断的问题
	if(USART_GetFlagStatus(USART2,USART_FLAG_ORE)==SET)
	{
		USART_ClearFlag(USART2,USART_FLAG_ORE); //读SR其实就是清除标志
		USART_ReceiveData(USART2);    //读DR
	}
} 






stm32串口1串口3数据互通,经测试同时发256字节不丢包 void usart3_init(u32 bound) { NVIC_InitTypeDef NVIC_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // GPIOBʱÖÓ RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE); //´®¿Ú3ʱÖÓÊ&sup1;ÄÜ USART_DeInit(USART3); //¸´Î»´®¿Ú3 //USART3_TX PB10 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PB10 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //¸´ÓÃÍÆÍìÊä³ö GPIO_Init(GPIOB, &GPIO;_InitStructure); //³õÊ&frac14;»¯PB10 //USART3_RX PB11 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//¸¡¿ÕÊäÈë GPIO_Init(GPIOB, &GPIO;_InitStructure); //³õÊ&frac14;»¯PB11 USART_InitStructure.USART_BaudRate = bound;//&sup2;¨ÌØÂÊÒ»°ãÉèÖÃΪ9600; USART_InitStructure.USART_WordLength = USART_WordLength_8b;//×Ö³¤Îª8λÊý¾Ý¸ñÊ&frac12; USART_InitStructure.USART_StopBits = USART_StopBits_1;//Ò»¸öÍ£Ö&sup1;λ USART_InitStructure.USART_Parity = USART_Parity_No;//ÎÞÆæÅ&frac14;УÑéλ USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//ÎÞÓ&sup2;&frac14;þÊý¾ÝÁ÷¿ØÖÆ USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //ÊÕ·¢Ä£Ê&frac12; USART_Init(USART3, &USART;_InitStructure); //³õÊ&frac14;»¯´®¿Ú 3 USART_Cmd(USART3, ENABLE); //Ê&sup1;ÄÜ´®¿Ú //Ê&sup1;ÄÜ&frac12;ÓÊÕÖÐ¶Ï USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);//¿ªÆôÖÐ¶Ï //ÉèÖÃÖжÏÓÅÏÈ&frac14;¶ NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2 ;//ÇÀÕ&frac14;ÓÅÏÈ&frac14;¶3 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //×ÓÓÅÏÈ&frac14;¶3 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQͨµÀÊ&sup1;ÄÜ NVIC_Init(&NVIC;_InitStructure); //¸ù¾ÝÖ¸¶¨µÄ&sup2;ÎÊý³õÊ&frac14;»¯VIC&frac14;Ä´æÆ÷ TIM4_Int_Init(1000-1,7200-1); //10msÖÐ¶Ï USART3_RX_STA=0; //ÇåÁã TIM_Cmd(TIM4,DISABLE); //&sup1;رն¨Ê±Æ÷7 } //´®¿Ú3,printf º¯Êý //È·±£Ò»´Î·¢ËÍÊý¾Ý&sup2;»³¬&sup1;ýUSART3_MAX_SEND_LEN×Ö&frac12;Ú void u3_printf(char* fmt,...) { u16 i,j; va_list ap; va_start(ap,fmt); vsprintf((char*)USART3_TX_BUF,fmt,ap); va_end(ap); i=strlen((const char*)USART3_TX_BUF); //´Ë´Î·¢ËÍÊý¾ÝµÄ³¤¶È for(j=0;j<i;j++) //Ñ­»··¢ËÍÊý¾Ý { while(USART_GetFlagStatus(USART3,USART_FLAG_TC)==RESET); //Ñ­»··¢ËÍ,Ö±µ&frac12;·¢ËÍÍê±Ï USART_SendData(USART3,USART3_TX_BUF[j]); } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值