【自学嵌入式:stm32单片机】TIM定时中断
观前提醒:本文是听江科大stm32课程的听课笔记,这节课内容多,难度大,我自己反复听了3个小时,还查了很多资料,整理了如下笔记。
TIM定时中断
TIM(Timer)定时器
- 定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断
- 定时器基准时钟一般是CPU主频72Mhz,对72Mhz记72个数,那就是1Mhz,也就是1us的时间,如果记72000个数,那就是1KHz,也就是1ms的时间
- 16位计数器、预分频器、自动重装寄存器的时基单元,在72MHz计数时钟下可以实现最大59.65s的定时,\(2^{16}=65536\),预分频器设置最大,自动重装也设置最大,那定时器的最大定时事件就是59.65s,接近一分钟,72M/65536/65536得到的是中断频率,然后取倒数,就是59.65秒多,如果嫌最大定时时间不构成,stm32定时器还支持级联模式,也就是一个定时器的输出当作另一个定时器的输入,这样加在一起,自大定时时间就是59.65s再乘2次65536,这个时间大概是8000多年,还可以继续级联一个定时器,定时时间还会再延长65536×65536倍,这个时间大概是34万亿年。
- 不仅具备基本的定时中断功能,而且还包含内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等多种功能
- 根据复杂度和应用场景分为了高级定时器、通用定时器、基本定时器三种类型
定时器类型
| 类型 | 编号 | 总线 | 功能 | 
|---|---|---|---|
| 高级定时器 | TIM1、TIM8 | APB2 | 拥有通用定时器全部功能,并额外具有重复计数器、死区生成、互补输出、刹车输入等功能 | 
| 通用定时器 | TIM2、TIM3、TIM4、TIM5 | APB1 | 拥有基本定时器全部功能,并额外具有内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等功能 | 
| 基本定时器 | TIM6、TIM7 | APB1 | 拥有定时中断、主模式触发DAC的功能 | 
STM32F103C8T6定时器资源:TIM1、TIM2、TIM3、TIM4,也就是一个高级定时器TIM1,和3个通用定时器TIM2、TIM3、TIM4。不同的型号定时器的数量是不同的。
高级定时器连的是速度更高的APB2总线。
【注】
- 重复计数器:定时器计数到设定值后,能让该计数过程重复执行若干次的功能,比如让定时任务循环运行多遍。
- 死区生成:在互补信号切换时插入短暂时间间隔,避免功率管等器件因同时导通引发短路,类似开关切换时的“缓冲停顿”。
- 互补输出:同时输出一对逻辑相反的电平信号(如一路高电平、另一路低电平),常用于电机驱动等场景控制功率开关。
- 刹车输入:当检测到刹车信号时,立即关停定时器相关输出,实现设备的紧急制动,如同汽车踩刹车瞬间停车。
- 内外时钟源选择:定时器可自主选择芯片内部的时钟信号,或外部引脚输入的时钟信号来驱动计数,二选一工作。
- 输入捕获:捕捉外部信号的跳变时刻(如上升沿、下降沿),用于测量信号频率、脉冲宽度等时间参数。
- 输出比较:当定时器计数值与预设值匹配时,触发特定输出动作(如电平翻转、中断请求),像“到点触发报警”。
- 编码器接口:连接旋转编码器,自动解析编码器输出的脉冲信号,获取电机转速、旋转位置等运动信息。
- 主从触发模式:主定时器的事件(如计数溢出)触发从定时器执行动作(如启动计数),实现多定时器联动控制。
- 定时中断:定时器计满设定时间后,主动触发CPU中断,让CPU暂停当前任务,去处理定时相关的事件(类似闹钟响铃提醒)。
- 主模式触发DAC:定时器工作在主模式时,到达特定时刻会触发DAC(数模转换器)进行转换,输出模拟电压,用于生成波形等场景。
基本定时器


