STM32时钟树怎么看?一步理解SYSCLK、HCLK、PCLK和外设时钟配置

STM32时钟树怎么看?一步理解SYSCLK、HCLK、PCLK和外设时钟配置

前言

刚开始学习 STM32 时,很多人看到 CubeMX 里的 Clock Configuration 页面都会有一种感觉:

怎么这么多线?

HSI、HSE、PLL、SYSCLK、HCLK、PCLK1、PCLK2到底是什么?

为什么APB1是36MHz,定时器却可能是72MHz?

UART波特率为什么配置没问题却通信乱码?

ADC、USB、RTC为什么又有自己的时钟?

实际上,STM32 的时钟树虽然看起来复杂,但核心逻辑非常简单。

只需要抓住一条主线:

text 复制代码
时钟源
  ↓
PLL倍频 / 预分频
  ↓
SYSCLK
  ↓
AHB分频
  ↓
HCLK
  ↓
APB1 / APB2分频
  ↓
PCLK1 / PCLK2
  ↓
各个外设最终时钟

如果能够顺着这条路径从左向右看,STM32 的时钟树就不再复杂。

本文将从最基础的时钟源开始,详细讲解:

  • HSI、HSE、LSI、LSE分别是什么;
  • PLL到底有什么作用;
  • SYSCLK、HCLK、PCLK有什么区别;
  • APB1和APB2分别负责哪些外设;
  • 为什么定时器时钟可能是PCLK的2倍;
  • UART、SPI、ADC、定时器到底拿到了多少MHz;
  • CubeMX时钟树应该按照什么顺序看;
  • 时钟配置错误会出现哪些现象;
  • 如何通过一个STM32F103实例完整计算时钟。

一、STM32为什么需要"时钟"

MCU内部的数字逻辑本质上需要一个节拍不断驱动。

可以把时钟理解成整个芯片工作的"节拍器"。

例如CPU执行:

text 复制代码
取指令
↓
译码
↓
执行
↓
访问存储器

都需要时钟驱动。

不仅CPU需要时钟,几乎所有外设也需要:

text 复制代码
CPU
GPIO
UART
SPI
I2C
ADC
定时器
USB
RTC
DMA

只不过不同模块对时钟的需求不同。

例如:

text 复制代码
CPU:希望运行得快
UART:需要准确产生波特率
ADC:时钟不能超过允许范围
RTC:希望功耗低,而且走时准确
USB:通常需要特定精度的时钟
定时器:需要确定的计数频率

因此STM32不会简单地让所有模块全部运行在同一个频率。

而是构造了一套:

text 复制代码
时钟源
+
倍频
+
分频
+
时钟选择器

最终形成一棵"时钟树"。


二、什么是时钟树

所谓时钟树,就是描述:

MCU内部各种时钟从哪里来、经过什么倍频和分频、最终送给哪些模块。

可以简单理解成:

text 复制代码
                  HSI
                   │
                  HSE
                   │
                   ▼
                  PLL
                   │
                   ▼
                SYSCLK
                   │
              AHB Prescaler
                   │
                   ▼
                  HCLK
               ┌───┴───┐
               │       │
             APB1     APB2
               │       │
             PCLK1    PCLK2
               │       │
            各类外设   各类外设

所以看到CubeMX复杂的时钟树时,不需要一次把所有线都看懂。

首先只追踪主干:

text 复制代码
时钟源 → PLL → SYSCLK → HCLK → PCLK → 外设

三、STM32常见的四种时钟源

常见STM32中经常可以看到:

text 复制代码
HSI
HSE
LSI
LSE

它们可以先按照两个维度分类:

text 复制代码
高速 / 低速
内部 / 外部

于是得到:

时钟 含义 类型 特点
HSI High Speed Internal 内部高速 启动快、无需晶振
HSE High Speed External 外部高速 精度高、适合主系统
LSI Low Speed Internal 内部低速 成本低、精度一般
LSE Low Speed External 外部低速 常为32.768kHz,适合RTC

不同STM32系列还可能存在其他时钟源,例如:

text 复制代码
MSI
CSI
HSI48

具体要看芯片数据手册。

但理解 HSI/HSE/LSI/LSE 后,基本思想已经掌握。


四、HSI是什么

HSI:

text 复制代码
High Speed Internal

中文通常叫:

text 复制代码
内部高速时钟

它由STM32芯片内部的RC振荡器产生。

特点:

text 复制代码
不需要外部晶振
启动速度快
成本低
PCB简单
精度通常不如外部晶振

很多STM32在刚刚复位时,会首先使用内部时钟启动。

可以简单理解为:

HSI是STM32自带的"内部节拍器"。

即使开发板没有外部晶振,芯片通常仍然能够运行。


五、HSE是什么

HSE:

text 复制代码
High Speed External

中文通常叫:

text 复制代码
外部高速时钟

通常来自:

  • 外部晶振;
  • 外部有源时钟;
  • 其他芯片提供的时钟。

例如经典STM32F103开发板常见:

