HSE:高速外部时钟
来源:有源晶振(1-50M),无源晶振(4-26M)
控制:RCC_CR时钟控制寄存器的位16:HSEON控制
HSI:高速内部时钟
来源:芯片内部,大小为16M,当HSE故障时,系统自动切换到HSI,直到HSE启动成功
控制:RCC_CR时钟控制寄存器的位0:HSION控制
锁相环时钟:PLLCLK
来源:HSI、HSE。由PLLSRC位配置
HSE或者HSI先经过一个分频因子M进行分频,然后再经过倍频因子N,然后在经过分频因子P,最后成为锁相环时钟
VCOCLK_IN = PLLCLK_IN / M = HSE / 25 = 1M
VCOCLK_OUT = VCOCLK_IN * N =1M * 336 = 336M
PLLCLK_OUT=VCOCLK_OUT/P=336/2=168M
PLL48CK时钟:USB_FS、RANG、SDIO提供时钟
系统时钟 SYSCLK,最高为168M
来源:HSI、HSE、PLLCLK
控制:RCC_CFGR时钟配置寄存器SW位
HCLK时钟 :AHB高速总线时钟,最高为168M
来源:系统时钟分频得到
控制:RCC_CFGR时钟配置寄存器的HPRE位
PCLK1时钟:APB1低速总线时钟,最高为42M,为APB1总显得外设提供时钟
来源:HCLK分频得到,通常为4分频
控制:RCC_CFGR时钟配置寄存器的PPRE1位
PCLK2时钟:APB高速总线时钟,最高为84M,为APB2总显得外设提供时钟
来源:HCLK分频得到,通常配置为2分频
控制:RCC_CFGR时钟配置寄存器的PPRE2位
将 system_stm32f4xx.c 文件中的void SystemInit(void) 函数中的 ==SetSysClock()==摘抄出来,去掉宏定义,和与STM32F40_41xxx无关的代码,只保留有关STM32F40_41xxx的内容进行分析:
#define PLL_M 25
#define PLL_Q 7
#define PLL_N 336
#define PLL_P 2
void User_SetSysClock(void)
{
/******************************************************************************/
/* PLL (clocked by HSE) used as System clock source */
/******************************************************************************/
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
RCC_DeInit();//复位RCC所有寄存器
/* Enable HSE */
/*使能HSE*/
RCC->CR |= ((uint32_t)RCC_CR_HSEON);//控制RCC_CR寄存器中的HSEON位置为1,使能
/* Wait till HSE is ready and if Time out is reached exit */
/*等待HSE启动稳定(通过HSEDAY位来判断),如果超时则退出*/
do
{
HSEStatus = RCC->CR & RCC_CR_HSERDY;//控制RCC_CR寄存器中的HSERDY位置
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CR & RCC_CR_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}
/*HSE启动成功*/
if (HSEStatus == (uint32_t)0x01)
{
/* Select regulator voltage output Scale 1 mode */
/*选择电压调节器的模式为1*/
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
PWR->CR |= PWR_CR_VOS;
/* HCLK = SYSCLK / 1*/ // AHB 1分频
RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
/* PCLK2 = HCLK / 2*/ // APB2 2分频
RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;
/* PCLK1 = HCLK / 4*/ // APB1 4分频
RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;
/* Configure the main PLL */
/*配置主PLL*/ //PLL_M分频因子(现在定义为25),如果外部晶振有变化需要更改,代码移植时会用到
RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
(RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);//RCC_PLLCFGR_PLLSRC_HSE 选择锁相环时钟的来源,一般都是HSE,一般不使用HSI
/* Enable the main PLL */
/*使能主PLL*/
RCC->CR |= RCC_CR_PLLON;
/* Wait till the main PLL is ready */
/*等待主PLL稳定*/
while((RCC->CR & RCC_CR_PLLRDY) == 0)
{
}
/* Configure Flash prefetch, Instruction cache, Data cache and wait state */
/*配置FLASH预取指,指令缓存,数据缓存,等待周期*/
FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;
/* Select the main PLL as system clock source */
/*选择主PLL时钟作为系统时钟*/
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= RCC_CFGR_SW_PLL;
/* Wait till the main PLL is used as system clock source */
/*确保主PLL时钟选为系统时钟*/
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);
{
}
}
else
{ /* If HSE fails to start-up, the application will have wrong clock
configuration. User can add here some code to deal with this error */
/*HSE 启动失败,在理可以添加启动失败的处理代码*/
}
}
适用固件库的方式编写SetSysClock()
void HSE_SetSysClock(uint32_t PLLM,uint32_t PLLN,uint32_t PLLP,uint32_t PLLQ)
{
ErrorStatus HSE_ErrorStatus = ERROR;
RCC_DeInit();//复位RCC所有寄存器
/*使能HSE*/
RCC_HSEConfig(RCC_HSE_ON);
/*等待HSE启动稳定*/
HSE_ErrorStatus=RCC_WaitForHSEStartUp();
if(HSE_ErrorStatus == SUCCESS){
/*启动成功*/
/*选择电压调节器的模式为1*/
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
PWR->CR |= PWR_CR_VOS;
/*配置AHB、APB1、APB2预分频系数*/
RCC_HCLKConfig(RCC_SYSCLK_Div1);
RCC_PCLK1Config(RCC_SYSCLK_Div4);
RCC_PCLK2Config(RCC_SYSCLK_Div2);
/*配置主PLL*/ //PLL_M分频因子(以参数的方式传进来),如果外部晶振有变化需要更改,代码移植时会用到
RCC_PLLConfig( RCC_PLLSource_HSE,PLLM,PLLN, PLLP,PLLQ);//锁相环时钟:PLLM 分频因子 PLLN 倍频因子 PLLP分频因子 PLLQ 分频因子
/*使能主PLL*/
RCC_PLLCmd(ENABLE);
/*等待主PLL稳定*/
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET){
}
/*配置FLASH预取指,指令缓存,数据缓存,等待周期*/
FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;
/*选择主PLL时钟作为系统时钟*/
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
/*确保主PLL时钟选为系统时钟*/
while(RCC_GetSYSCLKSource()!=0x08){
}
}
else{
/*HSE启动失败,在这里添加错误处理代码*/
}
}
准确检测时钟信号的频率方法:MCO1,MCO2 通过外部GPIO输出,用示波器进行检测
初始化MCO1、MCO2对应的GPIO引脚,调用图中两个函数,从PA8、PC9引出两条线接示波器进观察频率
上一篇:STM32F407中断学习笔记
下一篇:error: #268: declaration may not appear after executable statement in block问题解决方法