嵌入式铁头山羊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…)就是城市里的用水户。
时钟树就是一张“供水管网图”,告诉你水(时钟信号)怎么从源头分到各个用户。
为什么要搞“时钟树”?
灵活性:不同外设需要的速度不同,比如 USART 可能只要几十 MHz,CPU 可能要 100+ MHz。
省电:可以关闭不需要的时钟支路,减少功耗。
稳定性:外设之间互不干扰,每个外设有自己的“水管”。
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的频率树,太快了,所以就需要配置这个《预取功能》了
专业解释
CPU 执行指令的速度 vs Flash 读出的速度
STM32 的代码存放在Flash(片上程序存储器)里。
当 CPU 时钟频率很高(比如 72 MHz)时,Flash 的读取速度跟不上 CPU 的取指速度。
如果 CPU 每个周期都要等 Flash 慢吞吞地把指令拿出来,性能就会大幅下降。
预取缓冲的作用
Prefetch Buffer就是一个小缓存:它会提前把后面可能要用的指令读到缓冲区里。
这样 CPU 要用的时候就能直接取,减少等待。
为什么在配置时钟树时要开预取?
一旦系统切换到高频率运行,Flash 不开预取就会变成瓶颈。
所以在切换 SYSCLK 到 PLL 高速运行之前,要配置:
开启指令预取
设置 Flash 等待周期(LATENCY),确保读取稳定。
通俗解释(小白版)
想象 MCU = 一个学生,
CPU = 写作业的手
Flash = 铅笔盒里拿铅笔
如果 CPU 写字速度很慢(低频),每次从铅笔盒里慢慢拿笔,不会影响。
但当 CPU 写字特别快(高频),它每次都要等你打开铅笔盒 → 卡顿 → 写不下去。解决办法:
在桌上先摆一排备用的笔(= 预取缓冲)。
CPU 要写字时,直接从桌子上拿笔就行,不用等铅笔盒。
这样,CPU 即使跑得飞快,拿笔(取指令)的速度也能跟上。
总结一句话:
配置时钟树后 MCU 可能跑到几十 MHz 甚至上百 MHz,Flash 太慢跟不上 CPU。
所以要开启预取功能,提前把指令准备好,避免 CPU 卡住等 Flash。
6.片上外设开关和复位
这里面没有说明白,其实就是复位按钮的实现,是需要写两句话的,一句是按下按钮,一句是抬起。