STM32时钟树详解:配错一个全乱套

你有没有遇到过:UART波特率9600发出来却是乱码?定时器中断频率不对?

十有八九是时钟配置错了。这篇把STM32时钟树从HSE讲到APB,帮你彻底搞懂。


一、为什么时钟这么重要?

STM32的每个外设都依赖时钟工作:

  • UART波特率 = APB时钟 / 分频
  • I2C/SPI速率 = APB时钟 / 分频
  • 定时器中断频率 = APB时钟 / (PSC+1)(ARR+1)
  • ADC转换时间 = ADC时钟相关

时钟配错了,所有外设的时序全错


二、四个时钟源

STM32有4个时钟源:

时钟源 简称 频率 精度 用途
内部高速RC HSI 8MHz/16MHz ±1% 上电默认,精度差
外部高速晶振 HSE 4-26MHz ±20ppm 主力时钟,精度高
内部低速RC LSI 32kHz-40kHz ±10% 看门狗、RTC
外部低速晶振 LSE 32.768kHz ±20ppm RTC精准计时

主力用HSE(外部晶振)。HSI精度差(±1%),高波特率通信可能出错。


三、时钟树(以STM32F103为例)

复制代码
HSE 8MHz ──→ PLL倍频 ──→ SYSCLK(72MHz) ──→ AHB分频 ──→ HCLK(72MHz)

> **PLL是什么?** PLL(Phase-Locked Loop,锁相环)是STM32内部的一个硬件模块,你可以理解为一个"频率乘法器"------输入8MHz,设置倍频系数×9,输出就是8×9=72MHz。STM32内部没法直接产生72MHz的高频时钟,所以用PLL把外部晶振的8MHz"放大"到72MHz。
                                                              │
                                    ┌─────────────────────────┤
                                    ↓                           ↓
                              APB1分频                    APB2分频
                              (/2 = 36MHz)               (/1 = 72MHz)
                                    │                           │
                                    ↓                           ↓
                              PCLK1(36MHz)               PCLK2(72MHz)
                              (UART2/3, I2C,             (UART1, SPI1,
                               TIM2-7, ADC)               TIM1, GPIO)
                                                              │
                                                              ↓
                                                        ADC时钟(≤14MHz)

3.1 SYSCLK

系统时钟,MCU的主频。STM32F103最高72MHz,STM32F407最高168MHz,STM32H7最高480MHz。

3.2 HCLK

AHB总线时钟,CPU和DMA跑在这个频率上。通常等于SYSCLK。

3.3 PCLK1(APB1)

低速外设时钟,STM32F103最大36MHz。挂在这里的:USART2/3、I2C、SPI2、TIM2-7、ADC。

3.4 PCLK2(APB2)

高速外设时钟,STM32F103最大72MHz。挂在这里的:USART1、SPI1、TIM1、GPIO、ADC。

3.5 定时器倍频

重要 :当APB1分频≠1时(通常÷2=36MHz),挂在上面的定时器会自动×2倍频=72MHz。

复制代码
APB1 = 36MHz → 定时器时钟 = 36MHz × 2 = 72MHz
APB2 = 72MHz → 定时器时钟 = 72MHz(不倍频,因为APB2分频=1)

坑点:很多人以为TIM2-7的时钟是36MHz,实际是72MHz。算定时器频率时别搞错。


四、典型配置(F103 @ 72MHz)

4.1 CubeMX配置

复制代码
HSE: 8MHz (外部晶振)
PLL Source: HSE
PLL Multiplier: ×9  →  8MHz × 9 = 72MHz
SYSCLK: PLL = 72MHz
AHB Prescaler: /1  →  HCLK = 72MHz
APB1 Prescaler: /2  →  PCLK1 = 36MHz
APB2 Prescaler: /1  →  PCLK2 = 72MHz

4.2 代码(寄存器版)

c 复制代码
void SystemClock_Config(void)
{
    /* 1. 开HSE */
    RCC->CR |= (1 << 16);                    /* HSEON */
    while (!(RCC->CR & (1 << 17)));          /* 等HSERDY */

    /* 2. 配置Flash等待周期(72MHz需要2个等待) */
    /* Flash是物理存储,读取速度有限。CPU跑72MHz时,Flash来不及在一个时钟周期内交出数据,
     * 需要等2个周期。不配等待周期会导致CPU读到错误指令,程序跑飞。
     * prefetch(预取)是让Flash提前取下一条指令,弥补等待周期的性能损失 */
    FLASH->ACR = 0x00000012;                 /* 2 wait states + prefetch */

    /* 3. 配置PLL:HSE × 9 = 72MHz */
    RCC->CFGR |= (1 << 16);                  /* PLLSRC = HSE */
    RCC->CFGR |= (7 << 18);                  /* PLLMUL = ×9 */

    /* 4. 配置分频 */
    RCC->CFGR |= (4 << 8);                   /* APB1 = HCLK/2 = 36MHz */
    /* APB2 = HCLK/1 = 72MHz,默认不用配 */

    /* 5. 开PLL */
    RCC->CR |= (1 << 24);                    /* PLLON */
    while (!(RCC->CR & (1 << 25)));          /* 等PLLRDY */

    /* 6. 切换SYSCLK到PLL */
    RCC->CFGR |= (2 << 0);                   /* SW = PLL */
    while (((RCC->CFGR >> 2) & 3) != 2);     /* 等SWS = PLL */
}

