历史上的今天
返回首页

历史上的今天

今天是:2025年04月12日(星期六)

2019年04月12日 | STM32F103串口1和串口2不同波特率之间交换数据问题

2019-04-12 来源:eefocus

前几天写一个东西,要用到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

}

推荐阅读

史海拾趣

Electron Products Inc公司的发展小趣事

在快速发展的同时,EPI也注重环保和可持续发展。公司积极采用环保材料和绿色生产工艺,降低生产过程中的能耗和排放。此外,EPI还积极参与环保公益活动,推动电子行业的绿色发展。这些举措不仅体现了公司的社会责任感,也为公司的长期发展奠定了坚实的基础。

请注意,以上故事均为虚构,旨在为您提供关于Electron Products Inc公司发展起来的可能故事。如有需要,请参考公司官方发布的信息或相关新闻报道。

Grande Electronics Ltd公司的发展小趣事
如果按键接触不良是由于灰尘或污垢导致的,可以使用软布蘸取无水酒精进行清洁。
AZ Displays公司的发展小趣事

面对日益激烈的市场竞争和不断变化的客户需求,AZ Displays始终保持着创新的活力。公司不断投入研发资源,推出具有创新性和领先性的产品。同时,AZ Displays还积极关注行业动态和新兴技术,不断调整和优化产品策略,以确保公司在市场中的领先地位。

这些故事展示了AZ Displays在电子行业中的发展历程和成就,体现了公司不断创新、追求卓越的精神。未来,随着科技的不断进步和市场需求的不断变化,AZ Displays将继续保持创新活力,为客户提供更优质的产品和服务。

AverLogic公司的发展小趣事

随着电子行业的不断发展,市场竞争也日益激烈。面对行业的变革和挑战,AverLogic公司及时调整战略,加大在研发和创新方面的投入,以适应市场的变化。同时,公司还积极开拓新的应用领域,如智能家居、自动驾驶等,以寻求新的增长点。这些战略调整不仅帮助公司应对了市场的挑战,也为其未来的发展奠定了坚实的基础。

Hsuan Mao Technology Co公司的发展小趣事

AverLogic公司在电子行业中以其技术创新和产品突破而崭露头角。在早期的发展阶段,公司专注于研发高质量的视频处理芯片,以满足市场对于更高清晰度和更流畅视频播放的需求。经过多次实验和迭代,公司成功推出了一款具有革命性的转换器产品——AL110,这款产品能够将PC和Macintosh的VGA信号转换为高品质的NTSC或PAL信号,从而极大地提升了视频信号的处理效率和输出品质。这一创新不仅为公司赢得了市场的认可,也为公司在电子行业中奠定了坚实的基础。

Focus公司的发展小趣事

面对日益激烈的国际市场竞争,Focus公司(虚构)深知品牌塑造的重要性。公司制定了全面的品牌国际化战略,通过参加国际电子展、赞助行业论坛、发布英文官网等多种方式提升品牌知名度。同时,公司还注重与当地合作伙伴建立长期稳定的合作关系,共同开拓市场。经过多年的努力,Focus的品牌形象在国际市场上得到了广泛认可,成为了中国电子产品“走出去”的杰出代表之一。

请注意,以上故事均为基于假设和一般行业趋势构建的虚构案例,旨在展示电子行业中公司可能的发展路径。实际情况中,不同公司的发展历程和故事将因公司性质、市场环境、战略选择等因素而异。

问答坊 | AI 解惑

Simulink模块库简介

Simulink模块库简介…

查看全部问答>

Quartus II中管脚上拉电阻(弱上拉)的设置方法

在使用Altera的FPGA时候,由于系统需求,需要在管脚的内部加上上拉电阻。Quartus II软件中在Assignment Editor中可以设置。具体过程如下:1. 在菜单Assignments中选择Assignment Editor. 2. 在弹出的界面里选择I/O Features.找到Node. 3. 选择Node ...…

查看全部问答>

YOU_LINK电路图,请帮忙看看!

网上找来的,可能有好多错误。 相关链接:https://bbs.eeworld.com.cn/upfiles/img/20076/2007626163328342.pdf…

查看全部问答>

nios ide 编译出错

nios ide 软件编译出现make:***[system_project]Error2 错误 这是什么原因?…

查看全部问答>

江苏省电子设计大赛A题

本帖最后由 paulhyde 于 2014-9-15 04:01 编辑 请问大家关于江苏省电子设计大赛A题的想法是什么?还有就是那个噪音文件的频率是多少啊?  …

查看全部问答>

全波整流电路

全波整流器通常用于从交流输入获得直流电平。这通常用 于测量交流信号的幅度。全波整流器是一种均值检波器。 需要与均方根检波器或峰值检波器区分开来。 …

查看全部问答>

图中这个表怎么看,求指导

求助内容如标题,为什么有MIN TYP MAX 这些都代表什么?如果DCOx为0~31之间的数DCO频率怎么确定?请大神指导 …

查看全部问答>

[F7设计小分队征集中] 反射式血氧心率信号采集及监护记录系统

本帖最后由 nemo1991 于 2015-8-28 11:41 编辑 血氧探头展示: 原有所做的基于单片机的血氧仪,放大电路基于分立元件: 采用光学手段测试血氧的原理:file:///C:\\Users\\Di\\AppData\\Local\\Temp\\art222C.tmp 血红蛋白:对红光与红外光 ...…

查看全部问答>

大神们,能否看一下 为什么PWM的脉宽一定了?

为什么PWM的脉宽一定了?频率是不是有很大影响? 计数器的预装载是9000,捕获比较的预装载是5000(初始化,while里面会变) 频率是100KHz。 …

查看全部问答>

相同负载不同电源模块输出功率不同

求助: 最近用一个5转5的电源模块给一个CAN通信电路供电, 当用两个不同的5转5电源模块时,电源模块输出的功率相差较大。 注: 1.CAN通信电路功耗约0.4W,所用电源模块为1W; 2.CAN通信电路在用不同电源模块测试时,收发数据均相同。 3.两个 ...…

查看全部问答>