TIM简介
- TIM(Timer)定时器
- 定时器可以对输入的时钟进行计数【内部 / 外部时钟】,并在计数值达到设定值时触发中断
定时触发中断,定时器的本质上就是一个计数器
16位计数器【每来一个时钟,计数器+=1】、预分频器【对计数器的技术进行分频】、自动重装寄存器【就是目标值,多少个时钟数申请中断】的时基单元【三个都是16位的】,在72MHz计数时钟下可以实现最大59.65s的定时。
(1/72M) * 65536 * 65536,预分频器开最大,自动重装开最大。也可以使用多个定时器级联来定时,一个定时器的输出,作为一个定时器的输入,两个即可实现 59.65秒 * 65536 * 65536的定时
- 不仅具备基本的定时中断功能,而且还包含内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等多种功能
- 根据复杂度和应用场景分为了
高级定时器【最为复杂】、通用定时器【中等复杂,最常用】、基本定时器【最简单】三种类型
定时器类型
STM32F103C8T6中的定时器资源:
TIM1、TIM2、TIM3、TIM4
其中1个高级(TIM1)、3个通用、无基本定时器
Tip:库函数中还有9、10、11,不过一般都用不到;不同的型号,有的定时器也不一样

高级定时器:
TIM1、TIM8
挂载总线APB2
拥有 通用定时器 全部功能,并额外具有重复计数器、死区生成、互补输出、刹车输入【主要为了三向无刷电机使用】等功能
对于高级定时器,主要的区别是右下边这里,其他的和基本定时器差不多
主要升级如下:
1、重复次数计数器
有了这个计数器,就可以实现每隔几个计数周期,才发生一次更新事件和更新中断【原来是一个就得发生一次,就相当于给输出信号又做了一次分频,例如之前计算的最大定时时间59s,这里就可以再乘以65536【16位的重复次数计数器】】
2、高级定时器对输出比较模块的升级
DTG(Dead Time Generate)是死区生成电路,右边的输出引脚,可以输出互补的PWM波【原来是一个输出】,用于驱动三相无刷电机用的,第四路没什么变化,因为三相无刷电机只需要3路即可。
为了防止互补输出的PWM驱动桥臂时,在开关切换的瞬间,由于器件的不理想,造成短暂的直通现象,所以加入了死区生成电路,在开关切换的瞬间,产生一定的死区,让桥臂的上下管全部关断,防止直通。
3、刹车输入
为电机驱动提供安全保障,如果外部引脚BRK(Break IN)产生了刹车信号,或者内部时钟失效,产生故障,那么控制电路就会自动切断电机的输出,防止意外的发生

注意,高级时钟连接的是AP2总线,而通用定时器和基本定时器连接的是APB1总线,在RCC使能时钟的时候需要注意
通用定时器:
TIM2、TIM3、TIM4、TIM5
挂载总线APB1
拥有 基本定时器 全部功能,并额外具有内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等功能

基本定时器
TIM6、TIM7
挂载总线APB1
拥有基本的定时中断、主模式触发DAC的功能(定时器可以和DAC联合使用)

主从触发模式:【STM32的一个最大的特色】
可以让内部的硬件在不受程序的控制下实现自动运行,运用得当可以极大的减轻CPU的负担
右上角的DAC,就是在间隔固定时间触发一次DAC转换。
原先的操作模式是设置定时器,然后固定时间触发一次DAC,但是这样主程序会处于频繁中断的状态。
现在通过主从模式,可以把更新事件通过主模式映射到TRGO【触发输出,右上角】,再把TRGO接到DAC的触发转换引脚上,然后TRGO就会直接去触发DAC,整个过程不需要软件的参与,实现了硬件自动化
定时器中断基本结构
PSC【Prescaler】+ CNT 【Count】+ ARR【Auto Reload Register】组成时基单元
运行控制:控制开启计时灯操作【启动停止,向上或者向下计数】