触发中断流程
如上图,它们构成了最基本的计数计时电路,所以这一块电路叫做时基单元
由于基本定时器只能选择内部时钟,所以相当于从CK_INT(内部时钟)直接到预分频器PSC,内部时钟的来源是RCC_TIMxCLK,这里的频率值一般都是系统的主频72Mhz,PSC预分频器可以对72Mhz频率进行预分频,PSC为0,不分频,输出频率=输入频率=72Mhz,如果PSC为1,那就是2分频,输出频率=输入频率/2=36Mhz,如果PSC为2,就是3分频,输出=输入/3...以此类推,即实际分频系数=预分频器PSC的值+1,这个预分频器是17位的,所以最大值可以写65535,也就是65536分频。
计数器CNT可以对预分频后的计数时钟进行计数,计数时钟每来一个上升沿,计数器的值就加1,这个计数器也是16位的,所以里面可以从0加到65535,如果再加的话,就溢出回到了0,所以计数器CNT在运行过程中不断自增,当自增运行到目标值时,产生中断,那就完成了定时的任务,所以需要一个存储目标值的寄存器,那就是自动重装载寄存器。
自动重装载寄存器也算16位的,它存的就是我们写入的计数目标,在运行的过程中,计数值不断自增,自动重装值是固定的目标,当计数值等于自动重装值时,也就是计时时间到了,那它就会产生一个中断信号,并且清零计数器,计数器自动开启下一次的计数计时。

图中,向上的折线箭头,就代表这里会产生中断信号。向下的折线箭头,代表产生一个事件。
计数值等于自动重装值产生的中断,一般称为“更新中断”,这个更新中断之后,就会通往NVIC,我们再配置号NVIC的定时器通道,那定时器的更新中断就能够得到CPU的响应了,图中向下的折线箭头对应的叫“更新事件”,更新事件不会触发中断,但可以触发内部其他电路的工作。
主模式
主模式触发DAC的用途就是在使用DAC的时候,可能会用DAC输出一段波形,那就需要每隔一段时间来触发依次DAC,让它输出下一个电压点,如果用正常思路来实现的话,就是先设置一个定时器产生中断,每隔一段事件,在中断程序中调用代码手动触发一次DAC转换,然后DAC输出,这样没问题,但是这样会使主程序频繁被中断,这会影响主程序的运行和其他中断的响应,所以就设计了一个定时器的主模式,使用这个主模式可以把这个定时器的更新事件映射到触发输出TRGO(Trigger Out)的位置,TRGO直接接到DAC的触发转换引脚上,这样定时器的更新就不需要再通过中断来触发DAC转换了,仅需要把更新事件通过主模式映射到TRGO,然后TRGO就会直接去触发DAC了,整个过程不需要软件的参与,实现了硬件的自动化,这就是主模式的作用。
通用定时器


中间最核心的部分还是时基单元,这一部分和基本定时器一样,如上图的红圈范围。
计数模式
对于通用定时器而言,这个计数器的计数模式就不止向上计数这一种了,所谓向上计数,也就是计数器从0开始,向上自增,计到重装值,清零同时申请中断,然后开始下一轮,依次循环,这是向上计数。
除了这种向上计数的模式外,通用定时器和高级定时器还支持向下计数模式和中央对齐模式。
向下计数模式就是从重装值开始,向下自减,减到0之后,回到重装值同时申请中断,然后进入下一轮,依次循环,这就是向下计数。
中央对齐模式就是从0开始,先向上自增,计到重装值,申请中断,然后再向下自减,减到0,再申请中断,然后进入下一轮,依次循环。
最常用的是向上计数模式。
外部时钟

如上图,这部分就是内外时钟源选择和主从触发模式的结构,对于基本定时器而言,定时器只能选择内部时钟,也就是系统频率72Mhz,到了通用定时器这里,时钟源不仅可以选择内部的72MHz时钟,还可以选择外部时钟,第一个外部时钟是来自TIMx_ETR引脚上的外部时钟,这个ETR(External)引脚位置可参考下图定义表(对应PA0引脚):

