STM32单片机学习(35) —— 时钟树
时钟/时钟信号的概念
在 STM32 微控制器中,时钟信号是整个系统运行的基础与核心。
它为处理器、总线结构以及各类片上外设提供统一的时间基准与驱动节奏。

几乎所有功能模块都依赖时钟信号才能正常工作,包括:
- 中央处理器(CPU)
- 存储器接口
- AHB/APB 总线
- 定时器
- 串行通信外设(UART、SPI、I2C、CAN)
- 模拟外设(ADC、DAC)
- 看门狗定时器(IWDG、WWDG)
- 低功耗管理模块
- ...
怎么理解这个时钟信号呢?
通俗地讲,时钟信号就是一种周期性变化的高低电平信号。
它不断在“高电平”和“低电平”之间切换,形成一个稳定的节奏。
这种周期性的翻转,为整个数字电路系统提供了统一的“时间刻度”。
所有寄存器什么时候更新、数据什么时候采样、状态什么时候改变,都依赖这个节奏。
更准确地说,时钟信号是一种周期性方波信号,其上升沿或下降沿通常被用作触发数字电路状态变化的时刻。
比如我们之前学习SPI通信时,采样时机的边沿设置,就是时钟信号作用的体现:

从本质上讲,时钟的作用主要体现在以下几个方面:
- 提供系统运行的基本节奏,使各模块在统一时间尺度下运转。
- 保证数据传输与逻辑运算的同步性与正确性。
- 协调不同功能模块之间的协同动作。
- 通过选择不同的时钟源与分频策略,实现性能与功耗之间的平衡。
STM32 的时钟系统通常由多个时钟源构成,例如:
- 高精度内部时钟 HSI
- 低功耗内部时钟 LSI
- 高精度外部晶振 HSE
- 低功耗外部晶振 LSE
通过 RCC(Reset and Clock Control)片上外设模块构建的“时钟树”。
可以对各级总线与外设进行分频、选择与分配,实现灵活的时钟管理与性能控制。
举一个典型例子:
// 开启 GPIOA 的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
上述代码的本质,是修改 RCC 模块中的相关寄存器(例如 RCC->APB2ENR),为对应的外设提供时钟信号。
APB2ENR 寄存器负责控制如 GPIOA、GPIOB、ADC1、USART1 等外设的时钟使能状态。
所谓“开启时钟”,本质上就是为某个硬件模块提供周期性的脉冲信号。
这个脉冲信号在物理层面表现为持续的高低电平翻转,例如 8 MHz 的时钟,意味着每秒钟发生 8,000,000 次电平变化。
数字电路内部依赖这种周期性的电平变化来驱动触发器、状态机以及各种组合逻辑完成数据采样与状态更新。
如果某个外设没有时钟输入,那么其内部逻辑将停止翻转,相当于进入“静止”状态。
虽然并非真正意义上的断电,但由于内部逻辑不再切换,功耗会显著降低。
因此,STM32 在默认情况下并不会自动开启所有外设时钟。
大多数片上外设在复位后都是关闭状态。
在实际开发过程中,如果需要使用某个外设,第一步往往就是通过 RCC 为其开启时钟,否则即使配置寄存器,也不会产生实际效果。
可以这样理解:
时钟之于 STM32,就如同心跳之于生命系统。
没有时钟,所有数字逻辑都无法运行;
有了时钟,整个芯片才能按照既定的节奏协调工作。
时钟树的概念
时钟从哪里来?又是如何分配到各个模块的?
我们已经知道,在 STM32 中,无论是片上外设、总线数据传输,还是 CPU 内部的逻辑计算单元运行,都离不开时钟信号。
那么问题来了:
这些时钟信号是谁提供的?不同来源的时钟,又是如何被传递到不同的物理硬件区域的?
这个问题的答案,都在下图——时钟树当中。