text 复制代码
8MHz外部晶振

通过PLL倍频后可以得到:

text 复制代码
72MHz系统时钟

HSE通常具有:

text 复制代码
精度较高
稳定性较好
适合要求较高的通信
适合作为PLL输入

因此很多正式工程会优先使用:

text 复制代码
HSE → PLL → SYSCLK

作为系统主时钟。


六、LSI是什么

LSI:

text 复制代码
Low Speed Internal

即内部低速RC振荡器。

特点:

text 复制代码
功耗较低
不需要外部晶振
精度通常不高

典型应用包括:

text 复制代码
独立看门狗IWDG
某些RTC场景
低功耗模块

例如独立看门狗往往使用独立低速时钟,即使CPU主时钟发生问题,IWDG仍然能够工作。

这也是为什么看门狗通常需要相对独立的时钟来源。


七、LSE是什么

LSE:

text 复制代码
Low Speed External

通常使用:

text 复制代码
32.768kHz外部晶振

为什么经常是32.768kHz?

因为:

text 复制代码
32768 = 2^15

经过15次二分频就可以得到:

text 复制代码
1Hz

非常适合RTC产生1秒时间基准。

所以LSE最典型的应用就是:

text 复制代码
RTC实时时钟

相比LSI,LSE通常:

text 复制代码
走时精度更高
长期稳定性更好
适合真正的时钟日历功能

八、HSI和HSE应该怎么选择

可以简单记忆:

追求方便和启动速度

可以使用:

text 复制代码
HSI

适合:

text 复制代码
简单控制
开发调试
对频率精度要求不高的系统

追求精度

可以使用:

text 复制代码
HSE

适合:

text 复制代码
精确UART通信
USB相关时钟
CAN通信
高精度定时
正式产品

但需要注意:

并不是所有使用UART的系统都必须使用HSE。

现代STM32内部RC的精度已经可以满足不少场景,具体仍需根据:

text 复制代码
允许波特率误差
温度范围
工作电压
芯片内部RC精度

进行判断。


九、PLL到底是什么

PLL:

text 复制代码
Phase-Locked Loop

中文叫:

text 复制代码
锁相环

对初学者来说,可以暂时不用研究它内部的模拟电路原理。

只需要理解:

PLL最重要的作用之一,就是把一个已有时钟转换成我们需要的更高或特定频率。

例如:

text 复制代码
HSE = 8MHz

如果系统希望运行:

text 复制代码
72MHz

可以配置:

text 复制代码
8MHz × 9 = 72MHz

于是:

text 复制代码
HSE 8MHz
   ↓
PLL ×9
   ↓
72MHz
   ↓
SYSCLK

这是经典STM32F103中非常典型的配置。


十、为什么不直接使用72MHz晶振

有人可能会问:

既然CPU要72MHz,为什么不直接接72MHz晶振?

原因很多,例如:

text 复制代码
高频晶振成本更高
PCB设计更加困难
EMI问题更明显
芯片引脚对外部时钟有频率限制
PLL可以灵活产生多个频率

所以常见设计方式是:

text 复制代码
较低频率的稳定晶振
        ↓
PLL
        ↓
较高系统主频

例如:

text 复制代码
8MHz → PLL → 72MHz
25MHz → PLL → 168MHz
8MHz → PLL → 更高系统频率

具体规则取决于STM32系列。


十一、不同STM32的PLL规则并不一样

这一点非常重要。

STM32F1中的PLL可能比较简单:

text 复制代码
PLL输入 × 倍频系数

而在F4、F7、H7等系列中,经常看到:

text 复制代码
PLLM
PLLN
PLLP
PLLQ
PLLR

例如概念上可以理解为:

text 复制代码
输入时钟
   ↓
÷ PLLM
   ↓
× PLLN
   ↓
PLL VCO
   ├── ÷ PLLP → 系统时钟
   ├── ÷ PLLQ → 某些外设
   └── ÷ PLLR → 其他时钟

因此绝不能把:

text 复制代码
STM32F103的PLL公式

直接套用到:

text 复制代码
STM32F407
STM32F767
STM32H743

实际开发一定要结合:

  • 芯片Reference Manual;
  • Datasheet;
  • CubeMX Clock Configuration。

十二、SYSCLK到底是什么

SYSCLK:

text 复制代码
System Clock

即:

text 复制代码
系统时钟

可以理解为整个STM32时钟树的核心主干时钟。

SYSCLK通常可以由以下某个来源提供:

text 复制代码
HSI
HSE
PLL输出

例如:

text 复制代码
HSE = 8MHz
PLL × 9 = 72MHz

然后选择PLL作为系统时钟:

text 复制代码
SYSCLK = 72MHz

需要注意:

SYSCLK并不一定等于CPU最终运行时钟。

因为SYSCLK后面通常还有:

text 复制代码
AHB Prescaler

十三、什么是HCLK

SYSCLK进入AHB分频器:

text 复制代码
SYSCLK
  ↓
