使用固件库进行的RCC时钟配置。
时钟树:
由时钟配置寄存器 CFGR 的位 17:PLLXTPRE使能HSE为8M --> 时钟配置寄存器CFGR的位16: PLLSRC 将HSE(8M)选为PLL(锁相环)的输入 --> CFGR位 21-18:PLLMUL[3:0]倍频因子选择9M得到PLLCLK(64M) --> CFGR 的位1-0:SW[1:0] 设置SYSTCLK选择PLLCLK作为系统时钟(72M) --> 在系统时钟的基础上配置三条总线的时钟(1.AHB、2.APB2、3.APB1) --> AHB等于系统时钟的1分频(72M) ,HCLK等于72M --> 在HCLK基础上1分频得到APB2(72M) --> 在HCLK基础上2分频得到APB1(36M)
程序编写流程:
使能HSE(RCC_HSEConfig) --> 等待HSE稳定(RCC_WaitForHSEStartUp) --> HSE稳定后使能预取指(FLASH_PrefetchBufferCmd) --> 设置FLASH等待(FLASH_SetLatency) --> 设置三总线分频因子(RCC_HCLKConfig、RCC_PCLK1Config、RCC_PCLK2Config) --> 设置PLL锁相环的时钟源和倍频因子(RCC_PLLConfig) --> 使能PLL --> 等待PLL稳定 while( RCC_GetFlagStatus( RCC_FLAG_PLLRDY ) == RESET ); --> 选择系统时钟(RCC_SYSCLKConfig) --> 等待系统时钟稳定while( RCC_GetSYSCLKSource() != 0x08 );
#include "clkconfig.h"
void HSEConfig(uint32_t RCC_PLLMul_x)
{
ErrorStatus HSEStatus;
//将RCC寄存器复位为复位值
RCC_DeInit();
//使能HSE
RCC_HSEConfig( RCC_HSE_ON );
HSEStatus = RCC_WaitForHSEStartUp();
if( HSEStatus == SUCCESS )
{
//使能预取指
FLASH_PrefetchBufferCmd( FLASH_PrefetchBuffer_Enable );
//设置等待
FLASH_SetLatency( FLASH_Latency_2 );
//配置三总线分频因子
RCC_HCLKConfig( RCC_SYSCLK_Div1 );
RCC_PCLK1Config( RCC_HCLK_Div2 );
RCC_PCLK2Config( RCC_HCLK_Div1 );
//配置PLL的时钟源和倍频因子
RCC_PLLConfig( RCC_PLLSource_HSE_Div1, RCC_PLLMul_x );
//使能PLL
RCC_PLLCmd(ENABLE);
//等待PLL稳定
while( RCC_GetFlagStatus( RCC_FLAG_PLLRDY ) == RESET );
//选择系统时钟
RCC_SYSCLKConfig( RCC_SYSCLKSource_PLLCLK );
//等待系统时钟稳定
while( RCC_GetSYSCLKSource() != 0x08 );
}
else
{
/* HSE启动失败 */
}
}
为什么要配置FLASH ?
- 取指令时,两条指令之间需要时间间隔,所以需要使能预取指,设置时延,72M的频率需要两个等待状态;
为什么程序编写流程跟时钟树流程不一样?
- 选择时钟源后,分频因子不可轻易改动,需要先配置好分频因子,再配置时钟源;
总结:
使用固件库编程给我的感觉像是用积木搭房子,每块积木有各自的作用,合理的组合可以实现一定的功能,但需要事先了解步骤,任然需要对寄存器的有一定的了解。