五、时钟与外设的关系

5.1 UART波特率

c 复制代码
/* UART1挂在APB2(72MHz) */
波特率 = 72MHz / (16 × BRR值)
BRR = 72MHz / (16 × 115200) = 39.0625 ≈ 39

/* UART2挂在APB1(36MHz) */
波特率 = 36MHz / (16 × BRR值)
BRR = 36MHz / (16 × 115200) = 19.53 ≈ 20

注意:UART1和UART2时钟不同,BRR值也不同。配错时钟,波特率必错。

5.2 定时器频率

c 复制代码
/* TIM2挂在APB1(36MHz),定时器倍频×2 = 72MHz */
中断频率 = 72MHz / [(PSC+1) × (ARR+1)]

/* 要1kHz中断 */
/* 72MHz / [(71+1) × (999+1)] = 1kHz ✓ */

5.3 ADC时钟

STM32F103的ADC最大14MHz,从APB2(72MHz)分频:

复制代码
ADCCLK = PCLK2 / 分频系数
72MHz / 6 = 12MHz ✓(≤14MHz)
72MHz / 4 = 18MHz ✗(超过14MHz,可能出错)

六、常见踩坑

坑1:UART乱码------时钟没配

现象:代码写115200,串口助手收到的全是乱码。

原因:系统时钟默认8MHz(HSI),但波特率按72MHz算的。

解决 :确保SystemClock_Config()被调用,且配置正确。


坑2:定时器频率差9倍

原因:没配PLL,SYSCLK=8MHz而非72MHz。定时器按72MHz算,实际8MHz,差9倍。


坑3:ADC时钟超限

ADC时钟超过14MHz(F103限制),采样数据不稳定甚至损坏。检查分频系数。


坑4:Flash等待周期不够

CPU频率>24MHz(F103)时,Flash读取需要等待周期。72MHz需要2个等待周期,不配会HardFault。


七、总结

要点 内容
四个时钟源 HSE(主力)/HSI(备用)/LSE(RTC)/LSI(看门狗)
SYSCLK 系统主频,F103最高72MHz
APB1 低速,F103最大36MHz,定时器×2倍频=72MHz
APB2 高速,F103最大72MHz
时钟影响 UART波特率、定时器频率、ADC速率全取决于时钟

一句话总结 :时钟树的核心是**"HSE→PLL倍频→SYSCLK→AHB/APB分频→外设"**,配错任何一级,下游全错。


下一篇预告:《启动流程详解:从上电到main()发生了什么》

如果这篇文章对你有帮助,点赞 + 收藏 + 关注 ,这是我持续更新的动力!

有问题欢迎评论区交流,我会逐条回复。

作者:嵌入式阿蔡

相关推荐
caimouse2 小时前
ReactOS 图形系统分析(37):路径子系统 — path.c
c语言·reactos
CarIise2 小时前
C语言基础课程笔记:硬件原理、数据类型、结构体与格式化输入输出详解
c语言·开发语言·笔记
GeekZHR2 小时前
C语言指针2:数组名、二级指针、指针数组,一次把“指针和数组“讲透
c语言·数据结构·算法·指针
zlinear数据采集卡2 小时前
数据采集卡从入门到精通(7):流水线型ADC——级级接力,高速与高精的平衡术
开发语言·arm开发·嵌入式硬件·fpga开发·c#
Dr.kangder3 小时前
嵌入式面试总结(二十一)——C语言关键字
c语言·开发语言·面试·职场和发展·架构·虚拟化
bobuddy3 小时前
CMW500信令测试关键配置要点
嵌入式硬件
花花鱼3 小时前
TinyML Agent:MCU 上的微型智能体,AI 智能体下沉的底层实现
人工智能·单片机·嵌入式硬件
lsz1525903 小时前
嵌入式开发第一步:STM32 F1系列功能介绍与快速上手
stm32·单片机·嵌入式硬件·嵌入式开发·可扩展模块
橘色的喵4 小时前
SD 卡在上电后的完整加载流程:从中断信号到文件系统挂载
单片机·嵌入式硬件·嵌入式·rt-thread·rtos