历史上的今天
返回首页

历史上的今天

今天是:2024年08月28日(星期三)

正在发生

2018年08月28日 | 关于STM32F107RCT6使用8M晶振串口波特率错误的问题

2018-08-28 来源:eefocus

发现问题

这段时间在学习FreeRTOS,今天移植成功后,写了2个任务。一个是LED每隔1s闪烁任务,另一个是使用UART4每隔100ms发送字符串任务。下载成功后,发现LED闪烁间隔不对,串口打印间隔时间也不对。当时就很纳闷了:RCC是按标准库的例子来配置的,FreeRTOS的系统节拍也是配置正确的,不可能会出现这种问题。后来,仔细排查,用示波器测试串口的波形发现一个问题:程序代码配置的是115200波特率,但实际输出波形算出来是38400,相差3倍。到这就开始怀疑RCC配置了,这时,我把MCO引脚打开,让其出示SYSCLK时钟,示波器上面反应的是72MH。接着又让它输出APB1CLK时钟,是正常的36MHz。调试到这里就感觉莫名其妙了,后来仔细查看RCC配置代码,发现官方例子是使用的25MHz的晶振,于是我换上25Mhz,重算了下分频系数等。烧写后,就变正常了。这里说下官网的例子模板

问题解决

STM32F107的时钟树

这里写图片描述
从图中可以看出,STM32F107的SYSCLK时钟有2条配置路线。第一条可以使用8M外部晶振来配置系统72MHz。第二条可以使用25M外部晶振来配置系统72MHz时钟。起出使用的是第一条路线,系统时钟也是正确配置成72MHz了,但是串口时钟是不正确的(其实是HSE_VALUE值没修改)。换成25MHz晶振,按第二条线路配置后,串口就正常了

官方RCC配置例子代码


void RCC_Configuration(void)

{

 RCC_ClocksTypeDef RCC_ClockFreq;


   /* RCC system reset(for debug purpose) */

  RCC_DeInit();


  /* Enable HSE */

  RCC_HSEConfig(RCC_HSE_ON);


  /* Wait till HSE is ready */

  HSEStartUpStatus = RCC_WaitForHSEStartUp();


  if(HSEStartUpStatus != ERROR)

  {

    /* Enable Prefetch Buffer */

    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);


 /****************************************************************/

 /*      HSE=25MHz, HCLK=72MHz, PCLK2=72MHz, PCLK1=36MHz         */

 /****************************************************************/

    /* Flash 2 wait state */

    FLASH_SetLatency(FLASH_Latency_2);

    /* HCLK = SYSCLK */

    RCC_HCLKConfig(RCC_SYSCLK_Div1);

    /* PCLK2 = HCLK */

    RCC_PCLK2Config(RCC_HCLK_Div1);

    /* PCLK1 = HCLK/2 */

    RCC_PCLK1Config(RCC_HCLK_Div2);

    /*  ADCCLK = PCLK2/4 */

    RCC_ADCCLKConfig(RCC_PCLK2_Div6);


    /* Configure PLLs *********************************************************/

    /* PPL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */

    RCC_PREDIV2Config(RCC_PREDIV2_Div5);

    RCC_PLL2Config(RCC_PLL2Mul_8);


    /* Enable PLL2 */

    RCC_PLL2Cmd(ENABLE);


    /* Wait till PLL2 is ready */

    while (RCC_GetFlagStatus(RCC_FLAG_PLL2RDY) == RESET)

    {}


    /* PPL1 configuration: PLLCLK = (PLL2 / 5) * 9 = 72 MHz */

    RCC_PREDIV1Config(RCC_PREDIV1_Source_PLL2, RCC_PREDIV1_Div5);

    RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_9);


    /* Enable PLL */

    RCC_PLLCmd(ENABLE);


    /* Wait till PLL is ready */

    while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)

    {}


    /* Select PLL as system clock source */

    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);


    /* Wait till PLL is used as system clock source */

    while (RCC_GetSYSCLKSource() != 0x08)

    {}

  }


  RCC_GetClocksFreq(&RCC_ClockFreq);


  /* Enable USART2 clock */

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);    



  /* Enable ETHERNET clock  */

  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_ETH_MAC | RCC_AHBPeriph_ETH_MAC_Tx |

                        RCC_AHBPeriph_ETH_MAC_Rx, ENABLE);


  /* Enable GPIOs clocks */

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC |

                         RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE| RCC_APB2Periph_AFIO, ENABLE);

  /* Enable ADC1 clock */

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

}


可以发现官方的例子代码是使用25MHz外部晶振来配置的系统时钟,我在官方的代码基础上修改我的8M晶振配置就不能正常运行


我修改的代码


void bsp_RCC_Init(void)