AHB Prescaler
  ↓
HCLK

所以:

text 复制代码
HCLK = SYSCLK / AHB分频系数

例如:

text 复制代码
SYSCLK = 72MHz
AHB Prescaler = 1

得到:

text 复制代码
HCLK = 72MHz

如果:

text 复制代码
AHB Prescaler = 2

则:

text 复制代码
HCLK = 36MHz

HCLK通常供给:

  • CPU内核;
  • AHB总线;
  • 存储器接口;
  • DMA;
  • 部分高速外设。

因此我们常说的:

text 复制代码
CPU主频

很多情况下实际上更接近:

text 复制代码
HCLK

十四、AHB是什么

AHB:

text 复制代码
Advanced High-performance Bus

可以简单理解为STM32内部的:

text 复制代码
高速总线

高速设备通常挂在AHB总线,例如不同STM32系列可能包括:

text 复制代码
CPU
DMA
SRAM
Flash接口
GPIO
CRC
部分高速外设

具体哪个外设挂在哪条总线上,要看具体芯片。

不要死记不同型号的外设分配。


十五、什么是PCLK1和PCLK2

HCLK继续经过APB分频:

text 复制代码
HCLK
 ├── APB1 Prescaler → PCLK1
 └── APB2 Prescaler → PCLK2

于是:

text 复制代码
PCLK1 = HCLK / APB1分频系数

PCLK2 = HCLK / APB2分频系数

其中:

text 复制代码
PCLK1

主要供给APB1总线外设;

text 复制代码
PCLK2

主要供给APB2总线外设。


十六、APB1和APB2有什么区别

可以粗略理解:

text 复制代码
APB1:低速外设总线
APB2:高速外设总线

但"低速"和"高速"是总线分类概念,不代表每个设备本身一定很慢或很快。

以经典STM32F103为例,常见分布包括:

APB1

可能包括:

text 复制代码
USART2
USART3
I2C1
I2C2
TIM2
TIM3
TIM4
CAN

APB2

可能包括:

text 复制代码
USART1
SPI1
ADC
TIM1
GPIO相关控制

但不同STM32系列的外设归属差异非常大。

实际项目中应查看:

text 复制代码
Reference Manual → Memory Map / RCC

或者直接使用CubeMX查看。


十七、为什么要分AHB、APB1和APB2

最核心原因是:

不同模块并不需要全部运行在CPU最高频率。

例如:

text 复制代码
CPU运行72MHz

但某些低速外设可能只需要:

text 复制代码
36MHz

于是就可以配置:

text 复制代码
HCLK = 72MHz
APB1 = /2
PCLK1 = 36MHz

好处包括:

text 复制代码
降低功耗
满足外设最高频率限制
减轻总线压力
方便时钟管理

十八、用STM32F103完整走一遍时钟树

这是理解时钟树最好的方法。

假设:

text 复制代码
HSE = 8MHz

希望CPU运行:

text 复制代码
72MHz

第一步:HSE输入PLL

text 复制代码
HSE = 8MHz

第二步:PLL倍频

设置:

text 复制代码
PLL × 9

得到:

text 复制代码
8MHz × 9 = 72MHz

第三步:选择PLL作为SYSCLK

于是:

text 复制代码
SYSCLK = 72MHz

第四步:AHB不分频

配置:

text 复制代码
AHB Prescaler = 1

于是:

text 复制代码
HCLK = 72MHz

CPU也运行在:

text 复制代码
72MHz

第五步:APB1分频

由于经典STM32F103 APB1允许的最高频率低于72MHz,所以通常配置:

text 复制代码
APB1 Prescaler = 2

于是:

text 复制代码
PCLK1 = 72MHz / 2
      = 36MHz

第六步:APB2不分频

设置:

text 复制代码
APB2 Prescaler = 1

于是:

text 复制代码
PCLK2 = 72MHz

最终得到:

text 复制代码
HSE       = 8MHz
PLL       = ×9
SYSCLK    = 72MHz
HCLK      = 72MHz
PCLK1     = 36MHz
PCLK2     = 72MHz

这就是STM32F103最经典的72MHz时钟配置。


十九、时钟树总流程

整理成一张逻辑图:

text 复制代码
HSE = 8MHz
    │
    ▼
 PLL ×9
    │
    ▼
SYSCLK = 72MHz
    │
    ▼
AHB /1
    │
    ▼
HCLK = 72MHz
   ┌─────────────┐
   │             │
   ▼             ▼
APB1 /2        APB2 /1
   │             │
   ▼             ▼
PCLK1=36MHz   PCLK2=72MHz

这张图理解以后,再看CubeMX就容易很多。


二十、外设最终拿到的时钟怎么判断

这是最关键的一步。

很多人看懂:

text 复制代码
SYSCLK
HCLK
PCLK1
PCLK2

之后还是不知道:

USART1到底多少MHz?

USART2多少MHz?

TIM3是多少MHz?

核心方法只有两步。


第一步:找到外设挂在哪条总线

