TIM定时器
定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断
16位计数器、预分频器、自动重装寄存器(计数的目标值)的时基单元,在72MHz计数时钟下可以实现最大59.65s的定时(72M/65526/65526 = 中断频率,取倒数就为59.65s ,2的16次方=65526)
更长时间:级联模式,即一个定时器的输出,当作另一个定时器的输入,这样最大时间就是58.65s × 65536 × 65536
不仅具备基本的定时中断功能,而且还包含内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等多种功能
根据复杂度和应用场景分为了高级定时器、通用定时器、基本定时器三种类型
STM32F103C8T6定时器资源:TIM1、TIM2、TIM3、TIM4
基本定时器
预分频器,自动重装寄存器,计数器,构成了最基本的计数计时电路,叫作时基单元
预分频器之前连接的是基准计数时钟的输入,因为基本定时器只能选择内部时钟,所以可以认为直接连到了输入端,即内部时钟CK_INT,内部时钟的来源是RCC_TIMxCLK,频率值一般都是系统的主频72MHz,所以通向时基单元的计数基准频率为72M
预分频器可以对这72MHz的计数时钟进行预分频,比如,预分频器写0,这时输入频率 = 输出频率 = 72MHz ; 预分频器写1,为2分频,此时输出频率 = 输入频率/2 = 36MHz;预分频器写2,为3分频,此时输出频率 = 输入频率/3 ,所以预分频器的值和实际分频系数相差1,即实际分频系数 = 预分频器的值 + 1,因为为16位,最大可以写65535,即65536分频
计数器可以对预分频后的计数时钟进行计数,因为为16位,所以里面的值可以从0一直加到65535,再加就会从0重新开始。计数器的值在计时过程中会不断自增运行,当自增运行到目标值,产生中断,就完成了定时的任务
自动重装寄存器,存储目标值,当计数值 = 自动重装值,也就是计数时间到了,就会产生一个中断信号,并清零计数器,计数器自动开启下一次的计数计时
图中向上折线箭头,代表这里会产生中断信号,像这样,计数值 = 自动重装值产生的中断,一般叫做“更新中断”,这个更新中断之后就会通往NVIC,我们再配置好NVIC的定时器通道,那么定时器的更新中断就能够得到CPU的响应了
图中向下折线的箭头,代表会产生一个事件,叫作“更新事件”,不会触发中断,但可以触发内部其他电路的工作
主模式触发DAC功能:能让内部的硬件在不受程序控制下实现自动运行,在某些场景下可以极大减轻CPU负担
用途:在我们使用DAC的时候,可能会用DAC输出一段波形,那就需要每隔一段时间触发一次DAC,让它输出下一个电压点,
正常思路:先设置一个定时器产生中断,每隔一段时间在中断程序中调用代码手动触发一次DAC转换,然后DAC输出,没有问题,但是却会使主程序处于频繁被中断的状态,会影响主程序的运行和其他中断的响应,故定时器设计了主模式,可以把定时器的更新事件,映射到触发输出TRGO的位置,然后TRGO直接接到DAC的触发转换引脚上,这样,定时器的更新就不需要通过中断来触发DAC转换了,仅需把更新事件通过主模式映射到TRGO,然后TRGO就会直接触发DAC,实现了硬件的自动化
通用定时器
基本定时器仅支持向上计数模式
通用定时器和高级定时器还支持向下计数模式和中央对齐模式
中央对齐模式:从0开始,先向上自增,计到重装值,申请中断;再向下自减,减到0,申请中断,循环
内外时钟源选择结构:通用定时器时钟源不仅可以选择内部72MHz时钟,也可以选择外部时钟
TIMx_ETR
引脚定义表中,TIM2_CH1_ETR,就是TIM2的CH1和ETR都复用在PA0引脚
可以在TIM2的ETR引脚,也就是PA0上接一个外部方波时钟,再配置一下内部的极性选择、边沿检测和预分频器电路,再配置输入滤波电路,这两个电路可以对外部时钟进行一定整形,因为外部引脚的时钟难免会有毛刺,那么这些电路就可以对输入的波形进行滤波,滤波后的信号,兵分两路,上面一路ETRF进入触发控制器,紧跟着就可以作为时基单元的时钟。如果想在ETR外部引脚提供时钟,或者想对ETR时钟进行计数,把这个定时器当作计数器来用,就可以配置这一路的电路,这一路叫作“外部时钟模式2”;下面一路TRGI也可以提供时钟,主要是用作触发输入来使用,触发输入可以触发定时器的从模式,当TRGI当作外部时钟使用时,这一路叫作“外部时钟模式1”
外部输入模式1:
ETR引脚的信号可以通过上一路当作时钟,也可以通过下一路当作时钟,两种情况对于时钟输入是等价的,只不过下一路输入会占用触发输入的通道。
ITR信号,这一部分的时钟信号是来自其他定时器的,这个主模式的输出TRGO可以通向其他定时器,通向其他定时器时,就接到了其他定时器的ITR引脚上了,ITR0到ITR3分别来自其他4个定时器的TRGO输出
比如,可以先初始化TIM3,然后使用主模式将它的更新事件映射到TRGO上,再初始化TIM2(选择ITR2,对应的是TIM3的TRGO),后面再选择时钟为外部时钟模式1,这样TIM3的更新事件就可以驱动TIM2的时基单元,也就实现了定时器的级联
也可选择TI1F_ED,连接的是输入捕获单元的CH1引脚,也就是从CH1引脚获得时钟,后缀加一个ED(edge)就是边沿的意思,也就是通过这一路输入的时钟,上升沿和下降沿均有效
也可以通过TI1FP1和TI2FP2获得,TI1FP1是CH1引脚的时钟,TI2FP2是CH2引脚的时钟
编码器接口:可以读取正交编码器的输出波形
定时器的主模式输出,这部分电路可以把内部的一些事件映射到TRGO引脚上,我们可以把定时器内部的一些事件映射到这里来,用于触发其他定时器、DAC或ADC,触发输出的范围比基本定时器更广
右边为输出比较电路,总共有四个通道,分别对应CH1到CH4的引脚,可以用于输出PWM波形,驱动电机;左边为输入捕获电路,也有四个通道,对应也是CH1到CH4的引脚,可以用于测输入方波的频率;中间这个寄存器是捕获/比较寄存器,为输入捕获电路和输出比较电路共用,因为输入捕获和输出比较不能同时使用,所以寄存器是共用的,引脚也是共用的
高级定时器
相较于通用定时器,不同处:
申请中断的地方,增加一个重复次数计数器,可以实现每隔几个计数周期,才发生一次更新事件和更新中断,相当于对输出的更新信号又做了一次分频
DTG(死区生成电路),右边的输出引脚由原来的一个,变为了两个互补的输出,可以输出一对互补的PWM波,这些电路是为了驱动三相无刷电机,因为三相无刷电机一般需要三个桥臂,每个桥臂需要两个大功率开关管来控制,所以这里输出PWM引脚的前三路就变为了互补输出。
为了防止互补输出的PWM驱动桥臂时,在开关切换的瞬间,由于器件不理想,造成短暂直通现象,所以前面就加上了死区生成电路,在开关切换的瞬间,产生一定时长的死区,让桥臂的上下管全都关断,防止直通现象。
刹车输入功能:为了给电机驱动提供安全保障,如果外部引脚BKIN产生了刹车信号,或者内部时钟失效,产生了故障,那么控制电路就会自动切断电机的输出,防止意外的发生
定时中断基本结构
中断信号会现在状态寄存器里置一个中断标志位,这个标志位会通过中断输出控制,到NVIC申请中断
定时器有很多部分需要申请中断,如更新中断,触发信号,输入捕获和输出比较,这些中断都需要经过中断输出控制(中断输出的允许位)
预分频器时序
CK_PSC,预分频器的输入时钟
CNT_EN,计数器使能,高电平计数器正常运行,低电平计数器停止
CK_CNT,计数器时钟,既是预分频器的时钟输出,也是计数器的时钟输入
图中,刚开始,计数器未使能,计数器时钟不运行,使能后,前半段预分频器系数为1,计数器的时钟等于预分频器前的时钟,后半段,预分频器的系数变为2,计数器时钟就变为预分频器前时钟的一半了。
在计时器时钟的驱动下,下面的计数器寄存器也跟随时钟的上升沿不断自增,在中间FC位置之后,计数值变为0,ARR自动重装值就是FC,同时,下面产生一个更新事件。
预分频器缓冲机制:
预分频寄存器实际有两个,一是预分频控制寄存器,供我们读写用,并不直接决定分频系数,,二是缓冲寄存器(影子寄存器),真正起作用。当我在计数记到一半时改变了分频值,这个变化不会立刻生效,而是等到本次计数周期结束时,预分频计数器的值才会被传递到缓冲寄存器里去,才会生效。
预分频器内部实际上也是靠计数分频,预分频值为0时,计数器就一直为0,直接输出原频率;当预分频器为1时,计数器就0、1、0、1这样计数,在回到0的时候输出一个脉冲,这样输出频率就是输入频率的二分频。
计数器计数频率:CK_CNT = CK_PSC / (PSC + 1)
计数器时序
内部时钟分频因子为2,即分频系数为2
CK_INT,内部时钟72MHz
计数器在每个上升沿自增,增到0036,发生溢出,下一个上升沿,计数器清零,产生一个更新事件脉冲,还会置一个更新中断标志位UIF,这个标志位只要置1,就会申请中断,然后中断响应后,需要在中断程序中手动清零
计数器溢出频率:CK_CNT_OV = CK_CNT / (ARR + 1)
= CK_PSC / (PSC + 1) / (ARR + 1)
ARR+1?:因为计数器的计数周期是 0 → ARR,总共经历了 (ARR + 1) 个时钟脉冲
在图中,带有黑色阴影的寄存器都具有影子寄存器这样的缓冲机制,比如,预分频器,自动重装寄存器,捕获比较寄存器,这个缓冲寄存器可以自己设置是否使用
计时器无预装时序(没有缓冲寄存器)
计数器正在自增计数,突然更改自动重装寄存器的值,由FF改为36,故,计数器寄存器自增到36时,直接更新,开启下一轮计数
计时器有预装时序
计数器正在自增计数,突然更改自动重装寄存器的值,由F5改为36,故,计数器寄存器自增到F5时,才产生更新事件,同时要更改的36才被传递到影子寄存器。
引入影子寄存器目的实际上是为了同步,让值的变化和更新事件同步发生,防止在运行途中更改造成错误。图中,更改自动重装寄存器时,计数器已经增到了F1,已经超过了36,如果不使用影子寄存器,F1只能一直增加,一直加到FFFF,再回到0,再加到36,才能产生更新
通过设置ARPE位,可以选择是否使用预装功能
RCC时钟树
时钟树,STM32中用来产生和配置时钟,并把配置好的时钟发送到各个外设的系统,时钟是所有外设运行的基础,所以时钟也是最先需要配置的东西,程序主函数之前还会执行一个SystemInit函数,这个函数就是用来配置时钟树的
左边是时钟的产生电路,右边是时钟的分配电路,中间SYSCLK就是系统时钟72MHz
在时钟产生电路,有四个震荡源,分别为,内部8MHz高速RC振荡器(8 MHz HSI RC),外部4-16Hz高速石英晶体振荡器(4-16 MHz HSE OSE),也就是晶振,一般接8MHz,外部32.768KHz低速晶振(LSE OSC 32.768 KHz),一般是给RTC提供时钟,内部40KHz低速RC振荡器(LSI OSC 40 KHz),可以给看门狗提供时钟。
前两个高速晶振,是用来提供系统时钟的,AHB,APB1,APB2的时钟都是来源于这两个高速晶振,内部和外部的8MHz的晶振,外部的石英振荡器比内部的RC振荡器更加稳定,一般用外部晶振
ST配置过程:
首先会启动内部时钟,选择内部8MHz为系统时钟,暂时以内部8MHz的时钟运行,然后再启动外部时钟,配置外部时钟走上一路,进入PLL锁相环进行倍频,8MHz倍频9倍,得到72HMz,等到锁相环输出稳定后,选择锁相环输出为系统时钟
外部晶振出问题——程序时钟慢了大概十倍
CSS(时钟安全系统),负责切换时钟,可以监测外部时钟运行状态,一旦外部时钟失效,就会自动把外部时钟切换回内部时钟,保证系统时钟运行,防止程序卡死造成事故。
在高级定时器的刹车输入,一旦CSS检测到外部时钟失效,就会通过或门,立刻反映到输出比较,让输出控制的点击立刻停止,防止意外
在分配电路,首先系统时钟72MHz进入AHB总线,AHB总线有个预分频器,在SystemInit里配置的分配系数为1,那么AHB时钟就是72MHz,然后进入APB1总线,这里配置的分配系数为2,故APB1总线的时钟为72MHz/2 = 36MHz
注:本文为b站江协课程,为笔记