这里有TIM2_CH1_ETR,意思就是这个TIM2的CH1和ETR都是复用在了这个位置,表中下面还有TIM2,3,4 CH2,3,4和其他定时器的一些引脚,也都可以在这里找到,我们可以在TIM2的ETR引脚,接上一个外部方波时钟,然后配置一下内部的极性选择\(^{【注】}\)、边沿检测和预分频电路,再配置一下输入滤波电路,这两块电路可以对外部时钟进行一定的整形,因为是外部引脚的时钟,所以难免会有些毛刺(不是正好的方波),那这些电路可以对输入的波形进行滤波,同时也可以选择一下极性和预分频器。
【注】在电子电路或定时器等设备中,极性选择通常指对信号的有效状态(如高低电平)或触发边沿(上升沿 / 下降沿)进行设定的功能。
比如选择 “高电平有效” 还是 “低电平有效”,或是选信号从低到高跳变(上升沿)还是从高到低跳变(下降沿)时触发动作,就像设定 “开关按下去通电” 还是 “松开时通电”。
最后,如上图,滤波后的信号,兵分两路,上面一路ETRF进入触发控制器,紧跟着就可以选择作为时基单元的时钟了,如果想用ETR外部引脚提供时钟,或者相对ETR时钟进行计数,把这个定时器当作计数器来用的话,那就可以配置这一路的电路,在stm32中,这一路也叫做“外部时钟模式2”。

如上图,除了外部ETR引脚可以提供时钟外,下面还有一路可以提供时钟,就是TRGI(Trigger In),它主要是用作触发输入来使用的,这个触发输入可以触发定时器的从模式,当TRGI当作外部时钟来使用的时候,这一路就叫做“外部时钟模式1”,通过这一路的外部时钟有:ETR引脚的信号、ITR信号
【注】
- 触发输入(TRGI,Trigger In):指定时器的一种输入信号通道,专门用来接收外部或其他设备发来的触发信号。就像一个 “启动指令入口”,这个信号可以是脉冲、电平跳变等,用于触发定时器执行特定操作。
- 从模式:定时器的一种工作模式,此时定时器不自主运行,而是像 “从属设备” 一样,受外部触发信号(这里即 TRGI 触发输入)的控制。比如触发信号到来时,定时器才开始计数、复位计数或停止计数等,相当于 “听令行事” 的模式。

如上图,这里ETR引脚既可以通过上面这一路来当作时钟,又可以通过下面这一路来当作时钟,两种情况对于时钟输入而言是等价的,只不过下面这一路输入会占用触发输入的通道而已。

如上图,ITR信号,这一部分的时钟信号是来自其他定时器的,从右侧可以看出,这个主模式的输出TRGO可以通向其他定时器,那通向其他定时器的时候,就接到了其他定时器的ITR引脚上来了,ITR0到ITR3分别来自其他4个定时器的TRGO输出,具体连接方式如下图:

这里可以看到,TIM2的ITR0是接在了TIM1的TRGO上的,ITR1接在了TIM8,ITR2接在了TIM3,ITR3接在了TIM4,其他定时器也都可以参照上图的表格,这就是ITR和定时器的连接关系。

如上图,通过这一路我们就可以实现定时器级联的功能,比如我们可以先初始化TIM3,然后使用主模式把它的更新事件映射到TRGO上,接着再初始化TIM2,这里选择ITR2,对应的就是TIM3的TRGO,然后后面再选择时钟为外部时钟模式1,这样TIM3的更新事件就可以驱动TIM2的时基单元,也就实现了定时器的级联,

如上图,这里还可以选择TI1F_ED,这里连接的是输入捕获单元的CH1引脚,也就是从CHI1引脚获得时钟,这里后缀加一个ED(Edge)就是边沿的意思,也就是通过这一路输入的时钟,上升沿和下降沿均有效。

如上图,这个时钟还能通过TI1FP1和TI2FP2获得,其中TI1FP1连接到了CH1引脚的时钟,TI2FP2连接到了CH2引脚的时钟。
总结:外部时钟模式1的输入可以是ETR引脚、其他定时器、CH1引脚的边沿、CHI1引脚和CH2引脚,一般情况下,外部时钟设置ETR引脚就可以了,下面设置这么复杂的输入,不仅仅是为了扩大时钟输入的范围,更多地还是为了某些特殊的应用场景而设计的,比如为了定时器的级联而设计了ITR那部分,图中下面部分后面讲到输入捕获和测频率的时候还会继续讲到。
对于时钟输入而言,最常用的还是内部的72Mhz时钟,如果要使用外部时钟,首选ETR引脚外部时钟模式2的输入,如果要使用外部室长,首选ETR引脚外部时钟模式2的输入,这一路最简单最直接。
编码器接口

如上图,编码器接口可以读取正交编码器的输出波形。
主模式输出

