news 2026/9/10 13:01:58

嵌入式铁头山羊stm32-时钟树和时钟树编程(配置想要的默认初始时钟频率)-Day20

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
嵌入式铁头山羊stm32-时钟树和时钟树编程(配置想要的默认初始时钟频率)-Day20

嵌入式铁头山羊STM32-各章节详细笔记-查阅传送门(点击传送)


目录

一、时钟树

1.时钟和时钟树的概念

2.分频器、锁相环和复用器

3.树根(四种)

4.树干

5.树枝

6.练习

二、时钟树编程

1.时钟树的初始状态

代码测试:

2.标准库的启动代码

​3.时钟树的编程接口

​4.配置时钟树(使用代码去配置自己想要的时钟树,即时钟信号的频率由自己配置)

5.配置Flash指令预取

6.片上外设开关和复位


一、时钟树

1.时钟和时钟树的概念

时钟”(Clock)主要指的是提供给整个芯片(或者其中某个模块)运行的基准频率信号。这个时钟信号类似一个“节拍器”,所有指令执行、外设工作、总线传输都依赖它来“按节奏”进行。注意:这个时钟频率的快慢,也导致了他所支持的外设的执行快慢。

---简单来说,这个时钟是单片机的心脏,每个外设想要启动,先得启动这个外设对应的时钟

时钟树,单片机这里分为两颗树,一颗大树(高速树),一颗小树(低速树),我们主要是看大树这里,

首先其树根类似于左图的心跳这块,即产生时钟信号的。

接着,树干这里是:经过前面的梯形表示的复用器去复用时钟信号既而得到系统时钟

(SYSCLK)。

然后就是到分支了。即有树干产生了三个分支,每个分支上的叶子,就代表一个片上外设。

什么是“时钟树”?

时钟树就是 MCU 内部时钟分配的结构图。

  • MCU 里不止一个时钟源(内部的 HSI、外部的 HSE、PLL 倍频后的时钟等等)。

  • 不同的模块(CPU 内核、外设、总线、定时器、ADC 等)需要不一样的时钟。

  • 为了把一个或几个“总时钟源”分配给这么多模块,MCU 内部就设计了一个“分发网络”,它看起来像一棵树——根在底下(时钟源),树枝不断分叉(分频、倍频、选择),树叶就是外设。

所以叫时钟树

形象比喻

  • 把 MCU 里的时钟源(HSI/HSE/PLL)想象成水厂

  • 分频器 / 倍频器就是水管阀门,可以调整水流大小。

  • 不同的外设(CPU、总线、UART、SPI…)就是城市里的用水户

时钟树就是一张“供水管网图”,告诉你水(时钟信号)怎么从源头分到各个用户。

为什么要搞“时钟树”?

  1. 灵活性:不同外设需要的速度不同,比如 USART 可能只要几十 MHz,CPU 可能要 100+ MHz。

  2. 省电:可以关闭不需要的时钟支路,减少功耗。

  3. 稳定性:外设之间互不干扰,每个外设有自己的“水管”。




2.分频器、锁相环和复用器


3.树根(四种)

树根这里分为四种,即内外接、高低速的时钟源,注意:根据时钟源的不同,将两树分为高速树和低速树。

注意:为啥单片机有高低速的时钟源都有还要接外部的,因为内部的一般精度要求不高,所以想精度上有要求的话就得外接。

4.树干

主要就剩复用器这里的三种路径罢了

5.树枝

经过AHB总线得到的三大分支

6.练习

二、时钟树编程

1.时钟树的初始状态

初始的所有分频器后都产生的是8MHz(注意这里涉及到启动文件的细节,后面会讲,其实默认情况是72MHz)

代码测试:

这里使用代码进行测试是否初始是8MHz

判断:之前的延迟使用的是delay函数,这里使用for循环,假设一个for循环消耗10个时钟周期,那要延迟500ms就是400000次循环。这里注意1/f是一个时钟周期,所以会乘10代表一次for循环对应的时间。

按照上面的想法去运行发现一次闪烁,即一次亮灭很快,闪烁的非常快,说明有问题,看下面继续讲


2.标准库的启动代码

在启动文件里面发现这句话,即在main函数执行前都会先执行SystemInit,主要帮助用户选择最高频率。既而就表示你默认的是72MHz,所以会闪烁的很快

