历史上的今天
今天是: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时钟了。
史海拾趣
|
移动式无线视频监控,指系统的视频采集前端是可移动的视频采集终端,对不同的临时监控需求点进行监控。可移动的视频采集终端由于监控点不固定,因此,它必须利用无线公网作为监控数据的传输网络。 移动视频监控系统原理 移动视 ...… 查看全部问答> |
|
在2440.h中这么写的 #define ADC_BASE 0xB1800000 // 0x58000000 而在map.a中是这样写的, DCD 0x91800000, 0x58000000, 1 ; A/D convert register 0x91800000: 虚拟地址 0x58000000: 物理地 ...… 查看全部问答> |
|
最近一段时间,接触了好几个具有 I2C 接口的从设备器件; 也对 I2C 的 WinCE 流驱动也有所了解。 开始用【查询】方式实现了一个 I2C 流驱动; 现在准备用【中断】方式实现 I2C 流驱动; 但是看了好几遍【2410数据手册】,都没有看明白; 2410 ...… 查看全部问答> |
|
在线MSP430编辑编译无需本地电脑安装CCS或IAR之类开发环境 在线MSP430编辑编译无需本地电脑安装CCS或IAR之类开发环境看了一下,支持代码彩色显示编写完了以后还可以在其网站服务器上进行编译,然后可以下载编译后的可烧写文件。使用google帐户登陆,无需注册。对于帐户安全,一般可以放心,使用OpenId方式来 ...… 查看全部问答> |




