TIM简介

TIM(Timer)定时器
定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断。定时器本质上就是一个计数器。

STM32拥有
16位计数器(用来执行计数定时的一个寄存器,每来一个时钟,计数器加1)、
预分频器(对计数器的时钟进行分频,让计数器更加灵活)、
自动重装寄存器的时基单元(计数的目标值,就是我想要计多少个时钟申请中断),
上述三个寄存器构成了定时器最核心的部分,称为时基单元,且都是16位的寄存器。
在72MHz计数时钟下可以实现最大59.65s的定时(预分频器和自动重装寄存器全都设置为最大)。

STM32定时器不仅具备基本的定时中断功能,而且还包含内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等多种功能
根据复杂度和应用场景分为了高级定时器、通用定时器、基本定时器三种类型

定时器的类型

在这里插入图片描述
STM32F103C8T6定时器资源:TIM1、TIM2、TIM3、TIM4

基本定时器

在这里插入图片描述
基本定时器可以完成定时中断、主模式触发DAC的功能。

定时中断

框图中下方三个就是最基本的计数计时电路,所以叫做时基单元。
预分频器前连接的就是基准计数时钟的输入,图中的RCC的TIMxCLK频率值一般都是系统的主频72MHz。
预分频器: 可以对输入的计数器时钟进行预分频,若输入的是72MHz,比如寄存器写 0 ,就是不分频或者说是 1 分频,输出的还是72MHz。如果寄存器写 1 ,就是 2 分频输出的就是36MHz。所以实际分频系数是寄存器的值加1。
计数器: 计数时钟每来一个上升沿,计数器的值就加1。当计数到了目标值就产生中断。
自动重装寄存器: 存的是计数器的目标,计数到了目标值产生中断,并且清零计数器。

图中向上的折线箭头代表会产生中断信号,像这种计数值等于重装载值的中断叫做“更新中断”,更新中断后就会通往NVIC,再配置好NVIC的定时器通道,定时器的更新中断就能得到CPU的响应了。

向下的折线箭头代表会产生一个事件,对应的叫做“更新事件”,更新事件不会触发中断,而是会触发其他电路。

主模式触发DAC

主从触发模式可以让内部的硬件再不受程序的控制下实现自动运行。
DAC可以通过更新中断来采集电压,但是这会占用CPU,使主程序处于频繁被中断的状态。这会影响主程序的运行和其他中断。
这个主模式可以把这个定时器的更新事件映射到上图上面那个触发输出TRGO(Trigger Out)的位置,TRGO直接接到DAC的触发转换引脚上,这样定时器就不需要再通过中断来触发DAC转换了。仅需要把更新事件通过主模式映射到TRGO,TRGO就会直接去触发DAC了。整个过程不需要软件的参与,实现了硬件的自动化,这就是主模式的作用。

通用定时器

在这里插入图片描述
通用定时器框图中间也是时基单元,但是不同于基本定时器向上计数,通用定时器和高级定时器还可以支持向下计数中央对齐模式
向下计数就是从重装值开始向下自减,减到0后回到重装值,同时申请中断。
中央对齐模式是向上计数,记到重装值申请中断,然后向下计数,到0再申请中断,如此循环。

