
Ciallo(∠・ω< )⌒☆
| 系列专栏 | 直达链接 |
|---|---|
| 🔤 C 语言 | 进入专栏 → |
| 🧱 数据结构 | 进入专栏 → |
| 🔧 C++ | 进入专栏 → |
| 🐍 Python | 进入专栏 → |
| 🔌 STM32 | 进入专栏 → |
🏠 博客主页:暖焰核心
文章目录
- 引言
-
- [一、 节拍器](#一、 节拍器)
- [二、 控制成本](#二、 控制成本)
-
- [2.1 一笔成本账](#2.1 一笔成本账)
- [2.2 与门](#2.2 与门)
- [2.3 未使能时的读数](#2.3 未使能时的读数)
- [三、 时钟树](#三、 时钟树)
-
- [3.1 全图与三个部分](#3.1 全图与三个部分)
- [3.2 树根、树干与树叶](#3.2 树根、树干与树叶)
- [四、 时钟源](#四、 时钟源)
-
- [4.1 四个原始时钟源](#4.1 四个原始时钟源)
- [4.2 时钟的默认](#4.2 时钟的默认)
- [4.3 倍频器 PLL](#4.3 倍频器 PLL)
- [4.4 32.768 kHz 的由来](#4.4 32.768 kHz 的由来)
- [五、 倍频与分频](#五、 倍频与分频)
-
- [5.1 共享源头](#5.1 共享源头)
- [5.2 72 MHz 的来路](#5.2 72 MHz 的来路)
- [5.3 三个特殊分频](#5.3 三个特殊分频)
- [5.4 MCO 时钟输出](#5.4 MCO 时钟输出)
- [六、 外设使能](#六、 外设使能)
-
- [6.1 一排时钟开关](#6.1 一排时钟开关)
- [6.2 APB1 与 APB2 的外设归属](#6.2 APB1 与 APB2 的外设归属)
- [6.3 RCC 的位置与寄存器](#6.3 RCC 的位置与寄存器)
- [七、 HSE 的保命机制 CSS](#七、 HSE 的保命机制 CSS)
- [八、 RTC 与看门狗的低速时钟](#八、 RTC 与看门狗的低速时钟)
-
- [8.1 两个慢节奏计数器](#8.1 两个慢节奏计数器)
- [8.2 一秒的由来](#8.2 一秒的由来)
- [8.3 备份域与写保护](#8.3 备份域与写保护)
- [九、 上电那一刻](#九、 上电那一刻)
引言
前几篇把灯点亮了、把按键读回来了,有一个问题:芯片里的 CPU 和那些外设,到底是被什么推着跑的?为什么同样是这块板子,时钟配好了能跑到 72 MHz,配不好就只能用默认的低频率?
答案是时钟。STM32F103 标称的 72 MHz 不是天上掉下来的,它是从一颗 8 MHz 的晶振出发,经过倍频、分频,一路分发到每个外设手里的。这棵分发网络在手册里画成一棵树,所以叫时钟树,而管着这棵树的外设叫 RCC(Reset and Clock Control,复位和时钟控制)。
一、 节拍器
CPU 看起来什么都能干,但它自己不会主动干活。取指令、分析指令、执行指令,每一步都要有人喊拍子,喊拍子的就是时钟。
时钟信号的本质是个方波:电压按固定周期在高电平和低电平之间来回跳。部件们在脉冲到来的瞬间动一下,其余时间原地待命。方波越密,一秒内动的次数越多,跑得越快;方波越疏,节奏越慢。
把 CPU 换成串口、I2C(Inter-Integrated Circuit,两线制的板级通信总线)也一样:串口收到一个脉冲发一个字节,I2C 收到一个脉冲传一次数据。整颗芯片都在等同一样东西,就是脉冲。所以「主频 72 MHz」翻译过来就是:一秒里有 7200 万个脉冲在催它干活。
麻烦在于,片上每个部件要的节奏还不一样。CPU 要最快的;看门狗一秒数一次就够;RTC 更慢,它计的是秒。怎么用尽量少的电路,喂出这么多不同频率的脉冲?时钟树就是这道题的答案。
二、 控制成本
2.1 一笔成本账
一颗 STM32F103ZET6 里挂着几十个片上外设,GPIO(General Purpose Input/Output,通用输入输出)、定时器、串口、I2C、SPI(Serial Peripheral Interface,串行外设接口)都在其列,但一块具体的板子往往只用得上其中一小部分。要是所有外设永远接着时钟,没人用的也在被脉冲一遍遍空催,电就白烧了。功耗高,供电和散热的水准就得跟着抬,产品成本上去了,市场竞争力就下来了。
2.2 与门
设计者的解法是让时钟进外设之前先过一道闸。电路上这道闸就是一个与门:时钟一路、使能信号一路,两路都有效,脉冲才放行;使能一断,外设这边彻底安静。
text
+-------+
时钟源 -----+ AND +----- 外设的时钟输入
+---^---+
|
使能位 ---------+
所谓「使能外设时钟」,本质就是把这颗与门的闸抬起来。用哪个外设就开哪个的闸,不用的全部关着,功耗和自由度两头都占了。
2.3 未使能时的读数
注意:当外设时钟没有启用时,软件读它的寄存器,返回的数值始终是 0x0。
忘了开时钟就去操作外设,读回来的全是 0,写进去的也不生效。外设看起来「坏了」「失联了」,其实只是闸没开。很多「怎么写都没反应」的怪问题,原因就是这个。
三、 时钟树
3.1 全图与三个部分
时钟要有源,要能变出不同频率,还要能逐个开关。STM32 把这整套东西画成一张图,就是时钟树。

整张图看着密密麻麻,按频率高低其实能切成三块:右上一大块是高频区,驱动 CPU、内存和绝大多数片上外设,是日常开发真正打交道的主体;左下一块是低频区,喂 RTC 和独立看门狗这两个慢节奏设备;剩下一个小角是时钟输出,把内部时钟引出芯片给别人用。
3.2 树根、树干与树叶
这棵树有根有干有叶。

树根是时钟的发生源,内外各一套;树干负责倍频和选择,决定系统时钟跑多快;树枝是一级级分频器,把主干频率摊到各条总线;树叶就是一个个具体外设,每片叶子上还挂着自己的开关。后面三节就顺着树的结构走:先选树根,再理树干,最后开树叶。
四、 时钟源
4.1 四个原始时钟源
STM32F103 提供四个「原始时钟来源」,两内两外:
| 简称 | 全称 | 来源 | 频率 | 特点 |
|---|---|---|---|---|
HSI |
High Speed Internal | 内部 RC 振荡器 | 8 MHz | 上电即用,精度一般 |
HSE |
High Speed External | 外部晶振 | 4~16 MHz,板载 8 MHz | 精度高,要等起振 |
LSI |
Low Speed Internal | 内部 RC 振荡器 | 40 kHz | 喂独立看门狗 |
LSE |
Low Speed External | 外部晶振 | 32.768 kHz | 精度高,给 RTC 计秒 |
在时钟树全图上,它们就是被标出来的那四块:

RC 振荡器靠电阻电容的充放电产生振荡,成本低、说开就开,但频率会随温度和电压漂;外部晶振是石英的,稳得多,代价是占引脚、要等起振。高速这对恰好一内一外,低速这对也是。正经项目的主时钟用 HSE 图它稳,看门狗和 RTC 用低速那对,够用就好。
4.2 时钟的默认
芯片刚上电、一行代码都没跑的时候,系统时钟就是 HSI。证据写在 RCC_CR 的复位值里:0x0000 0083。低位拆开正好是 HSION(使能)和 HSIRDY(就绪)两位都为 1,也就是硬件设计成上电就把内部 8 MHz 振荡器开起来、等它稳定。
HSI 是内部 RC,不依赖任何外部电路,晶振焊没焊、焊得好不好都不影响它,所以芯片永远能靠它先转起来。后来把时钟切到更高频率是软件的事,但起步那一刻,是 HSI 在推着 CPU 跑。
它还能校准:RCC_CR 里有校准位,出厂值自动加载,默认能校到 8 MHz ±1% 左右;校准值每加一档,频率大约变 40 kHz。但再校也是 RC,跟石英晶振的稳定度没得比,这也是正经项目要把主时钟切到 HSE 的原因。
4.3 倍频器 PLL
严格数的话时钟源是四个,但树上还有个绕不开的角色:PLL(Phase Locked Loop,锁相环)。它自己不产生脉冲,而是把已有时钟「乘」出一个更高的频率,输出叫 PLLCLK,习惯上也算作一路时钟源。
它的输入可以二选一,由 PLLSRC 位决定:选 0 用 HSI 除以 2(4 MHz),选 1 用 HSE,还可以先经 PLLXTPRE 除 2 再进来。倍多少由 PLLMUL 位段决定,2 倍到 16 倍任选。注意:PLL 输出不得超过 72 MHz。
| PLL 输入 | 输入频率 | 顶格输出 |
|---|---|---|
HSI ÷ 2 |
4 MHz | 4 × 16 = 64 MHz |
HSE 直入 |
8 MHz(板载) | 8 × 9 = 72 MHz |
这就解释了一个奇怪的现象:为什么用 HSI 当源头,系统最快只能到 64 MHz?4 × 16 就是 64,倍频系数到 16 就封顶了。
4.4 32.768 kHz 的由来
LSE 的频率看着别扭,其实是精心挑的:32768 正好是 2 的 15 次方。二进制分频器做「除以 2」最顺手,一条 15 级的分频链除到底,正好一秒一个脉冲。RTC 要的就是一秒一格的秒针,所以这颗晶振几乎是量身定做,钟表行业用了几十年,便宜又准。
五、 倍频与分频
5.1 共享源头
树根只有一两个,树叶却有几十片,频率需求各不相同,中间全靠倍频和分频变花样。

倍频是把一个周期拆成 n 个,频率乘 n;分频反过来,n 个周期并成一个,频率除以 n。图里同一条 8 MHz 的源,串口那边 ×2 后节奏翻倍,I2C 那边 ÷2 后节奏减半,各取所需。
5.2 72 MHz 的来路
从晶振到各条总线,每一级拆开看:
| 级 | 位段与配置 | 动作 | 输出频率 |
|---|---|---|---|
| 晶振 | 无 | 产生原始脉冲 | HSE 8 MHz |
| PLL | PLLSRC=1、PLLMUL 配 9 倍 |
8 × 9 | PLLCLK 72 MHz |
| 系统时钟 | SW=10 |
选中 PLL | SYSCLK 72 MHz |
| AHB | HPRE 不分频 |
72 ÷ 1 | HCLK 72 MHz |
| APB1 | PPRE1 ÷ 2 |
72 ÷ 2 | PCLK1 36 MHz |
| APB2 | PPRE2 不分频 |
72 ÷ 1 | PCLK2 72 MHz |
这张表就是时钟树高频区的主干道:8 MHz 进门,PLL 乘 9 顶到 72 MHz,再由 AHB 摊给两条外设总线。APB1 有一条硬规定,手册原话是「软件必须保证 APB1 时钟频率不超过 36 MHz」,所以它至少得除 2。
AHB(Advanced High-performance Bus,高性能总线)跑高速成员,APB(Advanced Peripheral Bus,外设总线)专门挂外设,APB1 和 APB2 是它的两个档位。SYSCLK 是系统时钟,全芯片的根;HCLK 是 AHB 总线时钟,CPU、内存、DMA(Direct Memory Access,直接内存访问)挂在这条上;PCLK1、PCLK2 分别是 APB1、APB2 两条外设总线的时钟。CPU 内核还有个自由运行的 FCLK,一般与 HCLK 同频,不用特别操心。另外 Cortex 内核里的系统节拍定时器 SysTick,还可以选 HCLK 除以 8 当外部时钟,做精确延时的时候用得上。
5.3 三个特殊分频
定时器时钟会偷偷乘 2。 手册有条规则:APB 分频系数为 1 时,定时器时钟等于总线频率;分频系数不是 1 时,定时器时钟等于总线频率的 2 倍。上一节的配置里 APB1 除 2 得 36 MHz,挂在它下面的 TIM2 到 TIM7 拿到的是 36 × 2 = 72 MHz;APB2 没分频,TIM1 和 TIM8 直接拿 72 MHz。也就是说不管挂在哪条总线,定时器最后拿到的都是 72 MHz,硬件替你把频率补齐了。不知道这条的话,算定时周期一定会算错。
| 总线 | 本篇分频 | 总线频率 | 定时器实际时钟 |
|---|---|---|---|
| APB1 | ÷ 2 | 36 MHz | 36 × 2 = 72 MHz |
| APB2 | ÷ 1 | 72 MHz | 72 × 1 = 72 MHz |
USB 的 48 MHz 是除 1.5 除出来的。 USB(Universal Serial Bus,通用串行总线)全速设备要 48 MHz,可主干线上没有这个数(72 ÷ 2 是 36,72 ÷ 1 是 72)。硬件给 USB 单独留了个预分频器 USBPRE:72 ÷ 1.5 = 48,正好。手册还特别提醒,这个位要在使能 USB 时钟之前配好。
ADC 的时钟上限是 14 MHz。 ADC(Analog-to-Digital Converter,模数转换器)挂在 APB2 上,但有专门的预分频器 ADCPRE,从 PCLK2 里除 2、4、6、8 取一路。72 ÷ 2 = 36、72 ÷ 4 = 18,都超了 14 MHz 的上限,主频跑满时只能选 ÷ 6(12 MHz)或 ÷ 8(9 MHz)。分频档位摆在那,不代表每一档都能用。
5.4 MCO 时钟输出
时钟树还有个对外的小窗口:MCO(Microcontroller Clock Output,微控制器时钟输出),把内部选中的时钟直接送到一个 GPIO 引脚上,给片外设备当节奏,或者接示波器量一下,验证配置到底对没对。可选的源有 SYSCLK、HSI、HSE 和 PLL 二分频四种,靠 MCO[2:0] 三个位选。要留意的只有引脚的物理极限:输出不得超过 50 MHz,这是 I/O 口的速度上限,不是时钟树的。
六、 外设使能
6.1 一排时钟开关
前面说每个外设的时钟都过一道与门,那这些与门的使能端接在哪?答案是几个专门的寄存器。它们就是一排开关的集合:每一位管一个外设的时钟,写 1 闭合、写 0 断开。

看 RCC_APB1ENR 的位分布,每一位都写着一个外设的名字:TIM2EN、TIM3EN、SPI2EN、I2C1EN......想让谁收到时钟脉冲,就把对应位写成 1。前面点灯代码里的 __HAL_RCC_GPIOx_CLK_ENABLE,本质上就是在往这类寄存器的某一位写 1。
6.2 APB1 与 APB2 的外设归属
哪些外设挂 APB1、哪些挂 APB2,从两个使能寄存器的位分布就能读全:
| 总线 | 挂载的外设 |
|---|---|
| APB2(最高 72 MHz) | GPIOA 到 GPIOG、AFIO、USART1、SPI1、TIM1、TIM8、ADC1/ADC2/ADC3 |
| APB1(最高 36 MHz) | TIM2 到 TIM7、USART2/USART3、UART4/UART5、I2C1/I2C2、SPI2/SPI3、USB、CAN、DAC、PWR、BKP、WWDG |
跟速度相关的都往 APB2 挤,GPIO、高速串口、高速定时器、ADC 都在;慢速通信和电源管理类的外设留在 APB1。以后拿到一个新外设,先查它挂在哪条总线,时钟使能位就在对应的寄存器里。
表里几个眼生的:AFIO 是复用功能 IO,管引脚的第二职业;CAN 是车载总线;DAC 是数模转换器;WWDG 是窗口看门狗,与独立看门狗相对;PWR 和 BKP 分别是电源控制和备份接口,第八节备份域还会见到它们。
在 ZET6 这类大容量型号上,APB1 的定时器是 TIM2 到 TIM7 一共六个,不是只有 TIM2 到 TIM4。手册的位图里 TIM5EN、TIM6EN、TIM7EN 都在,别按只有三个来配。
6.3 RCC 的位置与寄存器
RCC 就是这整棵树的物业管理处:它自己挂在 AHB 总线上,手里握着全树所有选择器、分频器和与门的开关。

它名下的寄存器一共八个,各管一摊:
| 寄存器 | 管什么 |
|---|---|
RCC_CR |
四个时钟源的开关与就绪标志、PLL 开关、CSS 开关 |
RCC_CFGR |
分频倍频系数、系统时钟切换、MCO、ADC 与 USB 预分频 |
RCC_CIR |
时钟相关中断的使能与标志 |
RCC_AHBENR |
AHB 外设时钟使能(DMA、FSMC、CRC 这些) |
RCC_APB2ENR |
APB2 外设时钟使能 |
RCC_APB1ENR |
APB1 外设时钟使能 |
RCC_BDCR |
备份域:LSE 与 RTC 的开关、备份域复位 |
RCC_CSR |
复位原因记录、LSI 开关 |
RCC_AHBENR 的复位值是 0x0000 0014,不是 0。拆开正好是 SRAMEN(SRAM 接口)和 FLITFEN(闪存接口)两位默认为 1;反过来,DMA、CRC(循环冗余校验)、FSMC(外部存储器控制器)这些的时钟默认全是关的。
七、 HSE 的保命机制 CSS
树根有两棵,只挑一棵用就有个隐患:万一它停了呢?高温、线路老化、晶振虚焊,任何一样都能让 HSE 突然没了输出。而 HSE 一停,PLL 跟着断,CPU 和全部外设瞬间停摆,设备就死在那了。
CSS(Clock Security System,时钟安全系统)就是为这一刻准备的。它平时盯着 HSE,一旦检测到失效,硬件立刻做三件事:关掉 HSE 和 PLL、把系统时钟强制切回 HSI 的 8 MHz、产生一个 NMI(Non-Maskable Interrupt,不可屏蔽中断)通知软件来收拾残局。整个过程不需要软件参与,等软件收到中断时,芯片已经在 8 MHz 上活着了。
NMI 是一类不能被屏蔽的中断。普通中断可以因为优先级或关中断被暂时拦住,它不行,所以系统级的急事交给它正合适。
注意这个保护是单向的:只有 HSE 挂了会自动切 HSI,反过来 HSI 挂了没有切 HSE 的机制,规格里根本不存在「HSI 失效检测」这回事。工业设备里这套机制很常见:主时钟出事,系统至少能以低频率活着,把故障上报出去或者安全停机,而不是直接失控。
八、 RTC 与看门狗的低速时钟
8.1 两个慢节奏计数器
时钟树的低频区专门伺候两个慢家伙:RTC(Real-Time Clock,实时时钟)和 IWDG(Independent Watchdog,独立看门狗)。这俩本质都是计数器:RTC 往上加,一秒加一,记的是当前时刻;IWDG 往下减,减到 0 就把整个芯片复位。程序跑飞了不再喂狗,计数器减到底,系统自动重启,这就是看门狗的看家本领。
它们更新一次都是秒级、毫秒级的事,MHz 级的时钟纯属浪费,kHz 就够。
8.2 一秒的由来

RTC 的时钟源三选一:LSE(32.768 kHz)、LSI(40 kHz)或者 HSE 除以 128。首选 LSE,主电源断了它还能靠纽扣电池继续走;看门狗则只能用 LSI,独立运行,不受外部晶振影响,不然晶振一出事,连负责「看门」的都躺了。
32.768 kHz 进了 RTC 还要再分频,默认分频系数是 32768,除完正好一秒一个脉冲,这正是 4.4 节那个数字的选择理由。要是非要选 HSE 当源,就得自己重新算:8 MHz 先除 128 得 62500 Hz,再配一个 62500 的分频,一样凑得出 1 Hz。能凑,但没必要。
8.3 备份域与写保护
RTC 和 LSE 这几个开关住在一个特殊区域:备份域。这块区域由 VBAT 引脚供电,那颗纽扣电池接的正是它:主电源一断,电池顶上,里面的寄存器和时钟配置在整机断电后依然还在。

代价是写保护:RCC_BDCR 里的 LSEON、RTCSEL 这些位在复位后是锁死的,得先把电源控制寄存器里的 DBP 位(解除备份域写保护)置 1 才能改。设计意图也好理解:备份域的价值就在于「别的都动了它也别动」,要是任何一次复位都能随手改它的配置,掉电续时就没意义了。
九、 上电那一刻
芯片上电后的全过程:
text
选时钟源 -------> 配倍频与分频 -------> 使能外设
(HSE/HSI) (PLL与各级分频) (ENR 位段)
刚上电时 RCC_CR 的复位值里 HSION 已置 1,HSI 的 8 MHz 先跑起来,CPU 靠它取指执行;想跑满 72 MHz,就按第一步选 HSE 当源,第二步把 PLL 配成 9 倍、各级分频配好,切过去;之后每用到一个新外设,第三步把 RCC_APB2ENR 或 RCC_APB1ENR 里对应的那位写成 1,闸一开,脉冲就到了。
这套配置过程在 CubeMX(ST 的图形化配置工具)里被画成了可视化的时钟树:每个选择器、每级分频都是个下拉框,改一个数,全树的频率跟着重算。

对照着前面那棵树看这张截图,其实还是那三步:左边选树根,中间调树干,右边开树叶。软件只是把手册里的位段翻译成了下拉框。
芯片跑多快,不是晶振单方面说了算,也不是代码说了算,是时钟树上每一个选择器和分频器的配置共同决定的。8 MHz 进树根,9 倍频上主干,一排开关分发到树叶,RCC 管的就是这一切。