第七课时:时钟系统基础知识
本课主题:时钟系统基础知识,包括 STM32 内部结构、总线架构与时钟树。
一、单片机的内部结构
要理解 STM32 的内部结构,可以拿电脑来类比。

左半边是一台电脑的放大图,CPU 通过主板连着显卡、内存,再往下是 PCIe 插槽接的转接板,分成 USB 3.0 Hub 和 USB 2.0 Hub,各种外设挂在 Hub 上。右半边是 STM32 的总线架构,思路和电脑是一样的:Cortex-M3 内核用 I-Bus、D-Bus 经过总线矩阵连到 Flash 和 RAM,往下是 AHB 总线,再分成 APB2 和 APB1 两条外设总线。

单片机的 APB2 总线相当于 USB 3.0 的 Hub,APB1 总线相当于 USB 2.0 的 Hub,挂在上面就相当于各种外设。图里标出了三条总线的最大速度:AHB 总线最高 72MHz,APB1 总线最高 36MHz,APB2 总线最高 72MHz。这三条总线的名字、位置和最大速度要牢牢记住。
二、STM32 入门补课
要说清楚时钟,得先补一点数字电路的基础。先记住一句话:数字电路分两种,STM32 本质上就是一大片时序逻辑电路,靠时钟脉冲 CP 驱动,内部各个外设模块都需要时钟才能干活。
在提前学习 HAL 库的这条路上,以前的知识还不足以完全理解时钟这部分,所以这里必须补一课。
2.1 先看懂第一张图:组合逻辑和时序逻辑

左边是组合逻辑电路,元件只有与门、非门,没有记忆元件。它的特点是输出只由当前输入决定,输入一变输出立刻变,记不住过去的状态。编码器、译码器就是这一类,给 A、B、C 马上算出 Y,撤掉信号它什么也不保存。
右边是时序逻辑电路,元件里有 JK 触发器这种记忆元件,还有一个时钟输入 CP,也就是 Clock Pulse,时钟脉冲。重点是,它必须有时钟信号才能工作。它的输出不光看现在的输入,还记住上一刻的状态,触发器本身就是 1bit 的存储器,记住一个 0 或一个 1。

这张图把区别标得更清楚:组合逻辑电路不含记忆元件,时序逻辑电路含有记忆元件,并且标出了"有时钟信号才能工作"。
触发器是时序电路最小的记忆单元,CPU 和单片机里的寄存器全靠触发器堆出来。打个比方,组合逻辑像计算器,输数字立刻出结果,断电啥都忘;时序逻辑像带保存功能的计算器,能记住上次算到哪,按一下时钟才更新一次状态。
2.2 STM32F103 内部总线架构

这是 STM32F103,也就是我们用的 C8T6 所在系列,它的内部框图可以这样理出主干:
text
Cortex-M3内核(CPU)
├─I-Bus 指令总线 → Flash(存代码)
└─D-Bus 数据总线 → RAM(临时变量)
↓ 总线矩阵 → AHB总线(高速总线,最高72M)
↓ AHB分出两条外设总线:
1. APB2(最高72MHz):GPIOA/GPIOB/GPIOC、TIM1、USART1、SPI1、ADC
2. APB1(最高36MHz):TIM2/3/4、USART2/3、I2C、CAN
简单理解三点。第一,I 总线负责拿指令,也就是从 Flash 读程序,D 总线负责读写数据,也就是操作 RAM 变量。第二,AHB 是高速主干道,APB1、APB2 是分支小路,外设都挂在 APB 上。第三,我们操作 GPIO、串口、定时器,本质上就是 CPU 通过总线去读写外设寄存器。
这里有个小白必须记住的关键点:外设不接时钟,就算连在总线上,也不会工作。这就引出了时钟树。
2.3 第四张图:时钟树
时钟树是 STM32 最核心、也是新手最懵的部分。

可以把图里的树叶看成外设模块,树干看成时钟信号。时钟就是给时序电路的 CP 脉冲,没有时钟,外设直接休眠。
四个时钟源,也就是整个时钟树的根部,是时钟的来源。
- HSI:内部高速 RC 时钟,8MHz,芯片内置,不用外部晶振,精度差,启动快。
- HSE:外部高速晶振,4 到 16MHz,我们一般用外部 8M 晶振,精度高,常用。
- LSI:内部低速 RC,40kHz,给独立看门狗 IWDG 用。
- LSE:外部低速晶振,32.768kHz,给 RTC 实时时钟,也就是万年历。