例如STM32F103:

text 复制代码
USART1 → APB2
USART2 → APB1
TIM2   → APB1
SPI1   → APB2

第二步:根据总线时钟继续计算

例如:

text 复制代码
PCLK1 = 36MHz
PCLK2 = 72MHz

所以一般情况下:

text 复制代码
USART1时钟来自PCLK2
USART2时钟来自PCLK1

于是:

text 复制代码
USART1 ≈ 72MHz时钟源
USART2 ≈ 36MHz时钟源

但部分现代STM32允许UART单独选择:

text 复制代码
PCLK
SYSCLK
HSI
LSE

因此不能永久套用旧型号规则。


二十一、UART为什么和时钟树关系很大

UART波特率的产生,本质上依赖UART外设时钟。

概念上可以理解:

text 复制代码
USART时钟
    ↓
波特率分频器
    ↓
目标波特率

例如希望:

text 复制代码
115200 bit/s

UART会根据输入时钟计算对应的分频值。

如果程序认为:

text 复制代码
UART时钟 = 72MHz

但实际只有:

text 复制代码
36MHz

那么产生的实际波特率就会严重错误。

表现为:

text 复制代码
串口乱码
无法通信
偶尔能收到数据
高波特率错误率明显升高

所以串口乱码时,不要只检查:

text 复制代码
TX/RX
波特率
停止位

还要检查:

text 复制代码
UART真正拿到的时钟是多少

二十二、SPI时钟怎么来的

SPI时钟通常由外设总线时钟再分频产生。

例如:

text 复制代码
SPI源时钟 = 72MHz

SPI配置:

text 复制代码
Prescaler = 8

则SPI SCK约为:

text 复制代码
72MHz / 8 = 9MHz

因此SPI通信速度错误时,也要检查:

text 复制代码
PCLK是多少?
SPI挂在哪条总线?
SPI Prescaler是多少?

二十三、I2C也依赖外设时钟

I2C内部需要根据外设输入时钟计算:

text 复制代码
SCL高低电平时间
数据保持时间
建立时间

所以改变系统时钟后,如果I2C时序参数没有同步更新,可能导致:

text 复制代码
SCL频率错误
通信超时
ACK异常
高速模式失败

老型号STM32和新型号STM32的I2C时序配置方式区别很大。

例如较新STM32常见:

text 复制代码
TIMINGR

所以应优先使用CubeMX计算,然后用示波器实测SCL频率。


二十四、ADC时钟为什么特别重要

ADC并不能无限提高时钟。

ADC内部需要完成:

text 复制代码
采样
保持
逐次逼近转换

如果ADC时钟超过芯片规定范围,可能造成:

text 复制代码
ADC精度下降
转换结果不稳定
数据偏差

例如经典STM32F1中,ADC时钟需要由PCLK2进一步分频,并满足芯片规定的最高频率。

概念上:

text 复制代码
PCLK2
  ↓
ADC Prescaler
  ↓
ADC Clock

所以ADC不稳定时除了检查:

text 复制代码
输入阻抗
参考电压
采样时间

还要检查:

text 复制代码
ADC Clock

二十五、最容易看错的是定时器时钟

这是STM32时钟树最经典的坑之一。

很多人认为:

text 复制代码
TIM2挂在APB1

PCLK1 = 36MHz

所以TIM2时钟 = 36MHz

这并不一定正确。

在很多STM32系列中:

当APB预分频器不等于1时,对应总线上的定时器时钟可能会自动变成PCLK的2倍。

例如STM32F103:

text 复制代码
HCLK = 72MHz

APB1 Prescaler = 2

PCLK1 = 36MHz

但是:

text 复制代码
TIM2/TIM3/TIM4时钟 = 72MHz

而不是36MHz。

所以:

text 复制代码
PCLK1 = 36MHz
TIMCLK = 72MHz

二十六、为什么定时器会出现2倍时钟

这样设计可以让:

text 复制代码
APB总线降低频率

从而降低功耗,同时:

text 复制代码
定时器仍然保持较高计数精度

因此可以做到:

text 复制代码
APB总线运行36MHz
定时器运行72MHz

兼顾:

text 复制代码
功耗
+
定时器性能

二十七、定时器频率应该怎么计算

假设:

text 复制代码
TIMCLK = 72MHz
PSC = 71
ARR = 999

计数器频率:

text 复制代码
fCNT = 72MHz / (71 + 1)
     = 1MHz

每一次计数:

text 复制代码
1μs

定时器更新频率:

text 复制代码
fUPDATE =
72MHz / [(71 + 1) × (999 + 1)]

得到:

text 复制代码
fUPDATE = 1kHz

周期:

text 复制代码
1ms

如果错误地把TIMCLK认为36MHz:

text 复制代码
fUPDATE = 500Hz

结果直接差2倍。

这就是很多STM32定时器:

text 复制代码
频率为什么正好差一倍

的原因之一。


二十八、是不是所有STM32定时器都是PCLK×2

不是。

