G
N
I
D
A
O
L

STM32单片机学习(35) —— 时钟树

时钟/时钟信号的概念

在 STM32 微控制器中,时钟信号是整个系统运行的基础与核心。

它为处理器、总线结构以及各类片上外设提供统一的时间基准与驱动节奏。

F1系列单片机的系统结构体-图

几乎所有功能模块都依赖时钟信号才能正常工作,包括:

  1. 中央处理器(CPU)
  2. 存储器接口
  3. AHB/APB 总线
  4. 定时器
  5. 串行通信外设(UART、SPI、I2C、CAN)
  6. 模拟外设(ADC、DAC)
  7. 看门狗定时器(IWDG、WWDG)
  8. 低功耗管理模块
  9. ...

怎么理解这个时钟信号呢?

通俗地讲,时钟信号就是一种周期性变化的高低电平信号。

它不断在“高电平”和“低电平”之间切换,形成一个稳定的节奏。

这种周期性的翻转,为整个数字电路系统提供了统一的“时间刻度”。

所有寄存器什么时候更新、数据什么时候采样、状态什么时候改变,都依赖这个节奏。

更准确地说,时钟信号是一种周期性方波信号,其上升沿或下降沿通常被用作触发数字电路状态变化的时刻。

比如我们之前学习SPI通信时,采样时机的边沿设置,就是时钟信号作用的体现:

时钟信号的方波-图

从本质上讲,时钟的作用主要体现在以下几个方面:

  1. 提供系统运行的基本节奏,使各模块在统一时间尺度下运转。
  2. 保证数据传输与逻辑运算的同步性与正确性。
  3. 协调不同功能模块之间的协同动作。
  4. 通过选择不同的时钟源与分频策略,实现性能与功耗之间的平衡。

STM32 的时钟系统通常由多个时钟源构成,例如:

  1. 高精度内部时钟 HSI
  2. 低功耗内部时钟 LSI
  3. 高精度外部晶振 HSE
  4. 低功耗外部晶振 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 时钟树,本质上就在回答这几个问题。

虽然整张图看起来十分复杂,但如果换一个角度,可以把它拆分为三个阶段来理解。

  1. 时钟源输入
    1. 这是整棵时钟树的起点。
    2. 包括 HSI、HSE、LSI、LSE 等内部或外部振荡源。
    3. 这一部分解决的是:谁来产生最原始的周期性方波信号。
  2. 时钟选择 / 分频 / 倍频处理
    1. 这一层主要由 PLL 和各级分频器完成。
    2. 它的作用是对原始时钟进行加工处理。
    3. 有的需要提高频率(倍频),有的需要降低频率(分频),有的需要在多个时钟源之间进行切换选择。
    4. 这一阶段最终决定了 SYSCLK、HCLK、PCLK1、PCLK2 等关键系统时钟的数值。
  3. 输出到系统 / 外设 / 接口
    1. 加工完成后的时钟,会被分配到不同功能模块。
    2. 例如 HCLK 送往 AHB 总线、内核和 DMA;
    3. PCLK1 送往 APB1 外设;
    4. PCLK2 送往 APB2 外设;
    5. USB、ADC、RTC 等则有各自独立的时钟分支。
    6. 这一部分解决的是:哪一个模块,使用哪一路时钟。

如果用一个形象的比喻来理解:

时钟树就像一个供电网络。

上游是发电厂(时钟源)

中间是变压站(分频、倍频、选择);

下游是不同等级的用户(CPU、总线、外设)。

这样拆开来看,原本复杂的时钟树,其实就是一个清晰的三段结构:

时钟源输入 → 时钟加工处理 → 时钟分发到各模块。

理解了这个框架之后,再回头分析具体的分支,就会变得非常清晰。

时钟源

在 STM32F10x 系列微控制器中,时钟并不是只有一种来源。

为了兼顾性能、稳定性、功耗以及不同应用场景的需求,芯片内部一共提供了四种基础时钟源:

  1. HSI(High Speed Internal)高速内部 RC 振荡器,即高速内部时钟源
  2. HSE(High Speed External)高速外部晶振,即高速外部时钟源
  3. LSI(Low Speed Internal)低速内部 RC 振荡器,即低速内部时钟源
  4. 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 上。

当然:

单片机内部还会对时钟源信号做一些处理,比如分频和倍频:

  1. 分频:分频的作用是降低时钟频率,直白点说就是让原始时钟信号的频率除以一个整数。
  2. 倍频:倍频的作用是提高时钟频率,直白点说就是让原始时钟信号的频率乘以一个整数。