这张图从另一个角度把四个时钟源分成了两组。大树的、高速的是 HSI 和 HSE,小树的、低速的是 LSI 和 LSE。再看名字的规律:HS 是 High Speed 高速,LS 是 Low Speed 低速,I 是 Internal 内部,E 是 External 外部,拼起来就记住了。右边是芯片引脚图,低速外部晶振 LSE 用的是 PC14、PC15,也就是 RCC_OSC32_IN、RCC_OSC32_OUT;高速外部晶振 HSE 用的是 PD0、PD1,也就是 RCC_OSC_IN、RCC_OSC_OUT。所以用了这几个时钟源,对应的引脚就被占用了。
接着是 PLL 锁相环,它是核心倍频器。HSE 或 HSI 输入 PLL,倍频之后得到 SYSCLK 系统时钟,最大 72MHz,也就是 CPU 内核跑的主频。经典配置是 HSE 等于 8M,经过 PLL 乘以 9,得到 SYSCLK 等于 72MHz。
最后是逐级分频,树干逐级降速分给外设。SYSCLK 72M 先经 AHB 分频得到 HCLK,也就是 AHB 总线时钟,一般不分频,HCLK 等于 72M;HCLK 再分成两路,APB2 分频得到 PCLK2,最大 72M,给 APB2 上的 GPIO、TIM1、USART1;APB1 分频得到 PCLK1,最大 36M,给 APB1 上的 TIM2 到 4、串口 2 和 3。
这里要注意一点,STM32F1 的 APB 分频不等于 1 时,定时器的时钟会自动乘以 2,这个后面讲定时器会遇到。
一句话总结时钟树:从晶振拿到基础频率,PLL 倍频到 72M 主时钟,分频之后分给内核和各个外设,哪个外设要使用,就打开它对应的时钟开关。
这就是为什么 CubeMX 或者标准库代码第一步要写开时钟的语句:使能外设时钟,相当于给外设供电、给它 CP 脉冲,时序电路才能跑起来。
2.4 串联起来理解
- 触发器是时序电路的最小单元,很多触发器堆成寄存器,一堆寄存器加上总线、外设,就变成了 STM32 单片机。
- STM32 所有外设,GPIO、定时器、串口,全都是时序逻辑电路,必须给时钟 CP 才能运行。
- 时钟树就是产生各种 CP 脉冲,分给 CPU 和每一个外设。
- 写代码第一步开启 RCC 时钟,本质就是给对应外设的时序逻辑电路提供 CP 时钟脉冲,唤醒这个模块。
三、时钟树的细节
前面把时钟树整体过了一遍,这里再抠一下细节。

先看树干这一部分。

再看这几个时钟源,结合上面的讲解会有更具体的印象,所以实际上芯片的这几个接口是被占用的。

举例说,如果就是想在 SYSCLK 上得到 8MHz 的时钟信号,有两条路:想要低成本,就让 SYSCLK 直接等于 HSI,也就是 8MHz;想要高精度,就让 SYSCLK 直接等于 HSE,也是 8MHz。这说明同一个频率可以由不同的时钟源提供,区别在成本和精度。

PLL 可以通过各种方式调节时钟频率。输入的时候可以先做 2 分频,到达 PLL 时还能做 2 到 16 倍的倍频。还有很重要的一点,外部晶振对于内部时钟源来说通常更精准。

分频器的作用就是对输入的时钟信号做除法。AHB 分频器对 SYSCLK 产生的信号做分频,得到 HCLK,最大 72M,再传给 APB1 和 APB2,转化成一个 PCLK1,最大 36M,和一个 PCLK2,最大 72M。
四、动手实践(在 CubeMX 里配置时钟)
在 CubeMX 里配置好之后,切到第二个选项界面,也就是 Clock Configuration,能看到一棵完整的时钟树。

默认情况下,系统时钟来自内部的 HSI,SYSCLK 是 8MHz。
4.1 时钟树的树根、树干、树枝树叶
先看树根,也就是时钟源。

图中把 HSI、HSE、LSI、LSE 四个时钟源圈了出来,右侧对应的就是它们的输入频率设置。
再看树干,也就是 PLL 和 HSE、HSI 是怎么连到 SYSCLK 的。



PLL 在这几级之间起到倍频的作用,HSE 或 HSI 经过它之后得到 SYSCLK。
然后是树枝和树叶。

中间单个连通的就是 AHB 分频器,它产生的时钟信号叫 HCLK。随后就是 APB1、APB2 产生的 PCLK1、PCLK2。
4.2 一些特殊模块

USB 模块有它自己的那条分频路径,就是图里的 USB Prescaler。

除了外设总线,还有 Flash 接口、Cortex-M3 内核内存、DMA、Flash 定时器、ADC 这些模块,各自有对应的时钟。

其中 AHB 直接连着 Cortex-M3 内核,也就是单片机的 CPU,所有代码都在这里执行,所以这里的频率就代表了代码的执行速度。


SYSCLK 实际上就是系统时钟,默认使用 HSI 作为提供源头,它是芯片内部的高速 RC 振荡器,由 HSI 直接影响到 Cortex-M3。
8MHz 到底意味着什么,可以这样理解。