这一点必须特别强调。

不同STM32系列可能存在:

text 复制代码
不同APB定时器时钟规则
TIMPRE配置
不同定时器时钟选择器
独立Kernel Clock

部分系列在不同条件下甚至可能存在:

text 复制代码
PCLK
2 × PCLK
4 × PCLK
其他独立时钟

因此工程中必须按照:

text 复制代码
具体芯片Reference Manual

确认。

不要看到"STM32定时器×2"就认为所有型号都完全一样。


二十九、RTC使用什么时钟

RTC的目标与CPU不同。

CPU需要:

text 复制代码
高性能

RTC更关注:

text 复制代码
低功耗
长期稳定
掉电后继续走时

因此RTC通常可以选择:

text 复制代码
LSE
LSI
某些芯片的HSE分频

如果要求时间准确,一般更推荐:

text 复制代码
LSE 32.768kHz

如果只是简单计时或对精度要求不高,可以使用:

text 复制代码
LSI

三十、USB为什么经常有特殊时钟要求

USB通信需要较高的时钟精度。

传统USB Full Speed相关模块常常需要:

text 复制代码
48MHz时钟域

因此STM32时钟树中经常可以看到专门的一条:

text 复制代码
PLL
 ↓
PLLQ或其他分频
 ↓
48MHz
 ↓
USB

现代STM32不同系列的USB时钟来源可能不同。

配置USB时不能只检查:

text 复制代码
SYSCLK是否正确

还必须检查:

text 复制代码
USB Kernel Clock

是否满足要求。


三十一、什么是Kernel Clock

在较新的STM32系列中,会频繁看到:

text 复制代码
Peripheral Kernel Clock

这意味着:

外设工作时钟不一定简单等于PCLK。

某个UART可能选择:

text 复制代码
PCLK
SYSCLK
HSI
LSE

ADC可能使用独立:

text 复制代码
PLL输出
专用异步时钟

所以在STM32H7、G4、U5等较新系列里,看时钟树不能只停留在:

text 复制代码
PCLK1
PCLK2

必须继续找到:

text 复制代码
Peripheral Clock Source

三十二、为什么CPU时钟越高不一定越好

很多初学者喜欢直接把STM32配置到最大主频。

例如:

text 复制代码
芯片最大168MHz
→ 直接168MHz

但更高频率意味着:

text 复制代码
功耗增加
EMI增加
Flash等待周期增加
电源要求提高
散热增加

如果应用只是:

text 复制代码
读取温度
控制继电器
RS485通信

可能根本不需要最大主频。

时钟配置应该根据:

text 复制代码
业务计算量
实时性
功耗
通信需求
外设限制

综合决定。


三十三、Flash等待周期为什么与系统时钟有关

CPU速度很高时,Flash并不一定能够单周期提供指令。

因此STM32中通常存在:

text 复制代码
Flash Latency

例如随着CPU频率增加,需要设置更高的:

text 复制代码
Wait State

否则系统可能出现:

text 复制代码
启动异常
程序跑飞
HardFault
随机死机

CubeMX一般会根据主频自动配置Flash等待周期。

如果完全手写RCC寄存器,必须特别注意这一点。


三十四、时钟配置和电压等级也有关

部分高性能STM32中:

text 复制代码
最高CPU频率

与内部电压调节器、电压等级有关。

例如某些系列存在:

text 复制代码
Voltage Scaling
OverDrive
Boost Mode

如果电压等级不满足要求,却强行配置很高主频,系统可能不稳定。

因此高性能STM32的主频配置通常需要考虑:

text 复制代码
电源
↓
Voltage Scale
↓
Flash Latency
↓
PLL
↓
SYSCLK

而不是只修改PLL倍频。


三十五、CubeMX时钟树应该怎么看

建议按照以下6步。


第一步:看时钟源

先确认:

text 复制代码
HSI
HSE
LSI
LSE

哪些被启用。

例如:

text 复制代码
HSE = 8MHz

第二步:看PLL

确认:

text 复制代码
PLL输入来自哪里
预分频多少
倍频多少
最终输出多少

例如:

text 复制代码
8MHz × 9 = 72MHz

第三步:看SYSCLK

找到:

text 复制代码
System Clock Mux

确认SYSCLK选择的是:

text 复制代码
HSI?
HSE?
PLL?

以及最终频率是多少。


第四步:看HCLK

检查:

text 复制代码
AHB Prescaler

例如:

text 复制代码
SYSCLK = 72MHz
AHB /1
HCLK = 72MHz

第五步:看PCLK1和PCLK2

例如:

text 复制代码
APB1 /2 → PCLK1 = 36MHz

APB2 /1 → PCLK2 = 72MHz

第六步:看目标外设

例如想知道:

text 复制代码
TIM3

就继续追踪:

text 复制代码
TIM3属于哪条总线?
↓
该总线PCLK是多少?
↓
定时器有没有×2或独立时钟规则?
↓
得到真正TIMCLK

这才完成整个时钟分析。