简单总结:

  1. 分频是把时钟变慢。
  2. 倍频是把时钟变快。

单片机内部会根据 CPU、总线和外设的需要,对时钟源信号进行分频或倍频处理,以满足不同模块对时钟信号的需求。

在 STM32 的时钟系统中,不同模块对频率的需求不同,因此往往需要通过分频器将时钟调整到合适的数值。

简单理解,几分频,就是把时钟频率除以几。

因此,当 HSI 作为 PLL 输入时,其实际进入 PLL 的频率为 4 MHz,而不是原始的 8 MHz。

总结一下 HSI 的几个关键特征:

  1. MCU内部集成,无需外部晶振
  2. 默认上电即启用,启动速度快
  3. 频率 8 MHz
  4. 精度相对较低
  5. 可作为系统启动时的初始时钟信号源

理解了 HSI,你就掌握了 STM32 最基础、最“原始”的时钟来源。

HSI作为系统时钟源

当然如果只用文字讲 HSI,有点抽象。我们不妨结合时钟树来看,如下图所示:

HSI作为系统时钟时钟源-图

在图的左上角,可以看到:8 MHz HSI RC

这就是 HSI 的物理位置,也是整条路径的起点。

它先产生一个 8 MHz 的周期性时钟方波信号。

这就是最原始的内部高速时钟。

简单介绍一下图中涉及的一些数字功能单元:

  1. PLL(Phase Locked Loop)锁相环:用于将输入的参考时钟进行倍频处理,从而生成更高频率的时钟。
  2. PLLSRC(PLL Source)PLL时钟源选择:这是一个多路选择器,用于选择哪一路时钟作为 PLL 的输入来源,例如 HSI/2 或 HSE。
  3. PLLMUL(PLL Multiplier)PLL倍频系数:用于设置 PLL 的倍频倍数,将输入频率按设定系数放大。
  4. SW(System Clock Switch)系统时钟切换开关:这是一个多路选择器,用于选择当前系统时钟 SYSCLK 的来源,例如 HSI、HSE 或 PLLCLK。
  5. PLLCLK(PLL Clock)PLL输出时钟:指 PLL 经过倍频处理后输出的时钟信号,可作为系统主时钟候选源。
  6. SYSCLK(System Clock)系统主时钟:是整个芯片运行的核心时钟,最终供给 CPU 和各级总线分频使用。

接下来依照图中红线来看,HSI 主要有两条去向。

  1. 直接进入 SW,HSI 可以不经过任何处理,直接送到 SW。
    1. 如果在 RCC_CFGR 寄存器中将 SW 选择为 HSI,那么:
    2. SYSCLK = 8 MHz
    3. 这也是 STM32F103 上电复位后的默认状态。
    4. 在这种情况下,CPU、AHB 总线以及后续分频得到的 APB1、APB2 时钟,全部建立在 8 MHz 的基础上运行。
    5. 此时系统时钟结构最简单、启动最快,但主频较低,运行速度较慢且不准确。
  2. 经过 2 分频后再送入 PLL
    1. 在图中可以看到,HSI 在进入 PLL 之前,会先经过一个 “/2” 分频单元。
    2. 也就是说:8 MHz → 2 分频 → 4 MHz → 作为 PLL 输入
    3. 这是 STM32F10x 架构上的一个固定规则:HSI 作为 PLL 输入时,必须先进行 2 分频。
    4. 进入 PLL 后,再通过 PLLMUL 设置倍频系数,例如 ×6、×9 等。
    5. 例如:4 MHz × 9 = 36 MHz
    6. 得到 PLLCLK 后,再通过 SW 选择 PLL 作为系统时钟来源。
    7. 如果 SW 选择 PLLCLK,那么:
    8. SYSCLK = PLL 输出频率
    9. 这样就可以在内部 RC 时钟的基础上,提高系统运行频率。
    10. 这种设置不是默认配置,需要手动进行配置。

综合来看,HSI 的角色可以概括为:

  1. 它是系统默认的启动时钟来源
  2. 它可以直接作为系统主时钟
  3. 它也可以参与 PLL 进行倍频后再作为系统时钟
  4. 但由于频率和精度都相对有限,不适用于对频率精度要求较高、或对速率要求较高的场景
  5. 通常来说,STM32F10X单片机在默认情况下,只在上电启动时直接选择HSI作为系统时钟源,其余时候通常不使用HSI作为时钟源。

理解了 HSI 的这两条路径,你就已经掌握了时钟树中最基础的一段逻辑流程:

时钟源产生 → 选择是否加工 → 选择是否作为系统主时钟 → 再分配给各级总线与外设。

从单片机上电启动理解HSI的作用

第一步,上电瞬间(硬件阶段)

当 STM32 上电或复位时,芯片内部的复位逻辑首先工作。

此时发生两件关键事情:

  1. 高速内部时钟源 HSI 自动开启工作
  2. 系统时钟默认选择 HSI 作为 SYSCLK 系统时钟的时钟源

也就是说:

上电启动瞬间后,CPU 就运行在 8 MHz 的 HSI 上。

这一步是硬件自动完成的,不依赖任何软件代码。

如果没有 HSI 这个默认时钟,CPU 没有任何时钟信号,根本无法开始执行指令。

第二步,CPU读中断向量表的入口地址,也就是0x00000000,获取MSP主栈栈顶指针。

CPU会从该地址中读出一个 32 位数据,加载到 MSP(主栈指针)寄存器中。

这一步完成后:

主栈空间被建立,CPU 拥有了可用的主栈环境。

如此,CPU就可以开始调用函数,正式开始执行指令了。

第三步,CPU 读取中断向量表中地址 0x00000004。

CPU会从该地址取出复位处理函数地址,也就是 Reset_Handler 函数的入口地址。

随机开始执行此函数。

第四步,CPU 执行函数 Reset_Handler(执行汇编代码阶段)

在启动文件中可以看到,这个汇编代码函数,其实主要是调用了两个函数:

  1. 先调用 SystemInit()
  2. 最终调用 main()

此时整个执行过程仍然运行在 HSI 8 MHz 主频下。

这部分代码截图如下:

单片机上电启动过程-图

汇编代码我们不需要掌握,总得来说,这段汇编代码,相当于调用了这样的一个函数:

void Reset_Handler(void){
    SystemInit();
    __main();   // 进入C运行库,并最终调用main函数
}

第五步,调用SystemInit()函数(执行C语言代码)

在该函数中:

  1. 再次确保 HSI 处于开启状态
  2. 清除 RCC 时钟配置寄存器
  3. 关闭 PLL、HSE 等可能残留的配置
  4. 将时钟系统恢复到可控的默认状态

此时主系统时钟源仍然是 HSI。

这部分源码如下:

单片机上电启动过程-图2

第六步,在SystemInit()函数完成上述配置后,调用 SetSysClock() 函数,默认配置HSE作为主系统时钟源。

在默认情况下,在不修改此函数源码的前提下(通常都不会改):

该函数是这么操作的:

  1. 先开启外部高速晶振 HSE = 8 MHz
  2. 等待 HSE 稳定
  3. 配置 PLL:
    1. 选择 HSE 作为 PLL 输入
    2. 设置倍频系数 ×9
    3. 得到:8 MHz × 9 = 72 MHz
  4. 修改 RCC_CFGR 寄存器的 SW 位
    1. 将系统时钟源从默认的 HSI = 8 MHz
    2. 切换为 PLLCLK = 72 MHz(此时PLLCLK是倍频后的HSE)

当切换完成后:

系统主时钟正式由 “HSE 经 PLL 倍频后“ 接管,此时主系统时钟频率是 72MHz。

CPU 不再运行在 HSI 上,而是运行在新的HSE主频下。

从这一刻开始:

  1. CPU 主频 = 72 MHz
  2. AHB 总线 = 72 MHz
  3. APB1 = 36 MHz(默认 /2)
  4. APB2 = 72 MHz

也就是说:

CPU 从最初的 HSI 8 MHz 运行,正式切换为 72 MHz 高速运行模式。

这部分源码如下:

单片机上电启动过程-图3

单片机上电启动过程-图4

第七步,开始调用main函数(主系统时钟源已变为HSE)。

此时:

  1. 系统时钟已经完成切换
  2. 主频已达到目标频率(例如 72 MHz)
  3. 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两个引脚,一个用于输入,一个对外输出。

如下图所示:

HSE占用的引脚-图

因为我们使用的是最小系统板,这两个引脚都已经被占用了。所以一般是不能再作为PD0和PD1使用了。

HSI 是“芯片内部自带的时钟”,而 HSE 是“外接晶振提供的时钟”。

那为什么HSE这种石英材质的时钟源,更加准确稳定呢?

石英晶振的原理可以简单理解为:石英是一种压电材料。

当对石英晶体施加电压时,它会产生机械振动。

在特定尺寸和结构下,它会在某一个固定频率上发生稳定共振。