如上图,蓝色圈的部分就是定时器的主模式输出,这部分电路可以把内部的一些事件映射到TRGO引脚上,比如刚才的基本定时器分析,将更新事件映射到TRGO,用于触发DAC,这里也算一样,我们可以把定时器内部事件映射到TRGO,用于触发其他定时器、DAC或者ADC,这个触发输出的范围是比基本定时器更广一些。

如上图,也就是整个定时器下一半部分,右侧这个是输出比较电路,总共又4个通道,分别对应CH1到CH4的引脚,可以用于输出PWM波形,驱动电机。

如上图,也就是整个定时器的左下半部分,这一块是输入捕获电路,也是有四个通道,对应的也是CH1到CH4的引脚,可以用于测输入方波的频率等。

如上图,也就是整个定时器的中下部分,这个寄存器是捕获/比较寄存器,是输入捕获和输出比较电路共用的,因为输入捕获和输出比较不能同时使用,所以这里的寄存器是共用的,引脚也是共用的。
高级定时器

高级定时器主要改动的是右下角这一部分

如上图,申请中断的地方,增加了一个重复次数计数器,有了这个计数器之后,就可以实现每隔几个计数周期才发生依次更新事件和更新中断,如果没有这个重复次数计数器,那就是每个计数周期完成后都会发生更新,现在有个计数器在这里,可以实现每隔几个周期再更新一次,这就相当于对输出的更新信号又做了一次分频,那对于高级计时器,之前计算的最大定时时间59秒多,在这里还需要再乘一个65536,这就又提升了很多的定时时间了。

如上图,红圈圈起来的这些就是高级定时器对输出比较模块的升级了。

如上图,DTG(Dead Time Generate)是死区生成电路。

如上图,右边的输出引脚由原来的一个,变为两个互补的输出,可以输出一对互补的PWM波,这些电路是为了驱动三相无刷电机的,三相无刷电机常用于四轴飞行器、电动车的后轮、电钻等。

如上图,因为三相无刷电机的驱动电路有3个桥臂,每个桥臂由两个大功率开关管来控制,总共需要6个大功率开关管来控制。

如上图,所以这里输出PWM引脚的前三路就变味了互补的输出。而第四路却没什么变化,因为三相电机只需要三路就行了,为了防止互补输出的PWM驱动桥臂时,在开关切换的瞬间,由于器件的不理想,造成短暂的直通现象\(^{【注】}\),所以前面就加上了死区生成电路,在开关切换的瞬间,产生一定时长的死区,让桥臂的上下管全都关断,防止直通现象。
【注】在电子电路(尤其是互补输出的功率电路,如电机驱动的 H 桥、半桥等)中,直通现象指的是同一桥臂的上下两个功率器件(如 MOS 管、IGBT)同时处于导通状态,导致电源正负极通过这两个器件直接短路的情况。

如上图,这里是刹车输入的功能,这个是为了给电机驱动提供安全保障的,如果外部引脚BKIN(Break IN)产生了刹车信号\(^{【注】}\),或者内部时钟失效,产生了故障,那么控制电路就会自动切断电机的输出,防止意外的发生,
【注】在电子控制(尤其是功率电路、电机驱动等场景)中,刹车信号是一种用于紧急关停设备的控制信号。
比如,当系统检测到过流、过压、故障等危险情况时,会发出刹车信号,这个信号传入定时器或功率器件后,会立即切断输出、停止设备运行(像电机停转、功率开关关闭),相当于给设备 “踩急刹车”,防止损坏或危险扩大。
定时中断基本结构

预分频器时序

- CK_PSC:预分频器输入时钟,不断运行,选内部时钟的话一般是72Mhz
- CNT_EN:计数器使能,高电平计数器正常运行,低电平计数器停止
- CKCNT:定时器时钟,它既是预分频器的时钟输出,也算计数器的时钟输入。
 ![image]() 、 、
从时序图可以看到,开始时,计数器未使能,计数器时钟不运行,然后使能后,前半段,预分频器系数为1,计数器的时钟等于预分频器前的时钟,后半段,预分频器变为2,计数器的时钟也就变为预分频器前时钟的一半了,如下图:


如上图,在计数器时钟的驱动下,下面的计数器寄存器也跟随时钟的上升沿不断自增,在中间这个位置FC之后,计数值变为0了,这里虽然没写,但是可以推断出ARR自动重装值就是FC,当计数值计到和重装值相等,并且下一个时钟来临时,计数值才清零。

如上图,下面这里产生一个更新事件,这就是一个计数周期的工作流程,

如上图,时序图下面还有3行时序,这里描述的是预分频寄存器的一种缓冲机制,也就是这个预分频寄存器实际上是有两个,一个是预分频控制寄存器,供我们读写用的,它并不直接决定分频系数,另外还有一个预分频缓冲器或者说是影子寄存器,这个缓冲寄存器才是真正起作用的寄存器,比如在某个时刻,把预分频寄存器由0改成了1,如果在此时立刻改变时钟的分频系数,那么就会导致下图中,在一个计数周期内,前半部分和后半部分的频率不一样:

这里计数计到一半,计数频率突然就会改变了,这一般不会有什么问题,但是stm32的定时器比较严谨,设计了这个缓冲寄存器,这样,当计数计到一半的时候改变了分频值,这个变化并不会立刻生效,而是会等到本次计数周期结束时产生了更新事件,预分频寄存器的值才会被传递到缓冲寄存器里面区,才会生效,所以即使在计数中途改变了预分频值,计数频率仍然会保持原来的频率,如下图:

直到本轮计数完成,在下一轮计数时,改变后的分频值才会起作用,预分频器内部实际上也是靠计数来分频的,当预分频值为0时,计数器就一直为0,直接输出原频率,当预分频值为1时,计数器就0、1、0、1、0、1、0、1这样计数,在回到0的时候,输出一个脉冲,如下图:

这样输出频率就是输入频率的二分频,预分频器的值和实际的分频系数直接有一个数的偏移,那就有这样一个公式:计数器计数频率:\(\text{CK_CNT}=\frac{\text{CK_PSC}}{\text{PSC} + 1}\)
【注】
- 公式来源逻辑:
预分频器的作用是将输入时钟CK_PSC分频,让计数器以更低频率CK_CNT运行。预分频寄存器TIMx_PSC中存储的参数为PSC,但 分频逻辑是“每经过PSC+1个CK_PSC脉冲,才产生1个CK_CNT脉冲”(因为计数器从0开始计数,到PSC时触发分频,实际经历了PSC+1个输入周期)。- 通俗理解:
假设CK_PSC是“秒表每秒跳1下”,PSC=1时,秒表要跳 2下(1+1)才让计数器加1,相当于计数器的“秒表”变慢了——原来1秒跳1下,现在2秒跳1下,频率就是CK_PSC / 2。以此类推,PSC越大,CK_CNT频率越低,公式CK_CNT = CK_PSC / (PSC + 1)就对应这个分频规律。
(核心:PSC 是分频系数减1,因为计数从0开始,到PSC时完成一次分频,总周期数是PSC+1。)
计数器时序

计数器溢出频率:CK_CNT_OV = CK_CNT / (ARR + 1)
= CK_PSC / (PSC + 1) / (ARR + 1)
CK_INT内部时钟,72MHz;CNT_ENT,时钟使能,高电平启动;CK_CNT,计数器时钟,因为分频系数为2,所以这个频率是CK_INT的频率除2,然后计数器在这个时钟每个上升沿自增,如下图:

当自增到0036的时候发生溢出,再来一个上升沿,计数器清零,计数器溢出,产生一个更新事件脉冲,还会置一个更新标志位UIF,如下图:

这个标志位只要置1了,就会去申请中断,中断响应后,需要在中断程序中手动清零。
计数器溢出频率:\(\text{CK_CNT_OV}=\frac{\text{CK_CNT}}{\text{ARR}+1}=\frac{\text{CK_PSC}}{\frac{\text{PSC}+1}{\text{ARR}+1}}\)
【注】
- 公式拆解逻辑:
计数器溢出频率由 “预分频后的时钟(CK_CNT)” 和 “计数周期数(ARR+1)” 共同决定,分两步推导:- 第一步:预分频得到 CK_CNT:
输入时钟CK_PSC经过预分频器(参数PSC),分频后时钟频率为CK_CNT = CK_PSC / (PSC + 1)(PSC+1是因为计数器从0开始,到PSC时完成一次分频,实际经历PSC+1个输入周期)。- 第二步:计算溢出周期:
计数器从0计数到ARR时触发溢出,总共经历ARR + 1个CK_CNT周期(比如ARR=3,计数过程是0→1→2→3,共4个周期)。因此,溢出频率为CK_CNT_OV = CK_CNT / (ARR + 1)。- 合并公式:
将第一步的CK_CNT代入第二步,得到最终公式:
CK_CNT_OV = CK_PSC / (PSC + 1) / (ARR + 1),体现 预分频(PSC)和自动重装(ARR)共同降低溢出频率 的逻辑。- 通俗类比:
把CK_PSC想象成“每秒跳10下的秒表”,PSC=1时,秒表要跳 2下(1+1)才让计数器加1(即CK_CNT是5下/秒);若ARR=3,计数器要数 4下(3+1)才溢出。最终溢出频率就是10/(1+1)/(3+1) = 1.25次/秒——相当于每秒只溢出1.25次,完美对应公式的分频逻辑!
预分频器为了防止计数中途更改数值造成错误,设计了缓冲寄存器,这个计数器那肯德也少不了这样的设计了。

如上图,在结构图,带着阴影的寄存器,都是有影子寄存器这样的缓冲机制的,包括预分频器,自动重装寄存器和下面的捕获比较寄存器,所以计数的这个ARR自动重装寄存器,也是有一个缓冲寄存器的,并且这个缓冲寄存器是用还是不用,是可以自己设置的。
计数器无预装时序

这个就是没有缓冲寄存器的情况,在这里,计数器正在进行自增计数,突然更改自动加载寄存器,就是自动重装寄存器,由FF改成了36,那计数值的目标值就由FF变成了36,所以这里计到36之后,就直接更新,开始下一轮计数,如下图:

这里不使用影子寄存器,F5改到36立刻生效,但此时计数值已经到了F1,已经超过了36,F1只能增加但它的目标却是36,比它还小,这样F1就只能一直加,直到加到FFFF,再回到0,再加到36,才能产生更新,这就会造成一些小问题
计数器有预装时序

这个就是有缓冲寄存器的情况,通过设置这个ARPE位,就可以选择是否使用预装功能,在计数的中途,突然把计数目标由F5改成了36,下面的影子寄存器才是真正起作用的,它还是F5,所以现在计数的目标还是计到F5,产生更新事件,同时,要更改的36才被传递到影子寄存器,在下一个计数周期,这个更改的36才有效,所以可以看出,引入这个影子寄存器的目的实际上是为了同步。就是让值得变化和更新事件同步发生,防止在运行途中更改造成错误。
RCC时钟树

这个时钟树,就是stm32中用来产生和配置时钟,并且把配置好的时钟发送到各个外设的系统,时钟是所有外设运行的基础,所以时钟也算最先需要配置的东西,程序中主函数之前还会执行一个SystemInit函数,这个函数就是为了配置这个时钟树的,ST公司已经写好了配置这个时钟树的SystemInit函数。
时钟产生电路

如上图,界限左边是时钟产生电路,右边的是时钟分配电路,中间的SYSCLK就是系统时钟72MHz,在时钟产生电路,有四个震荡源,分别是内部8MHz高速RC振荡器,外部的4-16MHz告诉石英晶体振荡器,也就是晶振,一般都是接8MHz,外部额32.768KHz低速晶振,这个一般是给RTC提供时钟的,最后是内部的40KHz低速RC振荡器,这个可以给看门狗\(^{【注】}\)提供时钟,上面的告诉晶振是用来提供系统时钟的,AHB、APB2、APB1的时钟都是来源这两个告诉晶振,这里内部和外部都有一个8MHz的晶振,都是可以用的,只不过外部的石英振荡器比内部的RC振荡器更加稳定,所以一般我们都用外部晶振,如果系统很简单,不需要精确时钟,那也是可以使用内部RC振荡器的,这样就可以省下外部晶振的电路了。
【注】在 STM32 单片机中,看门狗(Watchdog) 是一种用于监控程序运行状态的定时器外设,核心作用是防止程序因异常(如死循环、跑飞、硬件故障等)陷入不可恢复的状态,确保系统在异常时能自动复位并重新启动,提升系统可靠性。
在SystemInit函数里,ST是这样来配置时钟的,首先它会启动内部时钟,选择内部8MHz为系统时钟,暂时以内部8MHz的时钟运行,然后再启动外部时钟,配置外部时钟走下图这一路(蓝色线):