{

 RCC_ClocksTypeDef RCC_ClockFreq;


   /* RCC system reset(for debug purpose) */

  RCC_DeInit();



  /* Enable HSE */

  RCC_HSEConfig(RCC_HSE_ON);


  /* Wait till HSE is ready */

  if(RCC_WaitForHSEStartUp() != ERROR)

  {

    /* Enable Prefetch Buffer */

    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);


 /****************************************************************/

 /*      HSE=8MHz, HCLK=72MHz, PCLK2=72MHz, PCLK1=36MHz         */

 /****************************************************************/

    /* Flash 2 wait state */

    FLASH_SetLatency(FLASH_Latency_2);

    /* HCLK = SYSCLK */

    RCC_HCLKConfig(RCC_SYSCLK_Div1);

    /* PCLK2 = HCLK */

    RCC_PCLK2Config(RCC_HCLK_Div1);

    /* PCLK1 = HCLK/2 */

    RCC_PCLK1Config(RCC_HCLK_Div2);

    /*  ADCCLK = PCLK2/4 */

    RCC_ADCCLKConfig(RCC_PCLK2_Div6);


    /* Configure PLLs *********************************************************/

    /* PPL2 configuration: PLL2CLK = (HSE / 2) * 10 = 40 MHz */

    RCC_PREDIV2Config(RCC_PREDIV2_Div2);

    RCC_PLL2Config(RCC_PLL2Mul_10);


    /* Enable PLL2 */

    RCC_PLL2Cmd(ENABLE);


    /* Wait till PLL2 is ready */

    while (RCC_GetFlagStatus(RCC_FLAG_PLL2RDY) == RESET)

    {}


    /* PPL1 configuration: PLLCLK = (HSE / 1) * 9 = 72 MHz */

    RCC_PREDIV1Config(RCC_PREDIV1_Source_HSE, RCC_PREDIV1_Div1);

    RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_9);


    /* Enable PLL */

    RCC_PLLCmd(ENABLE);


    /* Wait till PLL is ready */

    while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)

    {}


    /* Select PLL as system clock source */

    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);


    /* Wait till PLL is used as system clock source */

    while (RCC_GetSYSCLKSource() != 0x08)

    {}

  }

 }

上面我修改的代码使用后就出现了串口波特率错误的问题。在keil调试查看寄存器发现UART->BRR的数值与理论计算的不一样。追溯USART_Init()函数配置过程,发现获取的PCLK1时钟频率不是36MHz。这里写图片描述
仔细查询源头代码,发现HSE_VALUE定义的是25000000,这就导致图中RCC_GetClockFreq()函数获取的PCLK1_Frequency的值计算出错。所以需将HSE_VALUE改成8000000。 
这里写图片描述
另一种办法,更换外部8M晶振为25M,修改RCC配置为官方代码,就可以正常运行

总结

STM32F107具有以太网、USB OTG 等网络设备,以太网使用MII接口时需要提供25MHz时钟,STM32F107使用外部25MHz晶振来作为时钟源是最好不过了,官方也推荐使用25MHz。使用8M晶振需要修改HSE_VALUE值为8000000,然后配置相应的PLL时钟了。


推荐阅读

史海拾趣

Hexawave公司的发展小趣事

当涉及到采用算术逻辑单元(ALU, Arithmetic Logic Unit)组成的二进制加减电路时,网友们可能会提出多种问题,这里列举一些常见问题及其解答:

1. ALU 如何实现二进制加法?

回答
在二进制加法中,ALU 使用全加器(Full Adder)或一系列的全加器(对于多位二进制数)来实现。每个全加器接受三个输入:两个加数位(A 和 B)以及一个来自低位的进位(Cin)。它产生两个输出:一个和位(Sum)和一个向高位的进位(Cout)。通过级联多个全加器,可以完成多位二进制数的加法。

2. ALU 如何实现二进制减法?

回答
二进制减法可以通过加法来实现,利用“补码”的概念。具体地,将减数取反加一(即求其二进制补码),然后将该补码与被减数相加。结果的正负由最高位(符号位)决定,其余位表示数值大小。ALU 内部可以包含专门的电路来处理这种补码加法,从而间接实现减法。

3. ALU 如何处理进位和借位?

回答
在加法中,进位(Carry)是从低位向高位传递的,每个全加器都会输出一个进位信号给下一个高位的全加器。在减法(通过补码加法实现)中,由于使用了加法器,进位的概念仍然适用,但在某些情况下,它可能被视为“借位”的相反操作,尤其是在直观理解减法过程时。不过,从电路设计的角度来看,ALU 内部处理的是加法操作,包括进位。

4. ALU 如何支持更复杂的算术运算,如乘法和除法?

回答
ALU 通常支持基本的算术运算(加、减)和逻辑运算。对于乘法和除法,ALU 可能不支持直接计算,或者仅支持部分乘法和除法的简化版本(如移位操作,可以视为乘以2的幂或除以2的幂的简化形式)。复杂的乘法和除法运算通常需要额外的硬件单元(如乘法器和除法器)来执行,这些单元可能作为ALU的补充或与之并行工作。

5. ALU 的设计如何影响计算机的性能?

回答
ALU 的设计对计算机的性能有直接影响。更快的ALU 能够更快地完成算术和逻辑运算,从而提高整个计算机的处理速度。此外,ALU 的指令集和设计的灵活性也会影响其能够执行的操作种类和效率。现代CPU中的ALU通常非常高效且灵活,能够执行多种复杂的算术和逻辑操作,以满足现代应用程序的需求。