三十六、最推荐的"时钟树阅读口诀"

可以记成:

text 复制代码
一看源
二看PLL
三看SYSCLK
四看HCLK
五看PCLK
六看外设

也就是:

text 复制代码
时钟源
  ↓
倍频/分频
  ↓
SYSCLK
  ↓
HCLK
  ↓
PCLK
  ↓
Peripheral Clock

三十七、如何通过代码查看当前系统时钟

HAL库提供了一些非常方便的函数。

例如:

c 复制代码
uint32_t sysclk;
uint32_t hclk;
uint32_t pclk1;
uint32_t pclk2;

sysclk = HAL_RCC_GetSysClockFreq();
hclk   = HAL_RCC_GetHCLKFreq();
pclk1  = HAL_RCC_GetPCLK1Freq();
pclk2  = HAL_RCC_GetPCLK2Freq();

可以打印:

c 复制代码
printf("SYSCLK = %lu Hz\r\n", sysclk);
printf("HCLK   = %lu Hz\r\n", hclk);
printf("PCLK1  = %lu Hz\r\n", pclk1);
printf("PCLK2  = %lu Hz\r\n", pclk2);

例如输出:

text 复制代码
SYSCLK = 72000000 Hz
HCLK   = 72000000 Hz
PCLK1  = 36000000 Hz
PCLK2  = 72000000 Hz

这是验证时钟配置非常简单的方法。

不过:

这些函数返回的是HAL根据当前RCC配置计算出的频率,不等同于使用示波器直接测出的真实晶振频率。

对于高精度验证仍应进行实际测量。


三十八、SystemCoreClock是什么

CMSIS中经常看到:

c 复制代码
SystemCoreClock

它通常保存当前内核时钟信息。

例如:

c 复制代码
printf(
    "SystemCoreClock = %lu\r\n",
    SystemCoreClock
);

修改时钟配置后,某些场景需要调用:

c 复制代码
SystemCoreClockUpdate();

重新计算。

如果SystemCoreClock错误,可能影响:

text 复制代码
SysTick
延时函数
RTOS Tick
某些库中的时间计算

三十九、如何实际验证时钟是不是对的

不要完全相信软件配置。

工程中推荐至少验证一个实际输出。


方法一:串口波特率验证

例如配置:

text 复制代码
USART = 115200

使用示波器测量一个bit宽度。

理论时间:

text 复制代码
1 / 115200
≈ 8.68μs

如果明显不是这个数值,就应该检查时钟。


方法二:定时器PWM验证

例如配置:

text 复制代码
PWM = 1kHz

示波器测量周期应该约为:

text 复制代码
1ms

如果实际:

text 复制代码
2ms

就很可能存在:

text 复制代码
时钟计算差2倍

方法三:MCO输出

很多STM32支持:

text 复制代码
MCO
Microcontroller Clock Output

可以把某些内部时钟输出到GPIO。

例如:

text 复制代码
SYSCLK
HSE
HSI
PLL

通过示波器或频率计直接测量。

这是调试时钟问题非常有效的方法。


四十、常见错误1:把SYSCLK当成所有外设时钟

错误理解:

text 复制代码
SYSCLK = 72MHz

所以UART、SPI、TIM、ADC全是72MHz

这是错误的。

真实过程是:

text 复制代码
SYSCLK
 ↓
AHB
 ↓
APB1/APB2
 ↓
外设自己的分频

所以外设时钟很可能完全不同。


四十一、常见错误2:把PCLK直接当TIMCLK

例如:

text 复制代码
PCLK1 = 36MHz

就认为:

text 复制代码
TIM3 = 36MHz

实际上经典STM32F103中,由于APB1进行了分频:

text 复制代码
TIM3 = 72MHz

因此定时器频率恰好差2倍,是非常典型的现象。


四十二、常见错误3:改变系统主频后没修改外设参数

例如原来:

text 复制代码
SYSCLK = 72MHz

后来改成:

text 复制代码
SYSCLK = 48MHz

但UART、定时器和SPI配置没有重新计算。

可能出现:

text 复制代码
UART波特率错误
PWM频率错误
定时器延时错误
SPI速度变化

因此修改时钟后,应重新检查所有依赖时钟的外设。


四十三、常见错误4:HSE晶振频率定义错误

例如板子实际晶振:

text 复制代码
25MHz

软件却认为:

text 复制代码
8MHz

那么整个PLL计算都会错误。

部分工程中需要检查:

c 复制代码
HSE_VALUE

定义是否与实际硬件一致。

这种问题非常隐蔽,因为程序可能仍然能跑,但:

text 复制代码
串口波特率
定时器
USB
系统Tick

可能全部存在偏差。


四十四、常见错误5:外部晶振不起振

如果程序配置:

text 复制代码
使用HSE

但HSE实际没有起振,系统可能:

text 复制代码
启动失败
等待HSE Ready超时
回退到HSI
卡在Error_Handler