框图上方是内外时钟源选择,基本定时器只能选择内部的72MHz的时钟,通用定时器可以选择外部时钟。第一个外部时钟来自TIMx_ETR引脚上的外部时钟。观察引脚定义表,
在这里插入图片描述TIM2_CH1_ETR意思就是TIM2的CH1和ETR引脚都复用到了这个位置,也就是PA0引脚上。
外部时钟模式2:
所以就可以在TIM2的 ETR 引脚,也就是PA0上接一个外部方波时钟,然后配置以下内部的极性选择,边沿检测预分频器电路,再配置一下输入滤波电路。这两块电路可以对外部时钟进行一定的整形,因为是外部引脚的时钟,所以难免会有毛刺,这些电路就可以对输入的波形进行滤波。同时也可以选择极性和预分频器。最后,滤波后的信号,兵分两路,上面一路ETRF进入触发控制器,然后就可以选择作为时基单元的时钟输出。这一路电路主要是选择外部时钟或者对ETR时钟进行计数。 这一路也叫做外部时钟模式2。
外部时钟模式1:
除了ETR引脚可以提供时钟外,下面还有一路可以提供时钟,就是TRGI(Trigger In),这一路主要用作触发输入使用,触发输入可以触发定时器的从模式。
我们也可以将TRGI当作外部时钟的输入来看,当它当作外部时钟来使用的时候,这一路就叫做“外部时钟模式1”。
这一路有哪些外部时钟呢,第一个就是 ETR引脚的信号,对于时钟输入而言,ETR当作时钟信号和上面说的是等价的,只是这一路会占用触发输入的通道。
第二个就是选择器的左边的 ITR信号。ITR信号左边的ITRx是来自其他定时器的。从右边可以看出TRGO可以通向其他定时器,通向其他定时器的时候就接到了其他定时器的ITRx。所以上面的ITR0 到 ITR3分别来自其他四个定时器的TRGO输出。
在这里插入图片描述
那么这些ITRx是哪些定时器接过来的呢?通过手册可以看出,TIM2的ITRx分别来自上面那些定时器。

通过这样的方式就可以实现定时器级联的功能。比如可以初始化TIM3,然后选择主模式,把他的更新事件映射到TRGO上,再初始化TIM2,选择ITR2,TIM2的ITR2来自TIM3的TRGO。然后后面再选择时钟为外部时钟模式1,这样TIM3的更新事件就可以驱动TIM2的时基单元,也就实现了定时器的级联。

继续向下看,第三个就是TI1F_ED,这个连接的是输入捕获单元的CH1引脚,也就是从TIMx_CH1引脚获得时钟,这里后缀加一个ED(Edge)就是边沿的意思,也就是通过这一路输入的时钟,上升沿和下降沿均有效。
最后这个时钟(TRGI)还能通过TI1FP1和TI2FP2获得,TI1FP1就是CH1的引脚的时钟,TI2FP2就是CH2引脚的时钟。

综上,外部时钟模式1的输入可以是

  • ETR引脚
  • 其他定时器
  • CH1引脚的边沿
  • CH1引脚和CH2引脚

框图右下方是输出比较电路,,总共四个通道,分别对应CH1到CH4的引脚,可以用于输出PWM波形,驱动电机,左下一块是输入捕获电路,也是四个通道,对应的也是CH1到CH4的引脚,可以用于测量方波的频率,中间的是捕获/比较寄存器,是输入捕获和输出比较电路共用的。因为输入捕获和输出比较不能同时使用,所以寄存器是共用的,引脚也是共用的。

高级定时器

在这里插入图片描述

高级定时器相比通用定时器大部分都没有变化,只有右边一小部分和下面变化了一些。
首先是时基单元申请中断的地方增加了一个重复次数计数器。这个计数器可以实现每隔几个计数周期才发生一次更新事件和更新中断。右下DTG(Dead Time Generate)是死区生成电路。右边的输出引脚由原来的一个变为了两个互补的输出,可以输出一对互补的PWM波,这些电路是为了驱动三相无刷电机的。第四路还是一个输出,因为三相无刷电机只需要三路就行了。
最下面是刹车输入的功能,这是为了给电机驱动提供安全保障的,如果外部引脚TIMx_BKIN(Break IN)产生了刹车信号,或者内部时钟失效产生了故障,控制电路就会自动切断电机的输出,防止意外的发生。

定时中断基本结构

在这里插入图片描述
图中运行控制就是控制寄存器的一些位,比如启动停止,向上或向下计数等等,操作这些寄存器就能控制时基单元了。下面的编码器模式是编码器独用的模式,普通的时钟用不到。
右边就是计时时间到产生中断后的去向。如果是高级定时器还会多一个重复计数器。
注意此时中断信号会先在状态寄存器里置一个中断标志位,图中没有画出,标志位会通过中断输出控制,到NVIC申请中断。
中断输出控制的存在是因为定时器模块会有很多地方都要申请中断,不仅更新会申请中断,还要许多信号都会申请中断
在这里插入图片描述
中断输出控制就是一个中断输出的允许位,需要某个中断就要允许一下。

预分频器时序

