定时触发中断:定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断。
- STM32的基准时钟一般都是72MHz,对72MHz计72个数就是1MHz,也就是1us的时间。记72000个数就是1kHz,就是1ms。
16位计数器、预分频器、自动重装寄存器的时基单元,在72MHz计数时钟下可以实现最大59.65s的定时。
- 计数器就是用来执行计数定时的寄存器,每来一个时钟,计数器加1。
- 预分频器对计数器的时钟进行分频。
- 自动重载寄存器是计数的目标值,计多少个时钟申请中断。
- 72MHz/(65536×65536)≈1.6764Hz,取倒数就是59.65s。
- stm32也支持级联。
不仅具备基本的定时中断功能,而且还包含内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等多种功能。
定时器类型
注:不同型号的芯片定时器的数量不一样,使用前要查看是否有。
基本定时器
红框部分为时基单元。
预分频器连的就是基准时钟输入,对输入的时钟信号进行分频,写0就是不分频,写1就是二分频输入72MHz则输出72/2=36MHz。实际分频系数=预分频器的值+1
计数器对预分频后的计数时钟进行计数,当达到一个值后又回到0开始自增。
自动重装寄存器存入的是计数目标值。计数值不断自增,自动重装载是固定的目标,当计数值等于自动重装值时,就会触发中断。这种中断叫“更新中断”(下图向上的箭头),通往NVIC。向下的箭头为更新事件,更新事件不会触发中断但会触发内部其他电路的工作。
主模式触发DAC
在用DAC输出一段波形时需要每隔一段时间来触发一次DAC,让它输出下一个电压点。就需要设置定时器中断,然后在中断程序里设置DAC转换。但这样每隔一段时间就会导致主程序频繁被中断,影响主程序的运行和其他中断的响应。
主模式触发把更新事件映射到TRGO,然后TRGO直接接到DAC引脚就能触发DAC转换。
通用定时器
中间时基单元与基本定时器差不多。但计数模式有三种:向上计数(自增)、向下计数(自减)、中央对齐(先增后减)
时钟源选择
对于基本定时器只能选择内部时钟源,而通用定时器有四种选择。
外部时钟模式1
TIMx_ETR引脚上的外部时钟。关于ETR引脚位置可以在引脚定义图找,下面这个就对应PA0。
TRGI主要是作为触发输入来使用的,触发定时器的从模式。这里主要看这个触发输入作为外部时钟使用的情况。当TRGI作为外部时钟输入时,所连通的一路叫“外部时钟模式1”。
通过这一路的信号可以是ETR引脚的信号和ITR信号(来自其他定时器,可实现级联)
而TIM与对应的ITR引脚对应如下:
如上,第一行,TIM2的ITR0接在了TIM1的TRGO上。
外部时钟模式2
这一路最简单最直接。
先接好ETR引脚的外部时钟的输入,然后通过极性选择、边沿检测、预分频、输入滤波。
滤波后的信号,兵分两路,上一路ETRF进入触发控制器,然后作为时基单元的时钟,就是“外部时钟模式2”。下一路通过TRGI,就是外部时钟模式1。
还有其他时钟如下:
CH1引脚的边沿、CH1引脚(TIMx_CH1的TI2FP1)和CH2引脚(TIMx_CH2的TI2FP2)
左边是输入捕获,右边是输出比较。都是CH1-CH4引脚,因此不能同时使用。
高级定时器
高级定时器拥有通用定时器全部功能,并额外具有重复计数器、死区生成、互补输出、刹车输入等功能。
- 重复计数器。可以每隔几个计数周期才发生一次更新事件和更新中断。原来每个都会。
- 死区生成。右侧可以输出互补的PWM波,可以驱动三项无刷电机。而死区生成电路用于防止开关切换时的直通现象。
- 刹车输入。如果外部引脚BKIN产生了刹车信号,或者内部时钟失效产生了故障,控制电路就会自动切断电机的输出,防止意外的发生。
定时器时序
- 预分配缓冲寄存器(影子寄存器),防止分频改变,导致一个计数周期内前后频率不一致。
- 计数器技术频率:CK_CNT = CK_PSC / (PSC + 1)
- 计数器溢出频率:CK_CNT_OV = CK_CNT / (ARR + 1) = CK_PSC / (PSC + 1) / (ARR + 1)
定时程序
初始化定时器
把上图,从GPIO到NVIC通道打通。
先看要用到的TIM库函数:
1. RCC开启时钟
这里选择TIM2,而TIM2是APB1的。
2. 选择时基单元的时钟源
根据上述时钟模式选择需要的,这里选择了内部时钟。
3. 配置时基单元-TimeBaseInit()
要定一个1s的时间,定时频率 = 72M/(PSC+1)/(ARR+1) = 1Hz。
那可以PSC = 7200-1,ARR = 10000-1。
4. 配置输出中断控制-TIM_ITConfig()
5. 配置NVIC-NVIC_Init()
6. 运行控制-TIM_Cmd()
中断函数
但是从OLED显示看出num不是从0开始而是从一开始。
在TIM_TimeBaseInit()函数的末尾,会立即生成一个更新事件,重新加载预分频器和重复计数器的值。更新事件同时触发更新中断,将更新中断标志位置位。为了避免在初始化后立即进入更新中断函数,可以在初始化后手动清除更新中断标志位。