第七课时:STM32时钟系统揭秘:从零理解时钟树

第七课时:时钟系统基础知识

本课主题:时钟系统基础知识,包括 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 脉冲,没有时钟,外设直接休眠。

四个时钟源,也就是整个时钟树的根部,是时钟的来源。

  1. HSI:内部高速 RC 时钟,8MHz,芯片内置,不用外部晶振,精度差,启动快。
  2. HSE:外部高速晶振,4 到 16MHz,我们一般用外部 8M 晶振,精度高,常用。
  3. LSI:内部低速 RC,40kHz,给独立看门狗 IWDG 用。
  4. 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 串联起来理解

  1. 触发器是时序电路的最小单元,很多触发器堆成寄存器,一堆寄存器加上总线、外设,就变成了 STM32 单片机。
  2. STM32 所有外设,GPIO、定时器、串口,全都是时序逻辑电路,必须给时钟 CP 才能运行。
  3. 时钟树就是产生各种 CP 脉冲,分给 CPU 和每一个外设。
  4. 写代码第一步开启 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。
相关推荐
知识分享小能手1 小时前
C学习教程,从入门到精通,C语言指针 —— 详细知识点总结(10)
c语言·开发语言·学习
金融小师妹1 小时前
多因子时间序列分析:美元与美债收益率变化对黄金价格+1.6%的影响
c语言·人工智能·git·决策树·pyqt
xxwl5852 小时前
区域赛算法模版第四章---数据结构
数据结构·c++·算法
硅基手札2 小时前
【Linux 内核专栏 17】进程间通信 IPC(上)— 管道·信号·System V IPC·mmap·文件锁
linux·运维·服务器·stm32·单片机·mcu
Zw-awa2 小时前
PID 用顺了,然后呢:增强手术与前馈
stm32
国科安芯2 小时前
无方向脚如何既快又稳:ASC0101S 自动方向感应机理与边沿加速应用研究
网络·嵌入式硬件·低轨卫星·商业航天·抗辐射
额额额对了2 小时前
Linux 驱动开发:基于 platform 总线 + misc 设备的 DS18B20 单总线温度驱动
linux·c语言·开发语言·驱动开发·嵌入式硬件
奶盐cookie2 小时前
内存区域:栈、全局区和静态区
c语言
头像很酷2 小时前
嵌入式虚拟化-xvisor-跨越边界的读客
c语言·hypervisor·xvisor·嵌入式虚拟化