在这里插入图片描述
CNT_EN是计数器使能位,使能了才开始计数,所以可以看到低电平的时候,定时器时钟CK_CNT是没有波形的。图中也可以看出重装载值应该是FC,在那个时刻发生了更新事件,且寄存器变为0。CK_CNT既是预分频器的时钟输出,又是计数器的时钟输入

缓冲寄存器相当于影子寄存器,这才是真正起作用的寄存器,比如上面在某个时刻,把预分频寄存器由0变到1,如果在此时,立刻改变时钟的分频系数,那么就会导致在一个周期内,前半部分和后半部分的频率不一样,这里计数记到一半,计数频率突然就会改变了。STM32设计比较严谨,设计了缓冲寄存器,这样当我计数记到一半的时候,改变了分频值,这个变化不会立即生效,而是等到本次计数周期结束时,产生了更新事件,预分频控制寄存器的值才会传递到预分频缓冲器里面去,才会生效。所以这里我们看到,即使我们在计数中途改变了预分频值,计数器寄存器仍然会保持原来的频率,直到本轮计数完成,在下一轮计数时,改变后的分频值才会起作用。

预分频器内部其实也是靠计数来分频的,当预分频值为0时,预分频计数器也一直为0,直接输出原频率,当预分频值为1时,计数器开始01010101这样计数,在回到0的时候输出一个脉冲,定时器时钟计一次数。这样输出频率就是输入频率的二分频。所以预分频器的值与实际分频系数之间就会有一个值的偏移。

计数器时序

在这里插入图片描述
上图是计数器时序图,分频因子为2就是分频系数为2。
上图计数器溢出,产生一个更新事件脉冲,还会置一个更新中断标志位UIF,这个标志位置1就会申请中断,中断响应后需要在中断程序中手动清零。
所以最后的公式就是CK_CNT一秒钟计数多少,然后ARR是自动重装寄存器的值,重装为1,那就是计数 0 和 1,就是两次,所以也要加1,所以用 一秒钟计数多少 / 计多少溢出 就是计数器溢出的频率。
预分频器为了防止计数中途更改数值造成错误设计了缓冲寄存器,计数器也存在这种错误的可能,所以也存在这种设计。
在这里插入图片描述
图中带有阴影的寄存器都是存在影子寄存器这种缓冲机制的。

在这里插入图片描述
上图就是有无缓冲寄存器的情况对比,通过设置ARPE位,就可以选择是否使用预装功能。简单的不介绍了,有一种特殊情况,如果正在自增计数,如果没有使用自动重装载寄存器,如果更新的数比正在计数的小,那么就会一直自增,直到增加为0,然后再自增为目标值才会产生计数器溢出。

RCC时钟树

在这里插入图片描述
时钟树就是STM32中用来产生和配置时钟并且把配置好的时钟传递到各个外设的系统。时钟是所有外设的基础,所有时钟也是最先需要配置的东西,程序中主函数之前还会执行一个SystemInit函数,这个函数就是用来配置这个时钟树的。

图中中间有一个CSS电路,(Clock Security System),是时钟安全系统,负责切换时钟,可以检测外部时钟的运行状态,一旦外部时钟失效,就会切换到内部时钟。在高级定时器中就有CSS的身影,检测到外部时钟失效,就会触发刹车系统。

定时器定时中断库函数介绍

配置定时器定时中断只需要将这个图中每个模块打通即可
在这里插入图片描述
第一步:
RCC开启时钟,基本上每个代码这都是第一步。打开时钟后,定时器的基准时钟和整个外设的工作时钟就都会同时打开了。
第二步:
选择时基单元的时钟源,就是黄色那块。对于定时中断,我们就选择内部时钟源。
第三步:
配置时基单元,包括这里的预分频器,自动重装器, 计数模式等等,这些参数用一个结构体就可以配置好。
第四步:
配置输出中断控制,允许更新中断输出到NVIC。
第五步:
配置NVIC,在NVIC中打开定时器中断的通道并分配一个优先级。
第六步:
配置运行控制。整个模块配置完成后,我们还需要使能一下计数器,要不然计数器是不会运行的。当定时器使能后,计数器就会开始计数了,当计数器更新时触发中断。
第七步:
我们再写一个定时器的中断函数,这样这个中断函数每隔一段时间就能自动执行。