这种机械振动会被电路转换为稳定的电信号,从而形成周期性的时钟方波。

由于石英晶体的物理特性非常稳定,因此 HSE 的频率精度远高于内部 RC 振荡器,误差通常只有万分之一到万分之三左右。

从性能特点来看,HSE 具有两个核心优势:

  1. 频率稳定,误差小
  2. 不会像HSI那样,会随着温度变化导致频率偏移,术语叫“抗温漂能力强“。

因此HSE适用于对时钟精度要求较严格的场景,比如一些通信的场景,精准定时的场景。

这些外设如果使用精度较低的 HSI,可能会产生误差导致功能失效。

HSE的用途

在时钟树结构中,HSE 主要有两个用途:

  1. 可以直接作为系统时钟源(SYSCLK)
  2. 更常见的用法是作为 PLL 的输入源

比如STM32F103C8T6单片机,它的默认系统时钟主频为 72 MHz,其实现方式通常是:

HSE = 8 MHz,PLL × 9,SYSCLK = 72 MHz

如下图所示:

HSE作为系统时钟时钟源-图

也就是说:

HSE 提供稳定的参考频率,PLL 再对其进行倍频,最终生成高频系统主时钟。

HSI和HSE的差别

如果从系统运行阶段来看,可以把 HSI 和 HSE 理解为两个不同角色:

  1. HSI 负责“上电启动兜底”。
    1. 它集成在芯片内部,上电自动开启,不依赖任何外部器件。
    2. 只要 MCU 上电,HSI 就一定存在,因此系统一定能够跑起来。
    3. 它的优势是简单、可靠、无需外部电路、启动速度快。
    4. 但它的精度相对较低,本质上是 RC 振荡器,受温度、电压等因素影响较大。
  2. HSE 则更多承担“系统稳定运行阶段的主时钟来源”。
    1. 它来自外部石英晶振,频率稳定,误差小。
    2. 在系统完成初始化后,通常会切换到 HSE 经 PLL 倍频后的时钟作为 SYSCLK。
    3. 它的优势是精度高、稳定性好,适合对时序要求严格的应用场景。

因此可以这样理解:

HSI 是保证系统一定能启动的基础时钟,它解决的是“能不能跑起来”的问题。

HSE 是保证系统高性能、高精度运行的核心时钟源,它解决的是“跑得快不快、准不准”的问题。

如果用一个形象的比喻:

HSI 像是芯片内部自带的应急发电机,保证设备一开机就有电。

HSE 像是外接的稳定市电电源,在系统进入正常运行后,由它提供长期、稳定、高质量的电力。

或者:

HSI 是机器人的备用临时电池,刚启动复位的时候先用备用临时电池顶一顶。

HSE 则是机器人的长期稳定能量来源,机器人的长期工作运行,需要使用 HSE 这种长期、稳定、高质量的能量来源。

HSI和HSE,这两者并不是互相替代关系,而是启动阶段与运行阶段各司其职。

了解:CSS时钟安全系统

CSS(Clock Security System)时钟安全系统

在实际应用中,外部晶体振荡器在运行过程中是有可能出现异常的,例如振荡停止、频率漂移、焊接问题或环境干扰等。

也就是说:

如果系统主时钟来自 HSE(高速外部时钟),那么在运行过程中是存在失效风险的。

而在 STM32 的时钟结构中,HSE 是直接接入 CSS 监控逻辑的。

CSS 的作用机制

当 CSS 监测到 HSE 振荡异常或停止时,会立即触发硬件保护机制。

此时硬件会自动执行以下动作:

  1. 检测到 HSE 故障(HSERDY 失效)
  2. 关闭 HSE
  3. 自动将系统时钟来源切换为 HSI
  4. 触发 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 充放电形成周期性振荡信号。

不同的是,二者工作频率不同:

  1. HSI 是高速(8 MHz),
  2. LSI 是低速(40 KHz)。

由于 RC 振荡器天生存在精度问题,LSI 的频率波动较大。

虽然典型值为 40 KHz,但在实际环境中可能在 30~50 KHz 范围内波动。

因此它也不适用于对时间精度要求严格的场景。

LSI 的主要用途并不是作为系统主时钟。

它的用途参考下图:

LSI作用-图

它用于低速、独立运行的模块,例如:

  1. 独立看门狗 IWDG,该外设用于在程序异常或死机时自动复位系统,保证系统可靠运行。
  2. 实时时钟 RTC,F1系列的 RTC 外设实际上就是一个32位秒计时器,即使主系统掉电也可依靠后备电源继续计时。