用一段测试代码来量一量:
c
while (1)
{
uint32_t i;
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET); // 点亮板载LED
for (i = 0; i < 1000000; i++); // 执行100万次for循环,耗时1秒左右
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET); // 熄灭板载LED
for (i = 0; i < 1000000; i++);
}
思路大概是用 for 循环跑 100 万次来估时间,8MHz 就是每秒 800 万次。
4.3 发挥全部性能:配置 RCC
想让芯片跑满性能,要用到 RCC 选项卡。

RCC 是 Reset & Clock Controller,也就是复位和时钟控制器。

在 RCC 的模式配置里,高速外部时钟 HSE 和低速外部时钟 LSE 各有几种模式。BYPASS Clock Source 是旁路时钟源,直接用外部已经生成好的时钟信号;Crystal/Ceramic Resonator 是晶体、陶瓷振荡器,通过外接电路产生时钟信号。

最小系统板外接的是晶振,HSE 这里选 Crystal/Ceramic Resonator。选好之后,CubeMX 会自动分配两个引脚。

然后设置外部输入的频率,也就是晶振的频率,这里填 8MHz。

再选择 HSE 作为锁相环的输入,然后设置锁相环。

最后把每条分频路径设成 1、2、1,也就是 AHB 分频 1、APB1 分频 2、APB2 分频 1,这样就达到了最高频率:HSE 8MHz 经 PLL 乘 9 得到 SYSCLK 72MHz,HCLK 72MHz,PCLK1 36MHz,PCLK2 72MHz。
4.4 时钟源调控的意义
问题:这些时钟源的调控有什么意义呢?
核心一句话:调控时钟源,本质是按需分配节拍,兼顾速度、功耗、硬件上限和可靠性,适配不同的功能。
各自的作用是这样的。HSE 外部高速晶振 8M,精准稳定,作为主基准,送入 PLL 倍频得到 72M 系统主频,电压小幅波动下频率不易飘,适合正常运行。HSI 内部 RC 8M,芯片自带,上电即可启动,作为备用保底时钟,受电压、温度影响大,支持时钟校准修正频率漂移。LSE 外部低速晶振 32.768K,极低功耗,独立运行,给 RTC 万年历,CPU 休眠、主时钟关闭时仍可持续计时,断电还能靠纽扣电池维持时间。LSI 内部 RC 40K,是独立时钟源,供独立看门狗使用,主系统时钟崩溃时依旧运行,超时自动复位芯片,容易受温压影响,可以校准。
PLL 倍频,是把低速稳定晶振的频率放大,提升 CPU 运算速度,F103 最高倍频到 72M。分频器,是因为不同外设硬件有最大频率上限,比如 APB1 最高 36M,分频用来限速,避免外设出错;不用的外设还可以单独关掉时钟,降低功耗。
调控时钟有四个目的。一是适配硬件,满足不同外设的速度上限,防止超频异常。二是省电,闲置外设关闭时钟,低需求场景降低主频。三是可靠兜底,多时钟源相互独立,主时钟故障时可以切换备用时钟,也就是 CSS 时钟安全系统。四是精度选择,高精度任务用外部晶体,应急时用内部 RC。
再补充电压波动和时钟校准这两点。外部晶体 HSE、LSE 在小幅电压波动下频率稳定,一般不需要软件校准。内部 RC 的 HSI、LSI 则受电压、温度变化影响会产生频率漂移,时钟校准就是把偏移的频率修正回来。CSS 时钟安全系统则是,当 HSE 停振时自动切到 HSI,防止芯片直接卡死。
最后区分一组容易混的东西。TIM 定时器依赖主时钟,CPU 一休眠就停,适合毫秒级的短定时。RTC 用独立的 LSE 时钟,适合长时间计时,比如时分秒和日期。
一句话总结:多时钟源加上倍频、分频,就是为了高速运算、低功耗、时间记录和故障备份;晶体抗小幅电压抖动,内部 RC 靠校准补偿温压带来的频率偏差。
复习速记
- 四个时钟源:HSI 是内部 8M RC,HSE 是外部 8M 晶振且最常用,LSI 是 40k 用来喂看门狗,LSE 是 32.768k 给 RTC。
- PLL 倍频:HSE 8M 乘 9 得到 SYSCLK 等于 72MHz,这是 F103 的最高频率。
- 分频链:SYSCLK 经 AHB 得到 HCLK 72M,再经 APB2 得到 PCLK2 72M,给 GPIO、USART1、TIM1;经 APB1 得到 PCLK1 36M,给 TIM2 到 4、USART2 和 3、I2C。
- APB 分频不等于 1 时,定时器时钟会自动乘以 2,讲定时器时会用到。
- 外设不开时钟就不工作,写代码第一步就是开时钟,CubeMX 生成的 MX_xxx_Init() 里已经自动开了。
- 外接晶振比内部 RC 精准;想跑满速,在 RCC 里选 HSE 作 PLL 输入,分频设成 1、2、1。