库函数介绍:
在这里插入图片描述
库函数存在很多,只做部分介绍。

void TIM_DeInit(TIM_TypeDef* TIMx);

恢复缺省配置。

void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);

时基单元初始化函数,用来配置图中的时基单元的。TIMx是选择某个定时器。TIM_TimeBaseInitStruct结构体包含了配置时基单元的一些参数。

在使用的时候,发现需要配置一个变量为TIM_ClockDivision,这个参数是时钟分频,这个参数有什么用呢?
在这里插入图片描述
观察通用定时器的框图,在定时器的外部输入引脚后面会接一个输入滤波,这个滤波器就是会在一个固定的采样频率 f 下进行采样,如果连续N个采样点都是相同的电平,那就代表输入信号稳定,如果不全相同,就说明有抖动,此时就保持上一次的输入,或者输出低电平。采样频率 f 和采样点数N都是滤波器的参数,频率越低,采样点数越多,滤波效果就越好,不过相应的信号延迟也越大。这就是滤波器的工作原理。这个采样频率 f 是内部时钟,也可以是内部时钟加一个时钟分频,分频多少就是上面说的那个参数TIM_ClockDivision。所以这个参数和时基单元关系不大。

void TIM_TimeBaseStructInit(TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);

将结构体变量赋一个默认值。

void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);

使能计数器,就是图中的运行控制位。TIMx是选择某个定时器。NewState选择状态,即使能还是失能。

void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);

用来使能中断输出信号。对应图中中断输出控制。TIMx是选择某个定时器。TIM_IT选择配置哪个中断输出,即定时中断(更新中断)还是输入捕获或者其他。NewState选择状态,即使能还是失能。

void TIM_InternalClockConfig(TIM_TypeDef* TIMx);
void TIM_ITRxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);
void TIM_TIxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_TIxExternalCLKSource,
                                uint16_t TIM_ICPolarity, uint16_t ICFilter);
void TIM_ETRClockMode1Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,
                             uint16_t ExtTRGFilter);
void TIM_ETRClockMode2Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, 
                             uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter);
void TIM_ETRConfig(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,
                   uint16_t ExtTRGFilter);

这些函数就是选择时基单元的时钟选择部分。

void TIM_InternalClockConfig(TIM_TypeDef* TIMx);

选择内部时钟。即图中RCC内部时钟。

void TIM_ITRxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);

选择ITRx其他定时器的时钟,即图中ITRx其他定时器,参数TIMx是选择要配置的定时器,TIM_InputTriggerSource选择要接入哪个其他的定时器。

void TIM_TIxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_TIxExternalCLKSource,
                                uint16_t TIM_ICPolarity, uint16_t ICFilter);

选择TIx捕获通道的时钟,即图中TIx捕获通道,TIMx是选择某个定时器。TIM_TIxExternalCLKSource选择TIx具体的某个引脚TIM_ICPolarity输入的极性,ICFilter滤波器。

void TIM_ETRClockMode1Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,
                             uint16_t ExtTRGFilter);

选择ETR通过外部时钟模式1输入的时钟。TIM_ExtTRGPrescaler外部触发预分频器,可以对ETR的外部时钟再提前做一个分频。TIM_ExtTRGPolaritExtTRGFilter也是作极性和滤波器的配置。

void TIM_ETRClockMode2Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, 
                             uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter);

和上面一样,不过是换了一路,参数都一样。
对于ETR输入的外部时钟而言,这两个函数的功能和参数都是一样的。如果不需要触发输入的功能,这两个函数可以互换。

void TIM_ETRConfig(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,
                   uint16_t ExtTRGFilter);

单独用来配置ETR引脚的预分频器,极性,滤波器这些参数的。

在初始化结构体中有许多关键参数,比如自动重装载值和预分频值等,这些参数可能会在初始化之后还需要更改,如果为了改某个参数还要再调用一次初始化函数,这样就很麻烦。所以库提供了一些单独的函数,可以方便的更改这些关键参数。

void TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode);

用来单独写预分频值的,Prescaler要写入的预分频值。TIM_PSCReloadMode写入的模式,这个就是前面说的影子模式的选择。