Calmos Systems Inc公司的发展小趣事

随着国内市场的饱和,Calmos Systems Inc公司开始将目光投向国际市场。公司制定了详细的国际化战略,包括市场调研、产品定位、销售渠道建设等方面。公司派遣专业团队前往海外市场进行考察和交流,了解当地市场需求和文化特点。同时,公司还积极寻求与国际知名企业的合作机会,共同开拓国际市场。在国际化战略的推动下,公司的业务范围不断扩大,国际市场份额逐年提升。

Comair Rotron公司的发展小趣事

1987年,为了更好地适应市场变化和拓展国际业务,Comair决定进行品牌重塑,将公司名称更改为“Comair Rotron”。同时,公司还在墨西哥建立了新的制造工厂,并在圣地亚哥设立了销售和工程中心,以支持其在北美地区的业务发展。这一举措不仅提升了Comair Rotron的品牌形象,也为其在全球范围内的市场拓展奠定了坚实基础。

FTCAP Fischer & Tausche Capacitor Group公司的发展小趣事

1947年,James Van Ryan在美国纽约伍德斯托克创立了Comair公司,初期主要专注于风扇和风机产品的制造。当时,电子行业正处于起步阶段,对散热和空气流动的需求日益增长。Comair凭借其出色的技术和产品质量,很快在电子行业中崭露头角,为早期的电子设备提供了可靠的散热解决方案。

ATOP_Technologies公司的发展小趣事

ATOP Technologies自1989年创立以来,以创新、智能、整合、坚持为核心价值观,初期主要专注于工业自动化领域的产品研发。在创立初期,公司面临着资金紧张、市场竞争激烈等挑战。然而,凭借着对技术的深刻理解和对市场的敏锐洞察,ATOP Technologies逐步在工业自动化领域站稳脚跟,并开始积累起一批忠实的客户。

Cal Crystal Lab Inc / Comclok Inc公司的发展小趣事

随着全球化的加速推进,国际化战略成为了企业发展的重要方向。Cal Crystal Lab Inc在稳固国内市场的基础上,积极实施国际化战略。公司不仅在海外设立了研发中心和生产基地,还加大了对国际市场的开拓力度。通过与当地企业的合作与交流,Cal Crystal Lab Inc不断适应国际市场的需求和变化,提升了公司在全球市场的竞争力。

这五个故事只是虚构的示例,并不代表任何真实公司的历史。实际的电子行业公司发展历程往往更加复杂和多样,受到市场、技术、政策等多种因素的影响。如果您需要了解特定公司的真实发展故事,建议查阅相关资料或咨询相关人士。

问答坊 | AI 解惑

移动视频监控在“数字城管”中的应用

移动式无线视频监控,指系统的视频采集前端是可移动的视频采集终端,对不同的临时监控需求点进行监控。可移动的视频采集终端由于监控点不固定,因此,它必须利用无线公网作为监控数据的传输网络。    移动视频监控系统原理   移动视 ...…

查看全部问答>

请问你们知道前边值和后面的值有什么关系吗?

在2440.h中这么写的 #define ADC_BASE      0xB1800000 // 0x58000000 而在map.a中是这样写的, DCD 0x91800000, 0x58000000,  1  ; A/D convert register 0x91800000: 虚拟地址 0x58000000: 物理地 ...…

查看全部问答>

2410 I2C 在什么情况下产生中断?

最近一段时间,接触了好几个具有 I2C 接口的从设备器件; 也对 I2C 的 WinCE 流驱动也有所了解。 开始用【查询】方式实现了一个 I2C 流驱动; 现在准备用【中断】方式实现 I2C 流驱动; 但是看了好几遍【2410数据手册】,都没有看明白; 2410 ...…

查看全部问答>

大家用wince6.0, 在vs2005里是怎么找函数和变量定义的???

转到声明,转到定义都用不了,怎么回事?是不是非托管代码的原因?…

查看全部问答>

关于USB接口的serial驱动

serial驱动是将USB接口模拟成串口?那是怎样与外部设备进行通信的?难道就和普通的串口一样?…

查看全部问答>

八位二进制数转BCD码

怎样将八位的二进制数转换成一字节的BCD码?…

查看全部问答>

PPP协议

  cfanlwn  你那还有PPP协议的资料没,发我一份啊!…

查看全部问答>

【讨论】如何自建库并调用它?

在IAR下要如何自建库,又怎么去调用呢?可否举个最简单的例子?????…

查看全部问答>

在线MSP430编辑编译无需本地电脑安装CCS或IAR之类开发环境

在线MSP430编辑编译无需本地电脑安装CCS或IAR之类开发环境看了一下,支持代码彩色显示编写完了以后还可以在其网站服务器上进行编译,然后可以下载编译后的可烧写文件。使用google帐户登陆,无需注册。对于帐户安全,一般可以放心,使用OpenId方式来 ...…

查看全部问答>