定时器四部分讲解内容,本文是第一部分
TIM简介
基本定时器
时基单元:预分频器、计数器、自动重装载寄存器
预分频器之前,连接的就是基准计数时钟的输入,由于基本定时器只能选择内部时钟,所以可以认为这根线直接到输入端这里,也就是内部时钟CK_INT,内部时钟来源是RCC_TIMxCLK,频率值一般都是系统的主频72MHZ。
如果预分频器写1,那就是2分频,输出频率=输入频率/2=36MHZ
如果预分频器写2,那就是3分频,输出频率=输入频率/3=24MHZ
预分频器的值和实际的分频系数相差1,即实际分频系数=预分频器的值+1,这个预分频器的值是16位,所以最大值可以写65535,也就是65536分频。预分频器就是对输入的基准频率提前进行一个分频的操作。
计数时钟每来一个上升沿,计数器的值就加1,计数器是16位,所以里面的值可以从0一直加到65535.如果再加的话,计数器就会回到0重新开始。所以计数器的值在计时过程中会不断自增运行,当自增运行到目标值时,产生中断,那就完成了定时的任务。
自动重装载寄存器:存储目标值的寄存器。在运行的过程中,计数值不断自增,自动重装值是固定的目标,当计数值等于自动重装值时,也就是计时时间到了。那他会产生一个中断信号,并且清零计数器。计数器自动开始下一次的计数计时。
UI折线箭头代表这里会产生中断信号,像这种计数值等于自动重装值产生的中断,称为更新中断,这个更新中断之后,就会通往NVIC,我们再配置好NVIC的定时器通道,那么定时器的更新中断就能够得到CPU的响应。
U向下箭头表示更新事件,更新事件不会触发中断,但可以触发内部其他电路的工作。
主从触发
它能让内部的硬件在不受程序的控制下实现自动运行。主模式触发作用:
在我们使用DAC时,可能会用DAC输出一段波形,那就需要每隔一段时间来触发一次DAC,让它输出下一个电压点。正常思路,先设置一个定时器产生中断,每隔一段时间在中断程序中调用代码手动触发一次DAC转换,然后DAC输出,缺点:这样会使主程序处于频繁被中断的状态,这回影响主程序的运行和其他中断的响应。
所以定时器就设计了一个主模式,使用主模式可以把这个定时器的更新事件映射到这个触发输出TRGO(trigger out)的位置,然后TRGO直接接到DAC的触发转换引脚上。这样,定时器的更新就不需要再通过触发中断来触发DAC转换。无需软件参与,实现硬件自动化。
通用定时器
通用定时器和高级定时器支持3种计数模式,向上计数、向下计数和中央对齐这三种模式。
右边:输出比较电路,总共有4个通道,可以用于输出PWM波形,驱动电机
左边:输入捕获电路,总共四个通道,可以用于测量输入方波的频率、占空比等
中间寄存器:捕获/比较寄存器,是输入捕获和输出比较电路公用的,因为输入捕获和输出比较不能同时使用,因此寄存器机器引脚是公用的。
对于基本定时器而言,定时只能选择内部时钟,也就是系统频率72MHZ,
对于通用定时器而言,定时还可以选择外部时钟,第一个外部时钟来自TIMx_ETR引脚的外部时钟
TIMx_ETR是一个定时器的输入端口,可以用来接收外部的时钟信号。在其引脚接上一个外部方波时钟。然后配置一下内部的极性选择、边沿检测和预分频器电路,再配置输入滤波电路,这些电路可以对外部时钟进行一定的整型,因为外部引脚时钟,难免有毛刺,这些电路可对输入的波形进行滤波。
外部时钟模式1的输入可以是ETR引脚,其他定时器,CH1引脚的边沿、CH1引脚和CH2引脚。
一般情况下,外部时钟通过ETR引脚即可
对于时钟输入而言,最常用的还是内部的72MHZ的时钟,如果要使用外部时钟,首选ETR引脚外部时钟模式2的输入。,这一路最简单最直接
定时器的编码器接口,可以读取正交编码器的输出波形
高级定时器
通用定时器与高级定时器的区别 :
第一个:申请中断的地方,增加了一个重复次数计数器,有了这个计数器之后,就可以实现每隔几个计数周期,才发生一次更新事件和更新中断。原来的结构是每个计数周期完成后都会发生更新。相当于对输出的更新信号又做了一次分频。
以下是高级定时器对输出比较模块的升级
DTG是死区生成电路,右边的输出引脚由原来的一个变为两个互补的输出,可以输出一对互补的PWM波。为了驱动三相无刷电机
刹车输入:给电机驱动提供安全保障,如果外部引脚BKIN产生了刹车信号,或者内部时钟失效,产生了故障,那么控制电路就会自动切断电机的输出,防止以外的发生。
定时中断基本结构图
定时中断和内外时钟源选择
运行控制:就是控制寄存器的一些位,比如启动停止、向上或向下计数等,操作这些寄存器,就能控制时基单元的运行。
左边:为时基单元提供时钟的部分.
第一个定时中断使用RCC的内部时钟
第二个定时器外部时钟就是用外部时钟模式2
右边:计时时间到,产生更新中断后信号的去向(如果高级定时器,还会有一个重复计数器)
中断信号会先在状态寄存器里置一个中断标志位,这个标志位会通过中断输出控制,到NVIC申请中断。中断输出控制就是一个中断输出的允许位,如果需要某个中断,就记得允许一下。
时序
RCC时钟树
RCC时钟树是stm32用来产生和配置时钟,并且把配置好的时钟发送到各个外设的系统,时钟是所有外设运行的基础,所以时钟是最先需要配置的东西。
代码部分
程序现象
1、使用定时中断的功能,定时器使用内部时钟定了1秒的时间,每隔1秒申请一下中断,然后在中断函数里执行Num++,最后在OLED上显示Num
2、定时器外部时钟,使用外部时钟驱动定时器,在定时器指定的外部引脚上,输入一个方波信号,来提供定时器计数的时钟,目前用对射式红外传感器来手动模拟一个外部时钟,用挡光片一次遮挡、移开、遮挡、移开提供一个方波。OLED上的CNT就是定时器中计数器的值,每遮挡移开一次,计数器加1,然后计数器计到9后自动清零。同时申请中断,执行Num++。
定时中断
步骤
第一步:RCC开启时钟,定时器的基准时钟和整个外设的工作时钟就都会同时打开
第二步: 选择时基单元的时钟源,对于定时中断,我们选择内部时钟源
第三步:配置时基单元,包括预分频器、自动重装器、计数模式等等
第四步:配置输出中断控制,允许更新中断输出到NVIC
第五步:配置NVIC,在NVIC中打开定时器中断的通道,并分配一个优先级
第六步:运行控制
第七步:使能计数器
Timer.h
cpp
#ifndef __TIMER_H
#define __TIMER_H
void Timer_Init(void);
#endif /*__TIMER_H*/
外部时钟
Timer.h
cpp
#ifndef __TIMER_H
#define __TIMER_H
void Timer_Init(void);
uint16_t Timer_GetCounter(void); //获取计数值
#endif /*__TIMER_H*/