需要特别注意的是:独立看门狗 IWDG 必须使用 LSI 作为时钟源。

这是为了保证:

即使主系统时钟异常(例如 HSE 故障或 PLL 失锁),

看门狗仍然能够独立运行,从而在系统失控时完成复位保护。

至于 RTC,在大多数正式产品中,通常更倾向于使用 LSE(外部 32.768 KHz 晶振),

因为 LSE 精度更高,更适合长期计时。

最后用一句话概括:

LSI 是一颗低速、内部集成、精度一般,但具备独立性和可靠性的时钟源。

它最主要的,最常用的用途就是为独立看门狗提供时钟信号源。

LSE低速外部时钟源

LSE 是 STM32F10x 提供的低速外部时钟源,其标准工作频率为 32.768 KHz。

这个数值并不是随意选择的:

  1. 32.768 KHz = 215 Hz。
  2. 如果连续进行 15 次 2 分频
  3. 32.768 KHz → 1 Hz

也就是说:

经过分频后,可以非常方便地得到 1 秒的时间基准。

这正是它被广泛用于实时时钟(RTC)的根本原因。

与 HSE 类似,LSE 并不集成在芯片内部。

它和HSE一样,来自外部的低速石英晶振(通常为 32.768 KHz 晶振),

通过 OSC32_IN 和 OSC32_OUT 两个专用引脚接入芯片,如下图所示:

LSE低速外部时钟源引脚-图

这种晶振通常被称为“表晶”或“时钟晶振”,常见于电子手表、RTC 芯片等精密计时设备。

从精度角度来看:LSE 的稳定性远高于 LSI。

它受温度和电压变化的影响较小,适合用于长时间、连续运行的时间计量。

因此在实际产品中:RTC 通常优先选择 LSE 作为时钟源。

在 STM32F103 中,LSE 的主要用途就是:为 RTC 提供稳定、精准的低速时钟。

它不参与系统主频生成,不参与 PLL,也不直接供给 CPU 或高速外设。

在时钟树中,LSE的功能部分如下图所示:

LSE提供RTC时钟源-图

可以看到,LSE外部低速时钟源,最核心、最常见的用途就是作为RTC实时时钟的时钟信号源。

总结

从系统角色分工来看:

  1. HSI 负责上电启动与基础运行,
  2. HSE 负责系统的高速与高精度运行,
  3. LSI 负责低速、独立、安全相关模块,
  4. LSE 负责高精度、长期稳定的时间计量。

四种时钟源并不是相互替代关系,而是各司其职、分工明确:

  1. HSI 解决的是“系统能否可靠启动”的问题;
  2. HSE 解决的是“系统是否运行得快且准”的问题;
  3. LSI 保障的是“在主时钟异常时,关键模块仍能独立工作”;
  4. 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 的地位非常重要,它是整个芯片内部时钟体系的中心节点:

  1. CPU 的运行频率直接由 SYSCLK AHB 总线时钟(简称为HCLK)决定。
  2. AHB 总线时钟(简称为HCLK)由 SYSCLK 分频得到。、
  3. APB1、APB2 总线时钟(PCLK1、PCLK2)也都是在 SYSCLK 基础上继续分频派生。
  4. ...

进一步来看:

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(高速外设总线)

  1. 最大 72 MHz
  2. 典型外设:
    1. GPIO
    2. USART1
    3. SPI1
    4. TIM1
    5. ADC

APB1(低速外设总线)

  1. 最大 36 MHz
  2. 典型外设:
    1. USART2/3
    2. I2C
    3. SPI2
    4. TIM2~7
    5. 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 位

可选的输出时钟源包括:

  1. PLLCLK / 2:PLL 倍频后的时钟,再进行 2 分频
  2. HSI:高速内部时钟
  3. HSE:高速外部晶振时钟
  4. SYSCLK:当前系统主时钟

也就是说:

MCO 不是固定输出某个时钟,

而是可以通过软件选择输出哪一路时钟。

如下图所示:

时钟输出功能-图

本质理解

MCO 的作用是:

将芯片内部的某一路时钟,通过引脚“导出”到外部。

它本质上是一个时钟多路选择器 + 输出驱动电路。

可以理解为:

系统内部的时钟信号,不仅可以用于片上外设,也可以作为“公共时钟源”提供给外部系统。

MCO 是 STM32 提供的时钟输出功能,通过 PA8 引脚将内部选定的时钟信号输出到芯片外部。

posted @ 2026-05-05 20:09  星夜夏空  阅读(121)  评论(0)    收藏  举报
公众号二维码
微信公众号