需要检查:

  • 晶振型号;
  • 负载电容;
  • PCB走线;
  • RCC配置;
  • HSE Bypass模式;
  • 外部时钟是否真的存在。

四十五、常见错误6:把晶振模式和Bypass模式搞混

如果使用的是:

text 复制代码
无源晶振

通常选择:

text 复制代码
Crystal/Ceramic Resonator

如果外部直接输入有源时钟:

text 复制代码
方波时钟

通常应选择:

text 复制代码
HSE Bypass

两种模式不同。

配置错误可能导致HSE无法正常工作。


四十六、常见错误7:只看CubeMX绿色不代表工程一定正确

CubeMX显示绿色通常表示:

text 复制代码
频率配置在软件规则允许范围内

但并不能自动保证:

  • PCB晶振设计正确;
  • 实际晶振频率正确;
  • USB物理层一定工作;
  • 外设通信时序一定满足对端要求;
  • EMI一定满足要求;
  • 电源一定足够稳定。

所以推荐:

text 复制代码
CubeMX配置
+
参考手册确认
+
示波器实测

三者结合。


四十七、一个完整案例:为什么TIM3配置1kHz实际却是500Hz

假设程序设计人员认为:

text 复制代码
PCLK1 = 36MHz
TIM3时钟 = 36MHz

于是设置:

text 复制代码
PSC = 35
ARR = 999

计算:

text 复制代码
36MHz / 36 / 1000
= 1kHz

但经典STM32F103中:

text 复制代码
APB1 Prescaler = 2

导致:

text 复制代码
TIM3 Clock = 2 × PCLK1
           = 72MHz

那么实际:

text 复制代码
72MHz / 36 / 1000
= 2kHz

结果就比预期快一倍。

同理,如果反过来误判,也可能出现实际频率只有目标的一半。

所以定时器频率异常时,首先检查:

text 复制代码
TIM真正的输入时钟

而不是直接修改PSC和ARR"碰运气"。


四十八、一个完整案例:UART乱码怎么查

遇到UART乱码,可以按照:

text 复制代码
第一步:检查双方波特率
第二步:检查8N1等格式
第三步:检查TX/RX线路
第四步:确认UART挂在哪条总线
第五步:确认PCLK或Kernel Clock
第六步:确认HSE/HSI实际频率
第七步:示波器测量bit宽度

例如:

text 复制代码
115200 baud

理论一个bit:

text 复制代码
8.68μs

如果示波器测到:

text 复制代码
17.36μs

那么实际大约:

text 复制代码
57600 baud

时钟计算很可能正好差2倍。


四十九、看STM32时钟树最重要的思维方式

不要背:

text 复制代码
USART1是多少MHz
TIM3是多少MHz
ADC是多少MHz

因为换一个STM32型号,答案可能全部变化。

真正应该掌握的是:

text 复制代码
这个外设的时钟从哪里来?
        ↓
经过了哪些选择器?
        ↓
经过了哪些分频器?
        ↓
有没有特殊规则?
        ↓
最终得到多少频率?

这才是真正能够迁移到不同STM32系列的方法。


五十、不同STM32系列怎么看

STM32F1

时钟结构相对简单,非常适合入门:

text 复制代码
HSI/HSE
 ↓
PLL
 ↓
SYSCLK
 ↓
AHB
 ↓
APB1/APB2

STM32F4/F7

PLL开始明显复杂:

text 复制代码
PLLM
PLLN
PLLP
PLLQ

需要同时考虑:

text 复制代码
SYSCLK
USB
SDIO
RNG等

STM32H7

时钟树更加复杂,存在:

text 复制代码
多个PLL
多个时钟域
D1/D2/D3
独立Kernel Clock
不同外设Clock Mux

这时更应该遵循:

text 复制代码
从目标外设反向追踪

而不是试图一次记住整张时钟图。


五十一、时钟树的万能阅读法

以后无论遇到:

text 复制代码
STM32F103
STM32F407
STM32G431
STM32H743
STM32U5

都可以按照下面顺序。

第1步:找时钟源

text 复制代码
HSI/HSE/MSI/CSI......

第2步:找PLL

text 复制代码
输入
÷M
×N
÷P/Q/R

第3步:找SYSCLK

text 复制代码
系统主时钟选择了谁?

第4步:找HCLK

text 复制代码
SYSCLK经过AHB分频是多少?

第5步:找PCLK

text 复制代码
APB1/APB2/APB3/APB4分别是多少?

第6步:找到目标外设

例如:

text 复制代码
USART3
TIM6
ADC1
SPI2

第7步:检查特殊时钟规则

例如:

text 复制代码
TIM ×2
UART独立Kernel Clock
ADC异步时钟
USB 48MHz
RTC LSE

第8步:实测验证

使用:

text 复制代码
示波器
逻辑分析仪
MCO
串口
PWM

验证结果。


五十二、STM32时钟树速查表

