TIM简介
TIM(Timer)定时器
定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断
16位计数器、预分频器、自动重装寄存器的时基单元,在72MHz计数时钟下可以实现最大59.65s的定时(STM32中,定时器的基准时钟一般是主频72MHz,如果对72MHz计72个数,那就是1MHz也就是1微秒时间,如果计72000个数,那就是1KHz也就是1ms时间,如果预分频器设置最大,自动重装也设置最大,72M/65536/65536得的是中断频率,再取倒数,就是59.65秒多)
不仅具备基本的定时中断功能,而且还包含内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等多种功能
根据复杂度和应用场景分为了高级定时器、通用定时器、基本定时器三种类型

STM32F103C8T6定时器资源:TIM1、TIM2、TIM3、TIM4

下面简单介绍一下主模式触发DAC,后面会细讲:
我们在使用DAC时,可能会用DAC输出一段波形,那就需要每隔一段时间来触发一次DAC,让它输出下一个电压点,如果用正常的思路来实现就是先设置一个定时器产生中断,每隔一段时间在中断程序中调用代码手动触发一次DAC转换,然后DAC输出,这样会使主程序处于频繁中断的状态,这会影响主程序的运行和其他中断的响应。所以定时器就设计了一个主模式,使用这个主模式可以把定时器的更新事件映射到触发输出TRGO(Trigger Out)的位置,然后TRGO直接接到DAC的触发转换引脚上,这样定时器的更新就不需要通过中断来触发DAC转换了,仅需要把更新事件通过主模式映射到TRGO,然后TRGO就会直接去触发DAC了。整个过程不需要软件参与,实现了硬件自动化,这就是主模式的作用。

通用定时器

高级定时器

TIM定时中断
定时中断基本结构

时序图
现在看几个时序图,研究一下时基单元运行的一些细节问题。
预分频器时序

计数器计数频率:CK_CNT = CK_PSC / (PSC + 1)
计数器时序

计数器溢出频率:CK_CNT_OV = CK_CNT / (ARR + 1)=CK_PSC / (PSC + 1) / (ARR + 1)
用72MHz/(PSC+1)/(ARR+1)就能得到溢出频率,如果计算溢出时间,取个倒数就好了。计数器也是有缓冲机制的。结构体里有阴影的寄存器都是有影子寄存器这样的缓存机制的。并且这个缓存寄存器用不用是可以自己设置的。

计数器无预装时序

计数器有预装时序

RCC时钟树
STM32的RCC时钟树较为复杂,它主要由振荡源、锁相环等产生一定频率的信号,作为系统时钟、看门狗时钟等,同时将系统时钟分配给各个外设,驱动各外设工作。是STM32中用来产生和配置时钟,并且把配置好的时钟发送到各个外设的系统。
首先看时钟产生电路:

SystemInit函数里,ST配置时钟的过程:

再看看时钟分配电路:

定时器定时中断应用
在System文件夹新建Timer .c和Timer.h文件。在Timer.c写Timer_Init()函数初始化定时器。
初始化步骤根据定时中断基本结构来完成:

整个模块配置完成后,我们还需要使能一下计数器,要不然计数器是不会运行的,当定时器使能后计数器就会开始计数了,当计数器更新时,触发中断。最后我们在写一个定时器的中断函数,这样这个中断函数每隔一段时间就能自动执行一次了。
先介绍几个TIM的库函数:
/*
* 将TIMx外设寄存器初始化为其默认重置值。
* 参数 TIMx:其中x为1 ~ 17,表示选择TIM外设。
* 返回值:无
*/
void TIM_DeInit(TIM_TypeDef* TIMx);时基单元:
/*
* 根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx时基单元外设。
* 参数1 TIMx:其中x为1 ~ 17,表示选择TIM外设。
* 参数2 TIM_TimeBaseInitStruct:指向TIM_TimeBaseInitTypeDef的指针,包含指定的TIM外设的配置信息。
* 返回值:无
*/
void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);/*
* 用默认值填充每个TIM_TimeBaseInitStruct成员。
* 参数 TIM_TimeBaseInitStruct:指向将被初始化的TIM_TimeBaseInitTypeDef的指针。
* 返回值:无
*/
void TIM_TimeBaseStructInit(TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);运行控制:
/*
* 启用或禁用指定的TIM外设。
* 参数1 TIMx:其中x为1 ~ 17,表示选择TIMx外设。
* 参数2 NewState: TIMx外设的新状态。取值为:ENABLE或DISABLE。
* 返回值:无
*/
void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);中断输出控制:
/*
* 启用或禁用指定的TIM中断。
* 参数1 TIMx:其中x为1 ~ 17,表示选择TIMx外设。
* 参数2 TIM_IT:启用或禁用的TIM中断源。
* 参数3 NewState: TIM中断的新状态。取值为:ENABLE或DISABLE。
* 返回值:无
*/
void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);时基单元的时钟选择部分(可选RCC内部时钟、ETR外部时钟、ITRx其他定时器、TIx捕获通道):
/*
* 配置TIMx内部时钟
* 参数 TIMx:选择TIM外设,其中x可以是1、2、3、4、5、8、9、12或15。
* 返回值:无
*/
void TIM_InternalClockConfig(TIM_TypeDef* TIMx);
/*
* 配置TIMx内部触发器为外部时钟(选择ITRx其他定时器的时钟)
* 参数1 TIMx:用来选择TIM外设,其中x可以是1、2、3、4、5、9、12或15。
* 参数2 TIM_ITRSource:触发源(选择要接入哪个其他定时器)。
* 返回值:无
*/
void TIM_ITRxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);
/*
* 选择TIx捕获通道的时钟
* 参数1 TIMx:用来选择TIM外设,其中x可以是1、2、3、4、5、9、12或15。
* 参数2 TIM_TIxExternalCLKSource:触发源。(选择TIx具体的某个引脚)
* 参数3 TIM_ICPolarity: TIx极性。
* 参数4 ICFilter:滤波器。取值范围为0x0 ~ 0xF。
* 返回值:无
*/
void TIM_TIxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_TIxExternalCLKSource,
uint16_t TIM_ICPolarity, uint16_t ICFilter);
/*
* 配置外部时钟模式1(选择ETR通过外部时钟模式1输入的时钟)
* 参数1 TIMx:选择TIM外设,其中x可以为1、2、3、4、5或8。
* 参数2 tim_exttrgprecaler:外部触发器预分频器。(对ETR外部时钟再提前做一个分频)
* 参数3 TIM_ExtTRGPolarity:外部触发极性。
* 参数4 ExtTRGFilter:外部触发滤波器。取值范围为0x00 ~ 0x0F
* 返回值:无
*/
void TIM_ETRClockMode1Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,uint16_t ExtTRGFilter);
/*
* 配置外部时钟模式2(选择ETR通过外部时钟模式2输入的时钟)
* 参数1 TIMx:选择TIM外设,其中x可以为1、2、3、4、5或8。
* 参数2 tim_exttrgprecaler:外部触发器预分频器。(对ETR外部时钟再提前做一个分频)
* 参数3 TIM_ExtTRGPolarity:外部触发极性。
* 参数4 ExtTRGFilter:外部触发滤波器。取值范围为0x00 ~ 0x0F
* 返回值:无
*/
void TIM_ETRClockMode2Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler,
uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter)
/*
* 单独配置TIMx外部触发器(ETR)的预分频器、极性、滤波器
* TIMx:选择TIM外设,其中x可以为1、2、3、4、5或8。
* tim_exttrgprecaler:外部触发器预分频器。
* TIM_ExtTRGPolarity:外部触发极性。
* ExtTRGFilter:外部触发滤波器。取值范围为0x00 ~ 0x0F
* 返回值:无
*/
void TIM_ETRConfig(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,uint16_t ExtTRGFilter);更改关键参数的函数:
/*
* 配置TIMx预分频器。(单独写预分频器值)
* 参数1 TIMx:其中x为1 ~ 17,表示选择TIM外设。
* 参数2 precaler:预分频器寄存器的值
* 参数3 TIM_PSCReloadMode: 写入的模式(结合缓冲机制)。该参数可以是以下值之一:
* TIM_PSCReloadMode_Update:在更新事件中加载预分频值。
* TIM_PSCReloadMode_Immediate:立即加载预分频值。
* 返回值:无
*/
void TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode);
/*
* 指定要使用的TIMx计数器模式。
* 参数1 TIMx:选择TIM外设,其中x可以为1、2、3、4、5或8。
* 参数2 TIM_CounterMode:要使用的计数器模式。(向上、向下、中心对齐)
* 返回值:无
*/
void TIM_CounterModeConfig(TIM_TypeDef* TIMx, uint16_t TIM_CounterMode);
/*
* 自动重装器预装功能配置。
* 参数1 TIMx:其中x为1 ~ 17,表示选择TIM外设。
* 参数2 NewState: TIMx外设预装寄存器的新状态。取值为:ENABLE或DISABLE
* 返回值:无
*/
void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);
/*
* 设置TIMx计数器寄存器值
* 参数1 TIMx:其中x为1 ~ 17,表示选择TIM外设。
* 参数2 Counter:计数器寄存器的新值。
* 返回值:无
*/
void TIM_SetCounter(TIM_TypeDef* TIMx, uint16_t Counter);
/*
* 设置TIMx自动重装寄存器值
* 参数1 TIMx:其中x为1 ~ 17,表示选择TIM外设。
* 参数2 Autoreload:自动重装寄存器的新值。
* 返回值:无
*/
void TIM_SetAutoreload(TIM_TypeDef* TIMx, uint16_t Autoreload);
/*
* 获取TIMx计数器值。
* 参数 TIMx:其中x为1 ~ 17,表示选择TIM外设。
* 返回值:计数器的值。
*/
uint16_t TIM_GetCounter(TIM_TypeDef* TIMx);
/*
* 获取TIMx预分频器值。
* 参数 TIMx:其中x为1 ~ 17,表示选择TIM外设。
* 返回值:预分频器的值
*/
uint16_t TIM_GetPrescaler(TIM_TypeDef* TIMx);接下来我们按步骤配置一下定时器吧!以TIM2通用定时器为例:
