目录
为什么要调频
在STM32中有很多的芯片外设,他们的时钟频率或许不是一样的,为了各个外设之间能够协调运行,我们就需要对某个外设进行调频,比如对USB\SDIO\HCLK\ADC等等调频,这些的是必要的,韦德就是满足运行要求。
什么是HSE
HSE 是高速的外部时钟信号,可以由有源晶振或者无源晶振提供,频率从 4-16MHZ 不等。当 使用有源晶振时,时钟从 OSC_IN 引脚进入,OSC_OUT 引脚悬空,当选用无源晶振时,时钟从 OSC_IN 和 OSC_OUT 进入,并且要配谐振电容。
HSE 最常使用的就是 8M 的无源晶振。当确定 PLL 时钟来源的时候,HSE 可以不分频或者 2 分 频,这个由时钟配置寄存器 CFGR 的位 17:PLLXTPRE 设置,我们设置为 HSE 不分频。
什么是HSI
HSI时钟信号由内部8MHz的RC振荡器产生,可直接作为系统时钟或在2分频后作为PLL输入。
HSI RC振荡器能够在不需要任何外部器件的条件下提供系统时钟。它的启动时间比HSE晶体振 荡器短。然而,即使在校准之后它的时钟频率精度仍较差。
在这里通过外部时钟或者内部时钟的一步一步配置来达到自己想要的时钟;
配置过程顺着这个图来;
配置HSE外部高速时钟
注:因为系统定义为频率为72M,所以想要修改频率的话,必须在修改之前把频率在此初始化
1、开启 HSE/HSI ,并等待 HSE/HSI 稳定
2、设置 AHB、APB2、APB1 的预分频因子
3、设置 PLL 的时钟来源,和 PLL 的倍频因子,设置各种频率主要就是在这里设置
4、开启 PLL,并等待 PLL 稳定
5、把 PLLCK 切换为系统时钟 SYSCL
HSE配置
void HSE_SetSysClk(uint32_t RCC_PLLMul_x)
{
ErrorStatus HSEStartupStatus;
//先把时钟初始化
RCC_DeInit();
//打开HSE
RCC_HSEConfig(RCC_HSE_ON);
//等待打开,打开需要一段时间,并且之后还得检测一下是否打开
HSEStartupStatus=RCC_WaitForHSEStartUp();
//判断是否打开成功,否则跳转到最下面,执行else里面的程序
if(HSEStartupStatus==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);
//调整倍率
RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_x);
//打开PLL,这里如果你是使用其他的配置时钟的话例如:HSE/HSI/PLL
RCC_PLLCmd(ENABLE);
//等待PLL稳定
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET);
//稳定之后把系统时钟换成我们配置的时钟
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
//等待时钟修改成功
while(RCC_GetSYSCLKSource()!=0X08);
}
else
{
//这里就是时钟未开启成功后干的事,比如储存重要数据啊;
while(1);
}
}
HSI配置
//HSI配置过程如下,和HSE配置一样,这里我就不解释了
void HSI_SetSysClk(uint32_t RCC_PLLMul_x)
{
__IO uint32_t HSIStartUpStatus=0;
RCC_DeInit();
RCC_HSICmd(ENABLE);
HSIStartUpStatus = RCC->CR & RCC_CR_HSIRDY;
if(HSIStartUpStatus==RCC_CR_HSIRDY)
{
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);
RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_x);
RCC_PLLCmd(ENABLE);
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET);
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
while(RCC_GetSYSCLKSource()!=0x08);
}
else
{
while(1);
}
}
#include "stm32f10x.h"
#include "bsp_LED.h"
#include "bsp_rcc_clk_config.h"
void Delay(uint32_t count)
{
for(;count!=0;count--);
}
int main()
{
HSE_SetSysClk(RCC_PLLMul_16);//时钟为128M
HSI_SetSysClk(RCC_PLLMul_8);//时钟为64M
LED_GPIO_config();
while(1)
{
LED_G(ON);
LED_B(OFF);
LED_R(OFF);
Delay(0XFF0FFF);
LED_R(ON);
LED_G(OFF);
LED_B(OFF);
Delay(0XFF0FFF);
}
}
这里主函数选择不同的频率,也就是所谓的调频,尽量不要超过板子承受的频率,防止板子烧坏;
频率越大,时间越短;所以超过板子所能承受的频率之后,它就会因为短时间内工作过多的程序而烧坏;
---参考STM32野火