STM32的定时器功能众多,拥有基本定时功能,输出比较功能(如产生PWM波等),输入捕获(测量方波信号),读取正交编码器的波形。
1.中断原理
TIM定时器的基本功能是对输入的时钟进行计数,并在计数值达到设定值时触发中断(如主频一般是72MHZ,那么计数值设定为72,就是每1US触发一次中断;计数值设定为72000,就是每1MS触发一次中断。)
STM32定时器拥有16位计数器,预分频器,自动重装寄存器组成的时基单元,在72MHZ计数钟下可以实现最大59.65的定时。TIM不仅具备基本的定时中断功能,而且还包含内外时钟源选择,输入捕获,主从触发模式,输出比较,编码器接口等多种功能,并且分为高级定时器,通用定时器,基本定时器三种类型。
内部时钟(CK_CNT):一般就是系统的主频72MHz,通向时基单元的输入。
时基单元:16位预分频器 + 16位计数器 + 16位自动重装载寄存器。
预分频器:对输入的72MHz时钟进行预分频,寄存器内存储的值是实际的分频系数减一。写0就是不分频,写1就是2分频,写2就是3分频……
计数器:对预分频后的计数时钟进行计数,每遇到上升沿就加一。
自动重装载寄存器:存储计数的最大值,到达此值后触发中断并清零计数器。1。通用定时器框图
- 时基单元:中间的PSC预分频器、自动重装载寄存器、CNT计数器。通用定时器和高级定时器新增两个功能——“向下计数模式”、“中央计数模式”。
- 向上计数模式【常用】:从0开始累加,到自动重装载值触发中断。
- 向下计数模式:从自动重装载值递减,到0触发中断。
- 中央对齐模式:从0开始累加,到自动重装载值触发中断,然后递减,到0再次触发中断。常用于电机控制的SVPWM算法中。
- 内外时钟源选择和主从触发模式结构:上面的一大块。下面介绍各种各样的内外时钟源:
- 内部时钟CK_INT【常用】:通常为72MHz,基本定时器只能选择CK_INT,通用定时器和高级定时器则新增了下面的时钟源。
- 外部TIMx_ETR【常用】:引脚的位置可以参考引脚定义表,如stm32f103c8t6的PA0引脚复用了TIM2_CH1_ETR等。外部输入了方波时钟,然后通过极性选择、滤波等电路进行整形,然后兵分两路,一路ETRF进入触发控制器,紧跟着就可以选择成为时基单元的时钟(外部时钟模式2);一路进入选择器等待成为TRGI。
- TRGI主要用作触发输入来使用,可以触发定时器的从模式,本小节仅用做外部时钟(外部时钟模式1),其他功能后续再讲。
- 外部ITR信号:包括ITR0~ITR4(引脚定义见参考手册“表78 TIMx内部触发连接”),来自其他定时器,实现了定时器的级联。这个ITR信号从上一级定时器的主模式TRGO引脚来(图片右上方)。
- 外部TI1F-ED:来自于输入捕获单元的TIMx_CH1引脚,后缀“ED”意为边沿,也就是说该路时钟的上升沿和下降沿均有效,也就是CH1引脚的边沿。
- 外部TI1FP1:来自CH1引脚时钟。
- 外部TI2FP2:来自CH2引脚时钟。
- 编码器接口:可以读取正交编码器的输出波形,后续会再介绍。
- TRGO引脚:定时器的主模式输出,可以将内部的一些事件映射到TRGO上,相比基本定时器这些事件的范围显然更广。
- 注:最后三种外部时钟用于输入捕获和测频率,后续介绍。
- 输出比较电路:下面右侧的一大堆,总共有4个通道,可以用于输出PWM波形驱动电机。
- 输入捕获电路:下面左侧的一大推,也是有4个通道,可以用于测量输入方波的频率。
- 注:输入捕获电路和输出比较电路不能同时使用,所以共用中间的“捕获/比较寄存器”以及输入/输出的引脚。后续再介绍。
2.高级定时器
重复次数计数器:可以实现每个几个计数周期,才发生一次更新事件和更新中断,相当于自带一级的定时器级联。
DTG(Dead Time Generate):死区生成电路。将输出引脚由原来的一个变为两个互补的输出,可以输出一对互补的有死区的PWM波(防止出现短暂的直通现象),可以驱动三相无刷电机(如四轴飞行器、电动车后轮、电钻等)。
BRK刹车输入:为了给电机驱动提供安全保障,如果外部引脚BKIN(Break IN)产生了刹车信号或者内部时钟失效,这个电路就会自动切断电机的输出,防止意外的发生。
定时中断基本结构
时基单元:中间的粉色部分。
运行控制:控制寄存器的一些位,如启动停止、向上或向下计数等,操作这些寄存器就可以控制时基单元的运行了。
内部时钟模式、外部时钟模式2、外部时钟模式1:外部时钟源选择。这个选择器的输出就是为时基单元提供时钟。
编码器模式:编码器独有的模式,一般用不到。
中断申请控制:由于定时器内部有很多地方要申请中断,“中断申请控制”就用来使能控制这些中断是否使能。比如,中断信号会先在状态寄存器里置一个中断标志位,这个标志位会通过中断输出控制,到NVIC申请中断。
CK_PSC:预分频器的输入时钟,选择内部时钟源就是72MHz。
CNT_EN:计数器使能。高电平计数器正常运行,低电平计数器停止。
CK_CNT:计数器时钟,既是预分频器的时钟输出,也是计数器的时钟输入。
计数器寄存器:对CK_CNT进行自增计数,到达自动重装载值清零。
更新事件:计数器寄存器到达自动重装载值时产生一个脉冲。
下面三行时序体现了预分频计数器的一种缓冲机制:
预分频控制寄存器:供用户读写使用,实时响应用户控制,但并不直接决定分频系数。
预分频缓冲器:也称为影子寄存器,真正起分频作用的寄存器。只有在更新事件到达时,才从“预分频控制寄存器”更新预分频参数。以确保更新事件的稳定性。
预分频计数器:按照预分频参数进行计数,以产生对应的CK_CNT脉冲。
正常的计数器时序没啥好说的,就是根据CK_CNT计数,到达自动重装载值产生中断,所以只需看一下更新自动重装载值的过程:
无预装时序(禁用缓冲寄存器):有溢出问题。若将自动重装载值变小,且此时计数器寄存器已经超过这个新的重装载值,那么计数器寄存器就会一直计数到FFFF才清零。这可能会造成一些问题。
有预装时序(启用缓冲寄存器):比较稳定。只有更新事件来临时才更新自动重装载值。
时钟是所有外设的基础,所以是需要最先配置的。ST公司写好了SystemInit函数来配置时钟树,下面具体介绍:
左侧是时钟产生电路,右侧时钟分配电路,中间的SYSCLK就是72MHz的系统时钟。
时钟产生电路:
四个振荡源:
内部的8MHz高速RC振荡器。
外部的4-16MHz高速石英晶体振荡器:一般8MHz,相比于内部的RC高速振荡器更加稳定。
外部的32.768kHz低速晶振:一般给RTC提供时钟。
内部的40kHz低速RC振荡器:给看门狗提供时钟。
上面的两个高速晶振用于给系统提供时钟,如AGB、APB1、APB2的时钟。SystemInit函数配置时钟的过程:首先启动内部8MHz时钟为系统时钟,然后配置外部8MHz时钟到PLLMUL模块进行9倍频到72MHz,等到这个72MHz时钟稳定后,再将其作为系统时钟。于是就实现了系统时钟从8MHz切换到72MHz。
CSS:监测外部时钟的运行状态,一旦外部时钟失效,就会自动把外部时钟切换成内部时钟,保障系统时钟的运行,防止程序卡死造成事故。如果外部晶振出问题,那么就会导致程序的时钟变为8MHz,也就是比预期的时钟慢了9倍。
时钟分配电路
AHB总线:有预分频器,SysytemInit配置分频系数为1,于是AHB时钟输出就是72MHz。
APB1总线:SysytemInit配置分频系数为2,于是APB1时钟输出就是36MHz。
APB2总线:SysytemInit配置分频系数为1,于是APB2时钟输出就是72MHz。
外设时钟使能:就是库函数RCC_APB2PeriphClockCmd开启的地方,可以控制相应的外设时钟开启。
定时器的时钟:从图中可以看出,按照SystemInit的默认配置,所有的定时器时钟都是72MHz。