更新中断后续走的路:
更新中断会先在状态寄存器里面置一个中断标志位,这个标志位会通过中断输出控制,到NVIC申请中断
为什么要有一个中断输出控制?:
因为定时器里面很多东西都要申请中断,不仅仅只有更新中断,还有触发中断、下面的输入捕获和输出比较匹配的时候也会申请,所以用一个中断输出控制,如果需要这个中断,那就允许,如果不需要,那就禁止
时基单元运行细节
预分频器时序
- CK_PSC:时钟,内部时钟就是72Mhz
- CK_CNT:计数器时钟,明显的频率变慢了1倍
- CNT_EN:时钟使能位,高电平计数器启动

Tip:预分频寄存器的缓冲机制
预分频寄存器其实有两个:一个寄存器,一个缓冲器【或者叫影子寄存器】,
第一个用于给我们读写,并不起真的作用,第二个缓冲器才是真正作用的寄存器;
比如在某个时刻,我们把预分配寄存器的值从0改为1,如果此时马上修改时钟的分频系数,就会导致在一个时钟周期内,前半部分的技术频率和后半部分不一样,由于STM32的定时器比较严谨,在计数一半的时候改变预分配,不会马上生效,只有在本次计数完成,产生更新事件后,预分配寄存器的值才会被传递到缓冲寄存器里面去,才会生效
预分频器是怎么实现分频的呢?:
聪明的你可以发现,预分频之后的波形和之前的波形,并不是简单的频率除以2,而是好像又等待了一个周期,然后再次输出波形
这就是说明:预分配器内部也是计数的,在回到0的时候输出一个方波,当我们PSC为1的时候,它在输出的时候就会计数,0、1,这样就可以实现2分频了
计数器计数频率:CK_CNT计数器时钟 = CK_PSC时钟源 / (PSC预分频 + 1)
计数器时序
更新事件是一个脉冲
而更新中断标志UIF,只要置1之后,就会申请中断,然后中断响应后,需要在中断程序中,手动清0
计数器溢出频率:
这里的CK_XXX全部都是频率
溢出频率 = CK_CNT_OV = CK_CNT / (ARR + 1) = CK_PSC / (PSC + 1) / (ARR + 1)
溢出时间 = (ARR + 1) x TIM_CNT = (ARR + 1) x (1/CK_PSC) x (PSC + 1)
简单举一个例子:
如果现在,时钟源采用内部时钟72M,预分配器PSC设置为1,ARR自动重装载寄存器为35,那么定时时间是多少?
溢出时间 = (ARR + 1) * (TIM_CNT ) = (ARR + 1) * (1 / CK_PSC) * (PSC + 1)
溢出时间 = (35 + 1) * (1 / 72M) * (1 + 1) = 36 * (1 / 36M) = 1ns
一般更多的时候,是给出一个需要定时的时间,来反推PSC和ARR的,但是,在知道公式的情况下,一切都简单啦
更何况,很多芯片厂家都会给原厂DEMO的,一般会直接给你宏定义,直接改就好了,很简单

缓冲寄存器
上面的图里面寄存器带阴影的,都是有缓冲寄存器机制的,我们的自动加载寄存器也是带的,但是你可以选择开不开【通过ARPE标志位就可以】,下面一个是预装,一个不预装
就是下面这个,预装载寄存器

在下图,我们可以看出,开不开预装载寄存器的区别
区别就是,如果你开了预装载,那么我们变自动加载寄存器的时候ARR的时候,他不会马上变,他会等到一个更新事件来了之后,他才会变调
如果你没有开预装载,那么你只要一修改ARR,那么不管当前有没有溢出,那么都会直接改掉ARR
这个...我感觉很少用吧,STM32还是很严谨的,因为一般不太会改这个ARR,高精度的场合可能比较需要
这里讲一个不开会出问题的地方!
如果是向上计数,FF改成36,此时是F1,36比F1还小,那么计数器就会一直增加,直到增加到FFFF,溢出归0,重新加到36,才能产生更新,就会有一个这个问题,所以推荐开哈哈

RCC时钟树
这个时钟树,就是STM32中,用来产生和配置时钟,并且把配置好的时钟发送到各个外设的系统
时钟是所有外设运行的基础,所以时钟也是最先需要配置的东西
之前有说过,程序main函数开始执行前,还会执行一个SystemInit函数,这个函数就是用来配置这个时钟树的
