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系列,都能自己计算出正确的外设工作频率。