这里尝试注释这两行汇编语言(使用封号注释),然后再运行观察发现效果好多了,但是还是有点快,

这个问题出现在一开始的假设一个for循环为10个时钟周期(因为不同设备时钟周期不一样),这里比如一个for循环是6个时钟周期等等,发现闪烁正常实现了。


3.时钟树的编程接口

举个图中的例子,锁相环,第一个参数是复用器选择的传入信号,第二个是选择是*6或者乘多少

即参数1 为源头,参数2为倍频系数


4.配置时钟树(使用代码去配置自己想要的时钟树,即时钟信号的频率由自己配置)

这里当注释掉一开使的SystemInit后,默认就是直接走main,直接为8MHz。

所以这里尝试使用代码去配置想要的时钟树,这里尝试将默认的8MHz配置为72MHz的时钟树。使用前面的编程接口 。


注意顺序一定是:
1.先选择输入信号为HSE,即开始HSE,因为开启要时间,所以还要判断标志位

2.之后配置索相环,配置输入的信号和乘以的系数,即源头和倍频系数

3.之后先配置分频系数

4.最后配置复用器为HSE

5.(增加“指令预取”的操作,这个后面讲了)

Q为啥要先设置分配器再切换源头

  • #3:设置分频器
    👉 就是先规定好「CPU、外设们最多能跑多快」。
    (比如:CPU = 72 MHz,APB1 ≤ 36 MHz,APB2 ≤ 72 MHz)

  • #4:切换 SYSCLK
    👉 就是把 MCU 的真正工作时钟切换到你配置好的 PLL。


⚠️ 如果你先执行 #4(切时钟),再去执行 #3(分频):

  • 在那一瞬间,所有总线和外设会直接吃到未分频的高频时钟,可能超过它们的极限。

  • 结果就是外设异常、死机、复位

所以 ST 官方手册里要求:
✅ 必须先设置分频器 (#3),确保“护栏”立好 → 再切换 SYSCLK (#4),这样就不会超频。


📌一句话总结
分频器相当于「限速器」,要先设好限速,再让车跑起来;
如果先让车跑起来(切 SYSCLK),再设限速,就有可能瞬间超速出事。


5.配置Flash指令预取

当你配置了72MHz的时钟树后就需要配置指令预取,这是因为本来cpu只是简单的8MHz的话,自己没延迟(因为小于24MHz),但是当你指定配置了72MHz的频率树,太快了,所以就需要配置这个《预取功能》了

专业解释

  1. CPU 执行指令的速度 vs Flash 读出的速度

    • STM32 的代码存放在Flash(片上程序存储器)里。

    • 当 CPU 时钟频率很高(比如 72 MHz)时,Flash 的读取速度跟不上 CPU 的取指速度

    • 如果 CPU 每个周期都要等 Flash 慢吞吞地把指令拿出来,性能就会大幅下降。

  2. 预取缓冲的作用

    • Prefetch Buffer就是一个小缓存:它会提前把后面可能要用的指令读到缓冲区里。

    • 这样 CPU 要用的时候就能直接取,减少等待。

  3. 为什么在配置时钟树时要开预取?

    • 一旦系统切换到高频率运行,Flash 不开预取就会变成瓶颈

    • 所以在切换 SYSCLK 到 PLL 高速运行之前,要配置:

      • 开启指令预取

      • 设置 Flash 等待周期(LATENCY),确保读取稳定。


通俗解释(小白版)

想象 MCU = 一个学生,

  • CPU = 写作业的手

  • Flash = 铅笔盒里拿铅笔

如果 CPU 写字速度很慢(低频),每次从铅笔盒里慢慢拿笔,不会影响。
但当 CPU 写字特别快(高频),它每次都要等你打开铅笔盒 → 卡顿 → 写不下去。

解决办法

  • 在桌上先摆一排备用的笔(= 预取缓冲)。

  • CPU 要写字时,直接从桌子上拿笔就行,不用等铅笔盒。

这样,CPU 即使跑得飞快,拿笔(取指令)的速度也能跟上。


总结一句话
配置时钟树后 MCU 可能跑到几十 MHz 甚至上百 MHz,Flash 太慢跟不上 CPU。
所以要开启预取功能,提前把指令准备好,避免 CPU 卡住等 Flash。

6.片上外设开关和复位

这里面没有说明白,其实就是复位按钮的实现,是需要写两句话的,一句是按下按钮,一句是抬起。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!