STM32笔记 (五) RCC时钟系统
程序员文章站
2022-04-02 07:54:40
...
简介
由于STM32的性能强大,内部组成复杂,而且时钟频率普遍比51单片机高,不能简单的用一个51单片机的时钟系统来调配,对于F1系列时钟频率高达72MHz,如果把STM32的每一个外设的时钟都打开,那么功耗是不可想象的,同时对于一个电路,时钟频率越快,抗干扰能力就越弱,因此STM32采用了多时钟源的方式来解决这些问题,并且对于每一个片上外设,都需要单独设置时钟的使能位。
时钟源
-
HSE时钟–High Speed External Clock Signal (高速外部时钟)
精度高,位于芯片外部,通过OSC_IN 和OSC_OUT 引脚连接外部晶振
常用的是无源晶振(4~16MHZ)通常使用8MHZ(无源) ,一般倍频为72MHZ
晶振分类:
1.无源晶振是有2个引脚的无极性元件,需要借助于时钟电路才能产生振荡信号,自身无法振荡起来
2.有源晶振有4只引脚,是一个完整的振荡器,其中除了石英晶体外,还有晶体管和阻容元件主要看 你应用到的电路,如果有时钟电路,就用无源,否则就用有源。
-
HSI时钟–High Speed Internal Clock Signal(高速内部时钟)
位于芯片内部,当外部时钟出现故障时,会切换使用HSI时钟,直到HSE启动成功
大小为8MHZ 一般会被分频成4MHZ -
LSE时钟–Low Speed External Clock Signal(低速外部时钟)
位于芯片外部,通过OSC32_IN和OSC32_OUT连接频率为32.768MHz的石英晶体 -
LSI时钟–Low Speed Internal Clock Signal(低速内部时钟)
位于芯片内部,是一个RC震荡器,频率为40KHz -
PLLCLK–锁相倍频时钟源
PLLCLK本身的不是一个独立的内部或者外部时钟源,其来源可以是HSE或者HSI
相关寄存器
typedef struct
{
__IO uint32_t CR; //时钟控制寄存器
__IO uint32_t CFGR; //时钟配置寄存器
__IO uint32_t CIR; //时钟中断寄存器
__IO uint32_t APB2RSTR; //APB2 外设复位寄存器
__IO uint32_t APB1RSTR; //APB1 外设复位寄存器
__IO uint32_t AHBENR; //AHB外设时钟使能寄存器
__IO uint32_t APB2ENR; //APB2 外设时钟使能寄存器 常用
__IO uint32_t APB1ENR; //APB2 外设时钟使能寄存器 常用
__IO uint32_t BDCR; //备份域控制寄存器
__IO uint32_t CSR; //控制/状态寄存器
}RCC_TypeDef;
时钟树
稍加注释,原版可在参考手册中找到
几个名词这里解释一下:
分频:指的的将时钟频率除以一个常数,分频因子就是这个常数,例如,16MHz经过2分频后就是8MHz
倍频:将时钟频率乘以一个常数,倍频因子就是这个常数,例如,8MHz经过9倍倍频后就是72MHz
APB1和APB2总线配置流程图示例
RTC(实时时钟)时钟源
实时时钟是一个独立的定时器。 RTC模块拥有一组连续计数的计数器,在相应软件配置下,可
提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期。
RTC 时钟可由 HSE/128 分频得到,也可由低速外部时钟信号 LSE 提供,频率为32.768KHZ,也可由低速内部时钟信号 HSI 提供,具体选用哪个时钟由备份域控制寄存器BDCR 的位 9-8: RTCSEL[1:0]配置。独立看门狗的时钟由 LSI 提供,且只能是由 LSI 提供(LSI 是低速的内部时钟信号,频率为 30~60KHZ 直接不等,一般取 40KHZ)。
MCO 时钟输出
- MCO 是 Microcontroller Clock Output 的缩写,STM32允许输出时钟信号到外部MCO引脚,可以对外提供时钟,相当于一个有源晶振
- 时钟来源有: PLLCLK/2、 HSI、 HSE、 SYSCLK
- 由RCC->CFGR寄存器配置
配置HSE为系统时钟
编程要点:
- 开启 HSE , 等待 HSE稳定
- 设置 AHB、 APB2、 APB1 的预分频因子
- 设置 PLL 的时钟来源,和 PLL 的倍频因子
- 开启 PLL,等待 PLL 稳定
- 把 PLLCK 切换为系统时钟 SYSCLK
- 读取时钟切换状态位,确保 PLLCLK 被选为系统时钟
void HSE_SetSysClk( uint32_t RCC_PLLMul_x ) //x为倍频因子,如RCC_PLLMul_9
{
ErrorStatus ErrorStatus;
//把RCC复位成刚上电的状态
RCC_DeInit();
//使能HSE
RCC_HSEConfig(RCC_HSE_ON);
//等待HSE设置成功 返回success和error
ErrorStatus = RCC_WaitForHSEStartUp();
if( ErrorStatus == SUCCESS ) //如果启动成功
{
//使能预取址
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
FLASH_SetLatency(FLASH_Latency_2);
//AHB总线分频为1
RCC_HCLKConfig(RCC_SYSCLK_Div1);
//APB1总线分频为
RCC_PCLK1Config(RCC_HCLK_Div2);
//APB2总线分频为
RCC_PCLK2Config(RCC_HCLK_Div1);
//配置PLL锁相环
//配置PLLCLK = HSB * RCC_PLLMul_x (倍频因子)
RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_x);//8*x = xxxMHz
//使能PLL
RCC_PLLCmd(ENABLE);
//等待PLL稳定
while( RCC_GetFlagStatus( RCC_FLAG_PLLRDY ) == RESET );
//选择系统时钟为PLLCLK
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
//检查系统时钟来源是否正确
while( RCC_GetSYSCLKSource() != 0x08 );
}
else //启动失败
{
/* 可以在这里添加错误时运行的代码 */
}
}