时钟来源有四个:外部高速晶振HSE(一般是8M),外部低速晶振(32.768K)。内部高速RC振荡器HSI(8M),内部低速RC振荡器LSI(40K)。内部的时钟一般没有外部晶振准,一般用外部时钟来初始化。在STM32F1系列库函数文件里包含一个文件
******************************************************************************
* @file system_stm32f10x.c
* 作者:MCD 应用团队
* 版本 V3.5.0
* @日期 2011 年 3 月 11 日
* @brief CMSIS Cortex-M3 器件外设访问层系统源文件。
*
* 该文件提供了两个函数和一个全局变量,可从以下应用程序调用
* 用户应用程序调用:
* SystemInit(): 设置系统时钟(系统时钟源、PLL 倍增器、AHB/APF
* 系数、AHB/APBx 预分频器和闪存设置)。
* 该函数在重置后启动时调用,并在分支到主程序之前调用。
* 在分支到主程序之前调用。该调用在
* stm32f10x_xx.s "文件中调用。
*
* SystemCoreClock 变量: 包含内核时钟 (HCLK),用户应用程序可以使用它来设置系统内核时钟。
* 用户应用程序可使用它来设置 SysTick
* 定时器或配置其他参数。
*
* - SystemCoreClockUpdate(): 更新变量 SystemCoreClock,每当内核时钟发生变化时必须调用。
* 在程序执行过程中改变核心时钟时
* 在程序执行过程中
2. 每次设备复位后,HSI(8 MHz)都被用作系统时钟源。
* 然后调用 "startup_stm32f10x_xx.s "文件中的 SystemInit() 函数,以
* 在分支到主程序之前配置系统时钟。
*
* 如果用户选择的系统时钟源无法启动,SystemInit()
* 函数将不起作用,HSI 仍将用作系统时钟源。用户可以
* 在 SetSysClock() 函数中添加一些代码来解决这个问题。
*
4. HSE 晶体的默认值设置为 8 MHz(或 25 MHz,取决于*所使用的产品),请参阅 "HSE"。
* 请参阅 "stm32f10x.h "文件中的 "HSE_VALUE "定义。
* 直接或通过 PLL 将 HSE 用作系统时钟源时,如果使用不同的晶振,则必须对 HSE_VALUE 进行调整。
* 当 HSE 直接或通过 PLL 用作系统时钟源,而您使用不同的晶振时,您必须调整 HSE 值以适应您自己的
* 配置。
*
******************************************************************************
* 注意
*
* 本固件仅供参考,旨在为客户提供
* 本固件仅供参考,旨在为客户提供有关其产品的编码信息,以便客户节省
* 时间。因此,意法半导体公司不承担任何
* 因此,对于因这些固件和软件的内容而引起的任何索赔,意法半导体不承担任何直接、间接或间接的损害赔偿责任。
* 因此,对于因此类固件的内容和/或客户使用其中包含的
* 编码信息而引起的任何索赔。
*
在单片机上电后会自动初始化好时钟来源与主频。可以通过修改这个文件来达到自己时钟源初始化的配置
一般我们配置时钟源来自外部高速晶振不分频,经过锁相环倍频9倍后,得到72M时钟。配置系统时钟来源倍频器。然后SYSCLK就是来源于PLL的72M主频了,可以通过RCC库函数来查询SYSCLK时钟来源。然后就是配置AHB分频器,选择不分频,因为我们要得到HCLK-->72M。系统滴答定时器的时钟来源默认是HCLK,这样我们就可以在滴答定时器里计数72得到1us的延时。从而实现相对于准确的延时函数。APB1总线是低速外设总线,如果系统时钟是72M,那么它只能选择最大36M的频率,所以要经过APB1分频2,得到PCLK1-->36M。APB2是高速外设总线,可以不用管,它默认就是不分频。
然后就是实时时钟RTC,一般是用来做和实时相关的东西使用的,像闹钟啊。它的时钟来源可以来自HSE分频128,LSE,LSI。LSI在使用之前一般都要进行校准。
最后MCO是时钟输出,将单片机的时钟向外部输出,来源有4个:锁相环分频2,HSI,HSE,SYSCLK。
以下是配置开启HSE,HSE不分频,锁相环9倍频,系统时钟来自锁相环,HCLK(72M),PCLK1(36M),PCLK2(36M)的代码示例
void SystemClock_Config(void) {
ErrorStatus HSEStartUpStatus;
// 启用外部高速振荡器(HSE)
RCC_HSEConfig(RCC_HSE_ON);
// 等待外部高速振荡器稳定
HSEStartUpStatus = RCC_WaitForHSEStartUp();
if (HSEStartUpStatus == SUCCESS) {
// 外部高速振荡器稳定,配置 PLL
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); // 8MHz * 9 = 72MHz
// 使能 PLL
RCC_PLLCmd(ENABLE);
// 等待 PLL 稳定
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
// 配置系统时钟为 PLL
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
// 等待系统时钟配置完成
while (RCC_GetSYSCLKSource() != 0x08);
} else {
RCC_HSICmd(ENABLE);
// 等待内部高速振荡器稳定
while (RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET);
// 使能 PLL
RCC_PLLCmd(ENABLE);
// 配置 PLL
RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_16); // 8MHz / 2 * 16 = 64MHz
// 等待 PLL 稳定
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
// 配置系统时钟为 PLL
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
// 等待系统时钟配置完成
while (RCC_GetSYSCLKSource() != 0x08);
}
// 配置HCLK分频因子为1,即HCLK等于SYSCLK
RCC_HCLKConfig(RCC_SYSCLK_Div1);
// 配置PCLK1分频因子为2,即PCLK1等于HCLK除以2
RCC_PCLK1Config(RCC_HCLK_Div2);
// 配置PCLK2分频因子为2,即PCLK2等于HCLK除以2
RCC_PCLK2Config(RCC_HCLK_Div1);
}