名称 含义 主要用途
HSI 内部高速时钟 默认启动、系统时钟
HSE 外部高速时钟 高精度系统时钟
LSI 内部低速时钟 IWDG、RTC
LSE 外部低速时钟 高精度RTC
PLL 锁相环 倍频/频率合成
SYSCLK 系统主时钟 整个时钟树主干
HCLK AHB时钟 CPU、内存、DMA等
PCLK1 APB1总线时钟 APB1外设
PCLK2 APB2总线时钟 APB2外设
TIMCLK 定时器时钟 定时器计数/PWM
MCO 时钟输出 调试内部时钟

五十三、面试中怎么回答"STM32时钟树"

如果面试官问:

STM32时钟树是怎么工作的?

可以回答:

text 复制代码
STM32时钟树主要负责把内部或外部时钟源,
经过PLL倍频、预分频以及各级总线分频,
最终分配给CPU和不同外设。

常见时钟源包括HSI、HSE、LSI和LSE。

系统高速时钟通常会先经过PLL生成所需频率,
然后选择为SYSCLK。

SYSCLK再经过AHB Prescaler形成HCLK,
HCLK主要供给CPU、存储器和AHB总线。

HCLK继续经过APB分频形成PCLK1和PCLK2,
为不同APB外设提供时钟。

实际计算某个外设时钟时,
不能只看SYSCLK,而要确认外设挂在哪条总线,
是否存在独立Kernel Clock,
以及定时器等外设是否存在特殊倍频规则。

如果面试官继续问:

为什么TIM3的时钟可能是PCLK1的2倍?

可以回答:

text 复制代码
在很多STM32系列中,
当APB预分频器不等于1时,
对应APB上的定时器时钟会使用PCLK的2倍,
这样可以在降低APB总线频率和功耗的同时,
保持较高的定时器计数频率。

不过不同STM32系列规则可能不同,
需要以具体参考手册为准。

五十四、总结

STM32时钟树看起来非常复杂,但真正的核心主线只有一条:

text 复制代码
时钟源
 ↓
PLL倍频/分频
 ↓
SYSCLK
 ↓
AHB分频
 ↓
HCLK
 ↓
APB分频
 ↓
PCLK
 ↓
外设时钟

看时钟树时,可以牢记:

text 复制代码
一看时钟源
二看PLL
三看SYSCLK
四看HCLK
五看PCLK
六看目标外设

四种常见时钟源:

text 复制代码
HSI:内部高速RC
HSE:外部高速晶振/时钟
LSI:内部低速RC
LSE:外部32.768kHz晶振

几个核心时钟:

text 复制代码
SYSCLK:系统主时钟

HCLK:AHB总线及CPU相关时钟

PCLK1:APB1外设时钟

PCLK2:APB2外设时钟

经典STM32F103配置可以表示为:

text 复制代码
8MHz HSE
   ↓
PLL × 9
   ↓
SYSCLK = 72MHz
   ↓
AHB /1
   ↓
HCLK = 72MHz
   ├───────────────┐
   ↓               ↓
APB1 /2          APB2 /1
   ↓               ↓
PCLK1=36MHz      PCLK2=72MHz

最后还需要特别记住:

外设时钟并不一定等于SYSCLK,也不一定简单等于PCLK。定时器、ADC、USB以及现代STM32中的UART等外设,都可能存在特殊时钟规则或独立Kernel Clock。

所以真正正确的STM32时钟分析方法不是死记频率,而是:

找到时钟从哪里来,沿着时钟树一步一步追踪到目标外设。

这样无论换成F1、F4、G4、H7还是其他STM32系列,都能自己计算出正确的外设工作频率。

相关推荐
十月的皮皮1 小时前
STM32从零到量产开发:四路继电器工业控制模块开发 - 上位机操作说明书
c语言·stm32·单片机·stm32cubemx
ShiMetaPi2 小时前
ShiMetaPi-Pico-G1快速入门:04 系统登录
stm32·单片机·嵌入式硬件
Run_Teenage3 小时前
嵌入式:深刻理解GPIO的上拉输入、下拉输入、浮空输入、模拟输入
单片机·嵌入式硬件
单片机杂货铺4 小时前
【单片机毕业设计选题】基于LoRa的智慧农业环境监测系统设计与实现
stm32·单片机·嵌入式硬件·51单片机·硬件工程·课程设计
云泽8084 小时前
深入浅出 STM32(八):GPIO 寄存器底层原理与 CubeMX 点亮 LED 实战
stm32·单片机·嵌入式硬件
单片机杂货铺18 小时前
基于单片机的智能粮仓控制系统设计与实现
stm32·单片机·嵌入式硬件·物联网·计算机外设·51单片机·课程设计
指尖的爷18 小时前
RKNN转化环境搭建(rknn_toolkit2新版本)
嵌入式硬件·深度学习·物联网·目标检测
梁朝辉18 小时前
滴泪的曲线(Curved)还是直线(Line)什么区别,都应用于什么场景!
嵌入式硬件·硬件工程
clear sky .20 小时前
stm32H7进入HardFault_Handler机制
stm32·单片机·嵌入式硬件