void TIM_CounterModeConfig(TIM_TypeDef* TIMx, uint16_t TIM_CounterMode);

用来改变计数器的计数模式的。TIM_CounterMode选择新的计数器模式。

void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);

自动重装器预装功能配置

void TIM_SetCounter(TIM_TypeDef* TIMx, uint16_t Counter);

给计数器写入一个值,想手动给一个计数值,就可以用这个函数。

void TIM_SetAutoreload(TIM_TypeDef* TIMx, uint16_t Autoreload);

给自动重装器写入一个值

uint16_t TIM_GetCounter(TIM_TypeDef* TIMx);

看当前计数器计到多少了,返回值就是当前计数的值。

uint16_t TIM_GetPrescaler(TIM_TypeDef* TIMx);

获取当前的预分频器的值。

FlagStatus TIM_GetFlagStatus(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);
void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);
ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT);
void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT);

用来获取和清除标志位的。

demo

内部时钟

对TIM2定时一秒的更新中断配置。

#include "Config.H"
extern uint16_t Num;
void Timer_TIM2_Init()
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	
	TIM_InternalClockConfig(TIM2);//上电后默认就是内部时钟,不写这个函数也行
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1;//ARR重装寄存器的值
	TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;//PSC预分频器的值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//重复计数器的值,这是高级定时器的,我们配置TIM2,所以直接给0
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
	
	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);//对更新中断使能
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	NVIC_InitTypeDef NVIV_InitStructure;
	NVIV_InitStructure.NVIC_IRQChannel = TIM2_IRQn;//选择通道
	NVIV_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIV_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
	NVIV_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIV_InitStructure);
	
	TIM_Cmd(TIM2, ENABLE);
}


void TIM2_IRQHandler()
{
	if(TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{
		Num++;
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	}
}

通过OLED显示我们的Num值,可以发现,Num在上电后就立刻变为了 1,没有从0开始,这是为什么呢?
打开TIM_TimeBaseInit()函数,,最后一句是:
在这里插入图片描述
注释写的是,生成一个更新事件,来重装载预分频器的值和重复计数器的值,立刻。
因为预分频器是有一个缓冲寄存器的,我们写的值只有在更新事件后才会写入,所以在最后就手动生成了一次更新事件。这样预分频器的值就有效了。但是这也导致了立刻更新事件。
所以可以在中断使能TIM_ITConfig前面,TIM_TimeBaseInit后面,加一句TIM_ClearFlag(TIM2, TIM_FLAG_Update);,清楚中断标志位,因为中断还没有使能,所以不会进中断,再使能后,标志位为0,所以也不会进中断了。

至于TIM_ClearFlag与TIM_ClearITPendingBit区别,大部分人说的时后者时清楚中断挂起位,前者是清楚更新中断位,那么这样说,使用后者函数是无效的,因为中断都没有使能怎么会存在挂起呢?但是实际使用却是二者都有效。
在这里插入图片描述

外部时钟

在这里插入图片描述

#include "Config.H"
extern uint16_t Num;
void GPIO_TIM2_ETRMode2_Init()
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
}
void Timer_TIM2_Init()
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	
	GPIO_TIM2_ETRMode2_Init();
	
	//TIM_InternalClockConfig(TIM2);//上电后默认就是内部时钟,不写这个函数也行
	TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x00);//外部时钟,不分频,不反向(上升沿),不使用滤波器
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = 10 - 1;//ARR重装寄存器的值
	TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1;//PSC预分频器的值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//重复计数器的值,这是高级定时器的,我们配置TIM2,所以直接给0
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
	
	TIM_ClearFlag(TIM2, TIM_FLAG_Update);
	//TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);//对更新中断使能
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	NVIC_InitTypeDef NVIV_InitStructure;
	NVIV_InitStructure.NVIC_IRQChannel = TIM2_IRQn;//选择通道
	NVIV_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIV_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
	NVIV_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIV_InitStructure);
	
	TIM_Cmd(TIM2, ENABLE);
}


void TIM2_IRQHandler()
{
	if(TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{
		Num++;
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	}
}

主要是TIM_ETRClockMode2Config()配置,配置外部时钟源,他的分频,是否反向和滤波器的配置。因为是外部时钟,所以会存在滤波器的配置。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