进入PLL锁相环\(^{【注】}\)进行倍频,8MHz倍频9倍,得到72MHz,等到锁相环输出稳定后,选择锁相环输出为系统时钟,这样就把系统时钟由8MHz切换为了72MHz
【注】
- 什么是PLL锁相环:
简单说,PLL是一个“智能调节器”,能让输出信号的频率和输入信号保持固定的倍数关系,而且两者节奏(相位)完全同步,就像“跟着基准信号按比例跳舞”。- 核心作用:
把一个低频的“基准信号”(比如单片机里的8MHz晶振),稳定地转换成高频信号(比如72MHz),既放大了频率,又保证信号稳定不“跑偏”。- 工作过程(通俗版):
- 先“对比”:拿输入的基准信号和自己输出的信号比,看频率和节奏对不对得上;
- 再“调错”:如果对不上,就算出差距,慢慢调整输出信号的频率;
- 最后“锁定”:直到输出信号和基准信号的频率成固定倍数(比如10倍),节奏完全同步,就像“锁”在一起了,这就是“锁相”。
- 生活比喻:
好比你跟着音乐节拍走路,PLL就是你的“大脑”——先听音乐(基准信号),再调整步伐(输出信号),直到步伐频率正好是音乐节拍的2倍(比如音乐每秒1拍,你每秒走2步),而且每一步都踩在节拍上,这就是PLL的“锁相”效果。
如果外部晶振出现问题,可能会导致一个现象,程序时钟慢了大概10倍,比如你用定时器定一个1s的时间,结果过了大概10s才进中断,如果外部晶振出问题了,系统时钟就无法切换到72MHz,那它就会以8MHz运行,8MHz相比较72MHz,大概就慢了10倍。

如上图,这里还有个CSS(Clock Security System),这个是时钟安全系统,它也是负责切换时钟的,它可以检测外部时钟的运行状态,一旦外部时钟失效,它就会自动把外部时钟切换回内部时钟,保证系统时钟的运行,防止程序卡死造成事故。

高级定时器中,也有CSS的身影,在刹车输入这里,一旦CSS检测到外部时钟失效,这里通过或门,就会立刻反应到输出比较这里,如下图:

让这个输出控制的电机立刻停止,防止意外,这就是stm32里面的一些安全保障措施。
时钟分配电路

如上图,首先系统时钟72MHz进入AHB总线,AHB总线有个预分频器,在SystemInit里配置的分频系数为1,那AHB的时钟就是72Mhz,然后进入APB1总线,这里配置的分频系数是2,所以APB1总线的时钟为72MHz/2=36MHz,通用定时器和基本定时器是接在APB1上的,而APB1的时钟是36MHz,按理说它们的时钟应该是36MHz,但是定时器的时钟都是72MHz,这个原因如下图:

如果APB1预分频系数=1,则频率不变,否则乘2。

如上图,然后再看右侧,发现这一路是单独为定时器2~ 7开通的,因为APB1预分频系数是2,所以这里频率再乘2,所以通向定时器2~ 7的时钟,就又回到了72MHz,所以这里就有了结论,无论是高级定时器,还是通用定时器,还是基本定时器,它们的内部基准时钟都是72MHz

如上图,再看APB2的时钟,这里给的分频系数为1,所以APB2的时钟和AHB一样,都是72MHz

如上图,这里接在APB2上的高级定时器也单开了一路,上面写的也是如果APB2预分频系数=1,则频率不变,否则频率x2,但是这里APB2的预分频系数就是1,所以频率不变。

定时器1和8的时钟就是72MHZ

如上图,在这些时钟输出这里,都有一个与门进行输出控制,控制位写的是外部时钟使能,这就是我们在程序中写RCC-APB2/1PeriphClockCmd作用的地方,打开时钟,就是在这个位置写1,让左边的时钟能够通过与门输出给外设。
 
                    
                
 、
、 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号