RCC—使用HSE配置系统时钟
芯片提供时钟就要有时钟树
时钟树在参考手册RCC章节开头就有(这里的时钟树看到感觉眼睛打了马赛克,小弟截图技术有限)
什么是晶振?
晶振:晶体振荡器,用于各种电路中产生振荡频率,每个单片机里都会有晶振,给单片机提供时钟频率,振荡得越快,时钟频率就越高,单片机运行的速度就越快
解析时钟树的方法:(系统时钟)
- 时钟是由晶振提供的,首先要找到时钟的入口点。图中OSC_IN 和 OSC_OUT,这两个是外部晶振的引脚,所以时钟是从这里进入的。接有源晶振时,时钟从OSC_IN进入,OSC_OUT悬空。接无源晶振时,时钟从OSC_IN 和 OSC_OUT一起进入
- 时钟进入以后会经过PLL锁相环,进入前会经过一个M分频,进入PLL锁相环之后就会进入N倍频,输出时经过一个P分频,输出的时钟为PLLCLK
- 可以选择PLLCLK、HSE、HIS作为系统时钟
- 然后经过AHB总线的分频因子,成为HCLK作为AHB总线的时钟,或者再经过APB的分频因子作为APB1、APB2总线的时钟(根据参考手册AHB总线频率最大为180MHZ 、高速APB2总线频率最大为90MHZ 低速APB1总线频率最大为45MHZ)
上述分析的是时钟树的系统时钟,还有其他时钟RTC实时时钟、看门狗时钟、I2S时钟、以太网时钟、MCO输出时钟,这些等需要用到的时钟看吧
下面用固件库编写使用HSE配置系统时钟函数
(HSI也是同样的思路)
- 启动HSE,在头文件寻找HSE启动的函数void RCC_HSEConfig(uint8_t RCC_HSE)
- 等待HSE稳定ErrorStatus RCC_WaitForHSEStartUp(void)
这个函数是如何实现的:在这个函数中还调用了函数
FlagStatus RCC_GetFlagStatus(uint8_t RCC_FLAG)
那先讲解这个函数是如何实现的:这个函数的功能是检查是否设置了指定的RCC标志。RCC的标志(RCC_FLAG)都会有自己的值,首先检查参数,然后得到RCC寄存器的位号(根据RCC的标志确定在RCC的哪个寄存器里),最后获得RCC寄存器的位置判断是否设置了指定的参数,然后返回值,如果设置了返回1,否返回0
判断HSE是否准备好,如果是返回1,否返回0 - 设置HCLK、APB1、APB2预分频因子
void RCC_HCLKConfig(uint32_t RCC_SYSCLK)
void RCC_PCLK1Config(uint32_t RCC_HCLK)
void RCC_PCLK2Config(uint32_t RCC_HCLK) - 设置进入PLL锁相环的M分频因子 PLL锁相环的N倍频因子 出PLL锁相环的P分频因子 void RCC_PLLConfig(uint32_t RCC_PLLSource, uint32_t PLLM, uint32_t PLLN, uint32_t PLLP, uint32_t PLLQ)控制系统时钟的频率就在于这几个分频因子
- 启动PLL void RCC_PLLCmd(FunctionalState NewState)
等待PLL稳定 使用了FlagStatus RCC_GetFlagStatus(uint8_t RCC_FLAG)把RCC_FLAG设为RCC_FLAG_PLLRDY,若准备好返回1 - 设置PLLCLK为系统时钟void RCC_SYSCLKConfig(uint32_t RCC_SYSCLKSource)
- 读取状态位确保PLLCLK被选中为系统时钟
uint8_t RCC_GetSYSCLKSource(void)//该函数功能:返回时钟源用作系统时钟
若返回数值为PLLCLK数值,则PLLCLK被选为系统时钟
代码如下
函数的形参根据函数中需要传入的数据所设定
void HSE_SetSysclk ( uint32_t PLLM, uint32_t PLLN, uint32_t PLLP, uint32_t PLLQ)
{
RCC_HSEConfig(RCC_HSE_ON);
if(RCC_WaitForHSEStartUp()==SUCCESS)
{
RCC_HCLKConfig(RCC_SYSCLK_Div1);
RCC_PCLK1Config(RCC_HCLK_Div4);
RCC_PCLK2Config(RCC_HCLK_Div2);
RCC_PLLConfig(RCC_PLLSource_HSE,PLLM, PLLN, PLLP, PLLQ);
RCC_PLLCmd(ENABLE);
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET);
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
while(RCC_GetSYSCLKSource()!=0x08);
}
else
{
while(1)
{
}
}
}