上图所示的 STM32F10x 时钟树,本质上就在回答这几个问题。
虽然整张图看起来十分复杂,但如果换一个角度,可以把它拆分为三个阶段来理解。
- 时钟源输入
- 这是整棵时钟树的起点。
- 包括 HSI、HSE、LSI、LSE 等内部或外部振荡源。
- 这一部分解决的是:谁来产生最原始的周期性方波信号。
- 时钟选择 / 分频 / 倍频处理
- 这一层主要由 PLL 和各级分频器完成。
- 它的作用是对原始时钟进行加工处理。
- 有的需要提高频率(倍频),有的需要降低频率(分频),有的需要在多个时钟源之间进行切换选择。
- 这一阶段最终决定了 SYSCLK、HCLK、PCLK1、PCLK2 等关键系统时钟的数值。
- 输出到系统 / 外设 / 接口
- 加工完成后的时钟,会被分配到不同功能模块。
- 例如 HCLK 送往 AHB 总线、内核和 DMA;
- PCLK1 送往 APB1 外设;
- PCLK2 送往 APB2 外设;
- USB、ADC、RTC 等则有各自独立的时钟分支。
- 这一部分解决的是:哪一个模块,使用哪一路时钟。
如果用一个形象的比喻来理解:
时钟树就像一个供电网络。
上游是发电厂(时钟源)
中间是变压站(分频、倍频、选择);
下游是不同等级的用户(CPU、总线、外设)。
这样拆开来看,原本复杂的时钟树,其实就是一个清晰的三段结构:
时钟源输入 → 时钟加工处理 → 时钟分发到各模块。
理解了这个框架之后,再回头分析具体的分支,就会变得非常清晰。
时钟源
在 STM32F10x 系列微控制器中,时钟并不是只有一种来源。
为了兼顾性能、稳定性、功耗以及不同应用场景的需求,芯片内部一共提供了四种基础时钟源:
- HSI(High Speed Internal)高速内部 RC 振荡器,即高速内部时钟源
- HSE(High Speed External)高速外部晶振,即高速外部时钟源
- LSI(Low Speed Internal)低速内部 RC 振荡器,即低速内部时钟源
- LSE(Low Speed External)低速外部晶振,即低速外部时钟源
时钟树的所有分支,最终都可以追溯到这四个“原始振荡源”。
它们是整套时钟系统的起点,也是系统时钟架构设计的根基。
接下来,我们逐一分析 STM32F10x 所提供的四种时钟源,以及它们各自的特点和典型用途。
HSI高速内部时钟源
HSI 是 STM32F10x 内部集成的高速 RC 振荡器,其典型工作频率为 8 MHz。
该振荡器直接集成在 STM32F103 芯片内部,无需外接晶振或其他外围器件,上电即可工作。
HSI 的产生方式是 RC 振荡。
所谓 RC 振荡器,是利用电阻(R)与电容(C)构成的充放电网络,通过电压的周期性变化形成振荡信号。
这种振荡信号本质上就是周期性变化的高低电平方波,也就是我们所说的时钟信号。
RC 振荡器的优点是结构简单、体积小、启动速度快、无需外部器件、成本低。
但它的缺点也很明显:频率精度不高,误差较大。
即便经过出厂校准,HSI 的典型精度误差约为 ±1%,在极端情况下可能达到 ±2.5%(易受温度等环境量的改变而增加误差)。
因此它更适用于对时钟精度要求不高的应用场景,例如一般逻辑控制、GPIO 操作、简单通信实验等。
对于 STM32F103 系列单片机而言,HSI 是一个非常重要的时钟源:
由于上电启动速度快,MCU 上电复位后,默认使用 HSI 作为系统时钟(SYSCLK)的时钟源。
也就是说,如果用户不做任何时钟配置,默认情况下,系统在启动阶段,会直接运行在 8 MHz 的 HSI 上。
当然:
单片机内部还会对时钟源信号做一些处理,比如分频和倍频:
- 分频:分频的作用是降低时钟频率,直白点说就是让原始时钟信号的频率除以一个整数。
- 倍频:倍频的作用是提高时钟频率,直白点说就是让原始时钟信号的频率乘以一个整数。
简单总结:
- 分频是把时钟变慢。
- 倍频是把时钟变快。
单片机内部会根据 CPU、总线和外设的需要,对时钟源信号进行分频或倍频处理,以满足不同模块对时钟信号的需求。
在 STM32 的时钟系统中,不同模块对频率的需求不同,因此往往需要通过分频器将时钟调整到合适的数值。
简单理解,几分频,就是把时钟频率除以几。
因此,当 HSI 作为 PLL 输入时,其实际进入 PLL 的频率为 4 MHz,而不是原始的 8 MHz。
总结一下 HSI 的几个关键特征:
- MCU内部集成,无需外部晶振
- 默认上电即启用,启动速度快
- 频率 8 MHz
- 精度相对较低
- 可作为系统启动时的初始时钟信号源
理解了 HSI,你就掌握了 STM32 最基础、最“原始”的时钟来源。
HSI作为系统时钟源
当然如果只用文字讲 HSI,有点抽象。我们不妨结合时钟树来看,如下图所示:

在图的左上角,可以看到:8 MHz HSI RC
这就是 HSI 的物理位置,也是整条路径的起点。
它先产生一个 8 MHz 的周期性时钟方波信号。
这就是最原始的内部高速时钟。
简单介绍一下图中涉及的一些数字功能单元:
- PLL(Phase Locked Loop)锁相环:用于将输入的参考时钟进行倍频处理,从而生成更高频率的时钟。
- PLLSRC(PLL Source)PLL时钟源选择:这是一个多路选择器,用于选择哪一路时钟作为 PLL 的输入来源,例如 HSI/2 或 HSE。
- PLLMUL(PLL Multiplier)PLL倍频系数:用于设置 PLL 的倍频倍数,将输入频率按设定系数放大。
- SW(System Clock Switch)系统时钟切换开关:这是一个多路选择器,用于选择当前系统时钟 SYSCLK 的来源,例如 HSI、HSE 或 PLLCLK。
- PLLCLK(PLL Clock)PLL输出时钟:指 PLL 经过倍频处理后输出的时钟信号,可作为系统主时钟候选源。
- SYSCLK(System Clock)系统主时钟:是整个芯片运行的核心时钟,最终供给 CPU 和各级总线分频使用。
接下来依照图中红线来看,HSI 主要有两条去向。
- 直接进入 SW,HSI 可以不经过任何处理,直接送到 SW。
- 如果在 RCC_CFGR 寄存器中将 SW 选择为 HSI,那么:
- SYSCLK = 8 MHz
- 这也是 STM32F103 上电复位后的默认状态。
- 在这种情况下,CPU、AHB 总线以及后续分频得到的 APB1、APB2 时钟,全部建立在 8 MHz 的基础上运行。
- 此时系统时钟结构最简单、启动最快,但主频较低,运行速度较慢且不准确。
- 经过 2 分频后再送入 PLL
- 在图中可以看到,HSI 在进入 PLL 之前,会先经过一个 “/2” 分频单元。
- 也就是说:8 MHz → 2 分频 → 4 MHz → 作为 PLL 输入
- 这是 STM32F10x 架构上的一个固定规则:HSI 作为 PLL 输入时,必须先进行 2 分频。
- 进入 PLL 后,再通过 PLLMUL 设置倍频系数,例如 ×6、×9 等。
- 例如:4 MHz × 9 = 36 MHz
- 得到 PLLCLK 后,再通过 SW 选择 PLL 作为系统时钟来源。
- 如果 SW 选择 PLLCLK,那么:
- SYSCLK = PLL 输出频率
- 这样就可以在内部 RC 时钟的基础上,提高系统运行频率。
- 这种设置不是默认配置,需要手动进行配置。
综合来看,HSI 的角色可以概括为:
- 它是系统默认的启动时钟来源
- 它可以直接作为系统主时钟
- 它也可以参与 PLL 进行倍频后再作为系统时钟
- 但由于频率和精度都相对有限,不适用于对频率精度要求较高、或对速率要求较高的场景
- 通常来说,STM32F10X单片机在默认情况下,只在上电启动时直接选择HSI作为系统时钟源,其余时候通常不使用HSI作为时钟源。
理解了 HSI 的这两条路径,你就已经掌握了时钟树中最基础的一段逻辑流程:
时钟源产生 → 选择是否加工 → 选择是否作为系统主时钟 → 再分配给各级总线与外设。
从单片机上电启动理解HSI的作用
第一步,上电瞬间(硬件阶段)
当 STM32 上电或复位时,芯片内部的复位逻辑首先工作。
此时发生两件关键事情:
- 高速内部时钟源 HSI 自动开启工作
- 系统时钟默认选择 HSI 作为 SYSCLK 系统时钟的时钟源
也就是说:
上电启动瞬间后,CPU 就运行在 8 MHz 的 HSI 上。
这一步是硬件自动完成的,不依赖任何软件代码。
如果没有 HSI 这个默认时钟,CPU 没有任何时钟信号,根本无法开始执行指令。
第二步,CPU读中断向量表的入口地址,也就是0x00000000,获取MSP主栈栈顶指针。
CPU会从该地址中读出一个 32 位数据,加载到 MSP(主栈指针)寄存器中。
这一步完成后:
主栈空间被建立,CPU 拥有了可用的主栈环境。
如此,CPU就可以开始调用函数,正式开始执行指令了。
第三步,CPU 读取中断向量表中地址 0x00000004。
CPU会从该地址取出复位处理函数地址,也就是 Reset_Handler 函数的入口地址。
随机开始执行此函数。
第四步,CPU 执行函数 Reset_Handler(执行汇编代码阶段)
在启动文件中可以看到,这个汇编代码函数,其实主要是调用了两个函数:
- 先调用 SystemInit()
- 最终调用 main()
此时整个执行过程仍然运行在 HSI 8 MHz 主频下。
这部分代码截图如下:

汇编代码我们不需要掌握,总得来说,这段汇编代码,相当于调用了这样的一个函数:
void Reset_Handler(void){
SystemInit();
__main(); // 进入C运行库,并最终调用main函数
}
第五步,调用SystemInit()函数(执行C语言代码)
在该函数中:
- 再次确保 HSI 处于开启状态
- 清除 RCC 时钟配置寄存器
- 关闭 PLL、HSE 等可能残留的配置
- 将时钟系统恢复到可控的默认状态
此时主系统时钟源仍然是 HSI。
这部分源码如下:

第六步,在SystemInit()函数完成上述配置后,调用 SetSysClock() 函数,默认配置HSE作为主系统时钟源。
在默认情况下,在不修改此函数源码的前提下(通常都不会改):
该函数是这么操作的:
- 先开启外部高速晶振 HSE = 8 MHz
- 等待 HSE 稳定
- 配置 PLL:
- 选择 HSE 作为 PLL 输入
- 设置倍频系数 ×9
- 得到:8 MHz × 9 = 72 MHz
- 修改 RCC_CFGR 寄存器的 SW 位
- 将系统时钟源从默认的 HSI = 8 MHz
- 切换为 PLLCLK = 72 MHz(此时PLLCLK是倍频后的HSE)
当切换完成后:
系统主时钟正式由 “HSE 经 PLL 倍频后“ 接管,此时主系统时钟频率是 72MHz。
CPU 不再运行在 HSI 上,而是运行在新的HSE主频下。
从这一刻开始:
- CPU 主频 = 72 MHz
- AHB 总线 = 72 MHz
- APB1 = 36 MHz(默认 /2)
- APB2 = 72 MHz
也就是说:
CPU 从最初的 HSI 8 MHz 运行,正式切换为 72 MHz 高速运行模式。
这部分源码如下:


第七步,开始调用main函数(主系统时钟源已变为HSE)。
此时:
- 系统时钟已经完成切换
- 主频已达到目标频率(例如 72 MHz)
- AHB、APB 总线分频关系已生效
整个 MCU 进入用户程序阶段,单片机真正开始执行用户程序。
HSE高速外部时钟源
HSE(High Speed External)高速外部时钟源,为 STM32F10x 提供的高速外部时钟源。
其工作频率范围一般为 2 ~ 16 MHz。
在我们当前使用的 STM32F103C8T6 最小系统板上,HSE高速外部时钟源为 8 MHz。
如下图所示:

HSE高速外部时钟源
HSE(High Speed External)高速外部时钟源,为 STM32F10x 提供的高速外部时钟源。
其工作频率范围一般为 2 ~ 16 MHz。
在我们当前使用的 STM32F103C8T6 最小系统板上,HSE高速外部时钟源为 8 MHz。
如下图所示:

与 HSI 不同,HSE 并不集成在芯片内部。
它来自芯片外部的石英晶振,通过 OSC_IN 和 OSC_OUT 两个引脚接入 MCU。
对于STM32F103C8T6单片机来说,HSE外部晶振,实际上占用PD0和PD1两个引脚,一个用于输入,一个对外输出。
如下图所示:

因为我们使用的是最小系统板,这两个引脚都已经被占用了。所以一般是不能再作为PD0和PD1使用了。
HSI 是“芯片内部自带的时钟”,而 HSE 是“外接晶振提供的时钟”。
那为什么HSE这种石英材质的时钟源,更加准确稳定呢?
石英晶振的原理可以简单理解为:石英是一种压电材料。
当对石英晶体施加电压时,它会产生机械振动。
在特定尺寸和结构下,它会在某一个固定频率上发生稳定共振。
这种机械振动会被电路转换为稳定的电信号,从而形成周期性的时钟方波。
由于石英晶体的物理特性非常稳定,因此 HSE 的频率精度远高于内部 RC 振荡器,误差通常只有万分之一到万分之三左右。
从性能特点来看,HSE 具有两个核心优势:
- 频率稳定,误差小
- 不会像HSI那样,会随着温度变化导致频率偏移,术语叫“抗温漂能力强“。
因此HSE适用于对时钟精度要求较严格的场景,比如一些通信的场景,精准定时的场景。
这些外设如果使用精度较低的 HSI,可能会产生误差导致功能失效。
HSE的用途
在时钟树结构中,HSE 主要有两个用途:
- 可以直接作为系统时钟源(SYSCLK)
- 更常见的用法是作为 PLL 的输入源
比如STM32F103C8T6单片机,它的默认系统时钟主频为 72 MHz,其实现方式通常是:
HSE = 8 MHz,PLL × 9,SYSCLK = 72 MHz
如下图所示:

也就是说:
HSE 提供稳定的参考频率,PLL 再对其进行倍频,最终生成高频系统主时钟。
HSI和HSE的差别
如果从系统运行阶段来看,可以把 HSI 和 HSE 理解为两个不同角色:
- HSI 负责“上电启动兜底”。
- 它集成在芯片内部,上电自动开启,不依赖任何外部器件。
- 只要 MCU 上电,HSI 就一定存在,因此系统一定能够跑起来。
- 它的优势是简单、可靠、无需外部电路、启动速度快。
- 但它的精度相对较低,本质上是 RC 振荡器,受温度、电压等因素影响较大。
- HSE 则更多承担“系统稳定运行阶段的主时钟来源”。
- 它来自外部石英晶振,频率稳定,误差小。
- 在系统完成初始化后,通常会切换到 HSE 经 PLL 倍频后的时钟作为 SYSCLK。
- 它的优势是精度高、稳定性好,适合对时序要求严格的应用场景。
因此可以这样理解:
HSI 是保证系统一定能启动的基础时钟,它解决的是“能不能跑起来”的问题。
HSE 是保证系统高性能、高精度运行的核心时钟源,它解决的是“跑得快不快、准不准”的问题。
如果用一个形象的比喻:
HSI 像是芯片内部自带的应急发电机,保证设备一开机就有电。
HSE 像是外接的稳定市电电源,在系统进入正常运行后,由它提供长期、稳定、高质量的电力。
或者:
HSI 是机器人的备用临时电池,刚启动复位的时候先用备用临时电池顶一顶。
HSE 则是机器人的长期稳定能量来源,机器人的长期工作运行,需要使用 HSE 这种长期、稳定、高质量的能量来源。
HSI和HSE,这两者并不是互相替代关系,而是启动阶段与运行阶段各司其职。
了解:CSS时钟安全系统
CSS(Clock Security System)时钟安全系统
在实际应用中,外部晶体振荡器在运行过程中是有可能出现异常的,例如振荡停止、频率漂移、焊接问题或环境干扰等。
也就是说:
如果系统主时钟来自 HSE(高速外部时钟),那么在运行过程中是存在失效风险的。
而在 STM32 的时钟结构中,HSE 是直接接入 CSS 监控逻辑的。
CSS 的作用机制
当 CSS 监测到 HSE 振荡异常或停止时,会立即触发硬件保护机制。
此时硬件会自动执行以下动作:
- 检测到 HSE 故障(HSERDY 失效)
- 关闭 HSE
- 自动将系统时钟来源切换为 HSI
- 触发 NMI 中断(通知系统异常发生)
也就是说,系统主时钟原本路径是:HSE → PLL → SYSCLK
发生异常后会自动变为:HSI → SYSCLK
无需软件主动干预,硬件即可完成这样的切换。
切换的本质
这种切换并不是“软件重新配置”,而是硬件在底层自动修改 RCC 寄存器中的时钟选择逻辑。
通过控制 SW 选择器,将系统时钟来源从外部高速时钟路径,
切换为内部高速时钟 HSI。
目的只有一个:保证系统不会因为外部晶振失效而立刻停止运行。
为什么必须这样设计?
如果没有 CSS:一旦 HSE 停振失效,CPU 将失去时钟信号,系统立即崩溃。
而有了 CSS:系统可以退回到内部 RC 时钟,在HSI时钟源的驱动下,继续运行。
至少保证:程序还能执行,系统还能响应,起码可以进入安全处理流程。
一句话总结
CSS 是一种硬件级的主时钟容错机制,当 HSE 失效时,系统会自动切换到 HSI,保证 MCU 不会因为外部晶振故障而立刻停机。
LSI低速内部时钟源
LSI(Low Speed Internal)低速内部时钟源,LSI 是 STM32F10x 内部集成的低速 RC 振荡器。
其典型工作频率为 40 KHz。
和 HSI 一样,LSI 也是由 RC 振荡器产生,直接集成在 STM32F103 芯片内部,无需任何外部晶振或外围电路。
也就是说:
只要芯片上电,LSI 就可以作为单片机内部的时钟信号源,但需要软件开启(置位 RCC_CR 的 LSION 位)。
从结构上看,LSI 与 HSI 的原理相同,都是基于 RC 充放电形成周期性振荡信号。
不同的是,二者工作频率不同:
- HSI 是高速(8 MHz),
- LSI 是低速(40 KHz)。
由于 RC 振荡器天生存在精度问题,LSI 的频率波动较大。
虽然典型值为 40 KHz,但在实际环境中可能在 30~50 KHz 范围内波动。
因此它也不适用于对时间精度要求严格的场景。
LSI 的主要用途并不是作为系统主时钟。
它的用途参考下图:

它用于低速、独立运行的模块,例如:
- 独立看门狗 IWDG,该外设用于在程序异常或死机时自动复位系统,保证系统可靠运行。
- 实时时钟 RTC,F1系列的 RTC 外设实际上就是一个32位秒计时器,即使主系统掉电也可依靠后备电源继续计时。
需要特别注意的是:独立看门狗 IWDG 必须使用 LSI 作为时钟源。
这是为了保证:
即使主系统时钟异常(例如 HSE 故障或 PLL 失锁),
看门狗仍然能够独立运行,从而在系统失控时完成复位保护。
至于 RTC,在大多数正式产品中,通常更倾向于使用 LSE(外部 32.768 KHz 晶振),
因为 LSE 精度更高,更适合长期计时。
最后用一句话概括:
LSI 是一颗低速、内部集成、精度一般,但具备独立性和可靠性的时钟源。
它最主要的,最常用的用途就是为独立看门狗提供时钟信号源。
LSE低速外部时钟源
LSE 是 STM32F10x 提供的低速外部时钟源,其标准工作频率为 32.768 KHz。
这个数值并不是随意选择的:
- 32.768 KHz = 215 Hz。
- 如果连续进行 15 次 2 分频
- 32.768 KHz → 1 Hz
也就是说:
经过分频后,可以非常方便地得到 1 秒的时间基准。
这正是它被广泛用于实时时钟(RTC)的根本原因。
与 HSE 类似,LSE 并不集成在芯片内部。
它和HSE一样,来自外部的低速石英晶振(通常为 32.768 KHz 晶振),
通过 OSC32_IN 和 OSC32_OUT 两个专用引脚接入芯片,如下图所示:

这种晶振通常被称为“表晶”或“时钟晶振”,常见于电子手表、RTC 芯片等精密计时设备。
从精度角度来看:LSE 的稳定性远高于 LSI。
它受温度和电压变化的影响较小,适合用于长时间、连续运行的时间计量。
因此在实际产品中:RTC 通常优先选择 LSE 作为时钟源。
在 STM32F103 中,LSE 的主要用途就是:为 RTC 提供稳定、精准的低速时钟。
它不参与系统主频生成,不参与 PLL,也不直接供给 CPU 或高速外设。
在时钟树中,LSE的功能部分如下图所示:

可以看到,LSE外部低速时钟源,最核心、最常见的用途就是作为RTC实时时钟的时钟信号源。
总结
从系统角色分工来看:
- HSI 负责上电启动与基础运行,
- HSE 负责系统的高速与高精度运行,
- LSI 负责低速、独立、安全相关模块,
- LSE 负责高精度、长期稳定的时间计量。
四种时钟源并不是相互替代关系,而是各司其职、分工明确:
- HSI 解决的是“系统能否可靠启动”的问题;
- HSE 解决的是“系统是否运行得快且准”的问题;
- LSI 保障的是“在主时钟异常时,关键模块仍能独立工作”;
- LSE 则提供“长期稳定的时间基准”。
如果从整体架构角度理解:这四个时钟源共同构成了 STM32 时钟体系的根基。
它们通过时钟树被选择、加工、分配,最终支撑整个 MCU 的运行。
理解了这四个时钟源的定位与差异,就等于掌握了 STM32 时钟系统的核心逻辑。
SYSCLK系统主时钟
前面我们介绍了四种时钟源。
但如果继续深入研究时钟树结构,就会发现一个非常关键的“汇聚点”——SYSCLK。
除了少数特殊模块(例如 IWDG 使用 LSI、RTC 使用 LSE、USB 有独立时钟要求)之外,
绝大多数功能单元的时钟,最终都会以 SYSCLK 为基础进行分配,所以 SYSCLK 其实也可以视为一个时钟源。
SYSCLK(System Clock,系统时钟)是 STM32 单片机最核心、最主要的时钟源。
它本身并不产生时钟信号,而是从 HSI、HSE 或 PLLCLK 中选择其中一路作为系统主时钟。
这个选择是通过 RCC_CFGR 寄存器中的 SW 位完成的。
也就是说:
SYSCLK 是“被选出来的最终主时钟”。
系统主时钟的重要性
SYSCLK 的地位非常重要,它是整个芯片内部时钟体系的中心节点:
- CPU 的运行频率直接由 SYSCLK AHB 总线时钟(简称为HCLK)决定。
- AHB 总线时钟(简称为HCLK)由 SYSCLK 分频得到。、
- APB1、APB2 总线时钟(PCLK1、PCLK2)也都是在 SYSCLK 基础上继续分频派生。
- ...
进一步来看:
GPIO、USART、SPI、I2C、TIM 等大多数外设,
都是通过 APB 或 AHB 总线获得它们的工作时钟。
换句话说:
SYSCLK 决定了系统整体运行节奏。
SYSCLK 是整棵时钟树的“中枢节点”
系统主时钟输送时钟信号
单片机内部绝大多数片上外设,以及CPU的运行,它的时钟信号来源都是系统主时钟SYSCLK 。
但SYSCLK 并不会直接把时钟信号送出去,而是按照层级进行分发。
时钟树对这种输送路径,有明确的描述,如下图所示:

下面分为几部分专门讲解一下这种时钟信号的输送。
HCLK系统主干时钟
时钟输送路径如下:
SYSCLK → AHB Prescaler(AHB 分频器) → HCLK
也就是图中红线部分。
HCLK 是 AHB 总线时钟(包含上面挂载的外设),同时也是 Cortex-M3 内核CPU、DMA 控制器以及片上 SRAM / Flash 接口的工作时钟。
最重要的:
CPU 主频 = HCLK
如果 AHB 分频器为 1:
HCLK = SYSCLK
这就是默认选项,CPU默认主频就是72MHz
如果分频为 2:
HCLK = SYSCLK / 2
此时CPU的主频就是36MHz
除此之外,居于CPU内核当中的NVIC,它所使用的时钟频率也和CPU保持一致。
而 SysTick 默认使用 HCLK 作为时钟源(也可选择 HCLK/8),在默认配置下其频率页与 CPU 相同。
APB2 和 APB1外设总线时钟
HCLK 继续分发到两个重要分支:
HCLK → APB2 Prescaler(APB2 分频器) → PCLK2
HCLK → APB1 Prescaler(APB1 分频器)→ PCLK1
也就是图中蓝线部分。
APB2(高速外设总线)
- 最大 72 MHz
- 典型外设:
- GPIO
- USART1
- SPI1
- TIM1
- ADC
APB1(低速外设总线)
- 最大 36 MHz
- 典型外设:
- USART2/3
- I2C
- SPI2
- TIM2~7
- CAN
如果 SYSCLK = 72 MHz,且 APB1 必须至少分频为 2,否则会超出 36 MHz 上限。
特别需要注意的是:
APB 外设总线时钟 ≠ 挂载外设的时钟!
比如USART外设,其波特率来源于内部波特率寄存器,对时钟信号的分频。
定时器倍频设定
图中绿框框中的部分,属于定时器(Timer)外设的时钟控制部分。
注意,所有的定时器都挂载在APB总线上,可能是APB2,也可能是APB1。
但存在一个特殊规则:
如果 APBx 分频系数 ≠ 1,则:TIM x CLK = PCLK × 2,也就是时钟频率直接在APB总线的基础上乘以2。
例如:
SYSCLK = 72 MHz,APB1 分频 = 2,则APB1总线的时钟频率为36MHz。
但由于分频系数为2,触发特殊规则:
实际所有挂载在APB1总线上的定时器,其时钟频率仍然保持为72MHz!
这样设计的目的是:
在降低外设总线频率的同时,不降低定时器的时间分辨率。
通俗点说就是:APB 可以慢一点省电,但定时器需要精准所以不能满,芯片偷偷把时钟补回来。
ADC独立分频机制
所有 ADC 外设都挂载在 APB2 外设总线 上。
ADC 时钟来源于对 APB2 时钟的分频。
输送路径为:
PCLK2 → ADC Prescaler(ADC分频器) → ADCCLK
分频系数可选:2 / 4 / 6 / 8
STM32F103 系列单片机,存在明确的硬件约束:
ADCCLK ≤ 14 MHz
这是 STM32F103 数据手册规定的最大 ADC 输入时钟。
举一个例子:
在默认情况下:
SYSCLK = 72 MHz
AHB 不分频 → HCLK = 72 MHz
APB2 不分频 → PCLK2 = 72 MHz
此时:
如果选择:
2 分频 → 36 MHz ❌ 超出 14MHz
4 分频 → 18 MHz ❌ 仍然超标
6 分频 → 12 MHz ✅ 合法
8 分频 → 9 MHz ✅ 合法
因此:
当 PCLK2 = 72MHz 时,ADC 至少需要 6 分频。
扩展/了解:时钟输出功能
前面我们讲到的时钟源选择、SYSCLK 生成以及 CSS 时钟安全系统,本质上解决的是一个问题:
系统内部使用哪个时钟源,以及如何保证系统稳定运行。
也就是说:
我们讨论的是“时钟从哪里来”,以及“系统内部如何使用时钟”。
但如果换一个角度思考:
芯片内部产生的时钟信号,是否只能供芯片内部使用?
答案是:
当然不是。
在实际工程中,芯片产生的时钟也可以输出到芯片外部,供其他器件使用。
这就是所谓的:时钟输出功能,MCO(Microcontroller Clock Output)。
在 STM32F103C8T6 中,提供了一个专门的时钟输出引脚:
MCO 引脚(PA8)

通过该引脚,可以将芯片内部的某一路时钟信号输出到外部。
比如可以给一个外部 MCU 提供参考时钟。
MCO 的工作方式:
MCO 输出的时钟来源可以通过 RCC 寄存器进行选择。
具体是修改:
RCC->CFGR 寄存器中的 MCO 位
可选的输出时钟源包括:
- PLLCLK / 2:PLL 倍频后的时钟,再进行 2 分频
- HSI:高速内部时钟
- HSE:高速外部晶振时钟
- SYSCLK:当前系统主时钟
也就是说:
MCO 不是固定输出某个时钟,
而是可以通过软件选择输出哪一路时钟。
如下图所示:

本质理解
MCO 的作用是:
将芯片内部的某一路时钟,通过引脚“导出”到外部。
它本质上是一个时钟多路选择器 + 输出驱动电路。
可以理解为:
系统内部的时钟信号,不仅可以用于片上外设,也可以作为“公共时钟源”提供给外部系统。
MCO 是 STM32 提供的时钟输出功能,通过 PA8 引脚将内部选定的时钟信号输出到芯片外部。

浙公网安备 33010602011771号