STM32----通用定时器TIM2~TIM5的三种功能

通用定时器TIM2~5

引脚定义
TIM2_CH1------PA0
TIM2_CH2------PA1
TIM2_CH3------PA2
TIM2_CH4------PA3

TIM3_CH1------PA6
TIM3_CH2------PA7
TIM3_CH3------PB0
TIM3_CH4------PB1

对于通用定时器主要有三个功能:

  1. 基本的定时器功能,和基本定时器相同
  2. PWM脉冲输出
  3. 测量输入脉冲的频率和脉冲宽度

基本定时器功能

TIM2~5的基本定时器功能与基本定时器TIM6和TIM7类似,不过不同的是,对于基本定时器中的计数器只能向上计数,而通用定时器的计数器可以配置计数模式向上或者向下。
向上计数模式:从零开始向上计数,当达到TIMx_ARR中的值时,计数器清零,然后产生一个计数器溢出中断
向下计数模式:从TIMx_ARR中的数值开始向下计数,当计数器中数为0时,自动将TIMx_ARR中的数重装入计数器,同时产生一个向下溢出事件。

PWM脉冲输出

对应于上面的GPIO口,将对应的GPIO配置为推挽复用输出。对于TIM的配置主要包括两个结构TIM_TimeBaseInitTypeDefTIM_OCInitTypeDef,对于第一个结构体就是配置基本定时器时所使用的,对于第二结构体是输出捕获(Output Capture),只要用来配置输出PWM的占空比,高低电平等信息。

对于TIM_TimeBaseInitTypeDef的配置

类似于基本定时器的配置:

  1. .TIM_Period:定时的周期,该值存储在ARR中,计数器从0自增到该值,或者从该值自减到0
  2. .TIM_Prescaler:对TIMxCLK的预分频系数,分频后作为计数器的驱动时钟, 驱 动 时 钟 = T I M x C L K / ( 分 频 系 数 + 1 ) 驱动时钟=TIMxCLK/(分频系数+1) =TIMxCLK/(+1)
  3. .TIM_ClockDivision:时钟分频因子,这个与上一个不同,这个也是对TIMxCLK进行分频,但分频后的时钟被输送到定时器的ETRP数字滤波器,会影响滤波器的采样频率。ETRP数字滤波器是对外部时钟TIMxETR进行滤波。一般使用内部时钟,该值没有任何影响。
  4. .TIM_CounterMode:配置计数器的技术模式,常用的是向上计数或者向下计数。
    具体的配置,如下代码:
	tim_s.TIM_ClockDivision = TIM_CKD_DIV1;
	tim_s.TIM_CounterMode = TIM_CounterMode_Up;
	tim_s.TIM_Period = 9999;
	tim_s.TIM_Prescaler = 0;
	TIM_TimeBaseInit(TIM2,&tim_s);

对于TIM_OCInitTypeDef的配置

对于TIM_OCInitTypeDef结构体在通用定时器中的用处来看,就是配置输出PWM的相关信息:

  1. .TIM_OCMode:配置PWM输出的模式,总共有两种模式PWM1和PWM2,。
    PWM1:向上计数时,当计数器中的数值小于CCR中的数值(也就是后面配置的TIM_Pulse的值)时输出为有效电平,当计数器中的数值大于CCR中的数值且小于ARR中的数值时,输出为无效电平。向下计数时,计数器中的数值大于CCR中的值输出为无效电平。
    PWM2:向上计数时,当计数器中的数值小于CCR中的数值(也就是后面配置的TIM_Pulse的值)时输出为无效电平,当计数器中的数值大于CCR中的数值且小于ARR中的数值时,输出为有效电平。向下计数时,计数器中的数值大于CCR中的值输出为有效电平。
  2. .TIM_OutputState:配置输出模式的状态,使能输出。
  3. .TIM_OCPolarity:(polarity n.极性)该配置有效电平的极性,可以将有效电平配置高电平,也可以配置为低电平。
  4. .TIM_Pulse:该参数记为CCR中的数值,由它来控制PWM的占空比。
    具体的配置代码如下:
	oc_s.TIM_OCMode = TIM_OCMode_PWM1;
	oc_s.TIM_OutputState = TIM_OutputState_Enable;
	oc_s.TIM_OCPolarity = TIM_OCPolarity_High;
	oc_s.TIM_Pulse = 1000;
	TIM_OC1Init(TIM2,&oc_s);

对于同一个定时器的不同通道需要单独初始化TIM_OCxInit(TIMx,&oc_s)
并且对于每个通道初始化之后,需要将CCR中的值存入寄存器TIM_OCxPreloadConfig(TIMx,TIM_OCPreload_Enable)
在开启TIM之前需要将ARR的也存入寄存器TIM_ARRPreloadConfig(TIMx,ENABLE)

对于PWM输出的TIM完整配置代码如下:

void TIM2_Config(void)
{
    
    
	TIM_TimeBaseInitTypeDef tim_s;
	TIM_OCInitTypeDef oc_s;	
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	
	
	
	oc_s.TIM_OCMode = TIM_OCMode_PWM1;
	oc_s.TIM_OutputState = TIM_OutputState_Enable;
	oc_s.TIM_OCPolarity = TIM_OCPolarity_High;
	oc_s.TIM_Pulse = 1000;
	TIM_OC1Init(TIM2,&oc_s);
	
	TIM_OC1PreloadConfig(TIM2,TIM_OCPreload_Enable);
	
	oc_s.TIM_Pulse = 8000;
	TIM_OC2Init(TIM2,&oc_s);
	TIM_OC2PreloadConfig(TIM2,TIM_OCPreload_Enable);
	
	TIM_ARRPreloadConfig(TIM2,ENABLE);
	TIM_Cmd(TIM2,ENABLE);
}

测量输入脉冲的频率和脉冲宽度

对于测量输入脉冲的频率和脉冲宽度,需要配置对应通道的GPIO。将对应的GPIO配置为下拉输入。对于输入脉冲测量主要配置两个结构体和书写中断函数。具体的工作过程,假设使用通道1来进行脉冲测量,首先在配置中将捕获设为上升沿捕获,则当捕获到上升沿时,触发中断,在中断中将触发方式改为下降沿触发,并将计数器中的数清0。当下降沿到来,再次触发中断,计数器中的数自动存入到CCR中,则在中断中将触发方式再次更改为上升沿触发,且可以读出CCR中的值即为输入PWM的高电平时间。当上升沿再次到来,计数器中的数自动存入到CCR中,并触发中断,在中断中将CCR的值读出即为PWM的周期(以上的过程,默认为PWM的周期小于定时器溢出的时间

配置两个结构体

在测量输入脉冲时需要配置TIM_TimeBaseInitTypeDef和TIM_ICInitTypeDef,对于TIM_TimeBaseInitTypeDef来说和之前的PWM配置相似,不同的是关于预分频系数和周期的配置,这个按照需要自己配置。

TIM_ICInitTypeDef的配置
  1. .TIM_Channel:进行采用的通道,例TIM_Channel_3。
  2. .TIM_ICPolarity:触发中断的电平,可以设置为上升沿,也可设置成下降沿。
  3. .TIM_ICPrescaler:输入分频器,对输入的PWM可以进行相应的分频,例如2分频,就是两个周期采样一次。(个人理解)
  4. .TIM_ICFilter:输入的滤波器,没用,设为0x00
  5. .TIM_ICSeclection:设置是否直连如下图中对于TI1来说,后面有TIFP1和TIFP2,对于TIFP1是直接连,对于TIFP2是间接连接。
    在这里插入图片描述
    具体的配置代码:
	ic_s.TIM_Channel = TIM_Channel_3;
	ic_s.TIM_ICPolarity = TIM_ICPolarity_Rising;
	ic_s.TIM_ICPrescaler = TIM_ICPSC_DIV1;
	ic_s.TIM_ICFilter = 0x00;
	ic_s.TIM_ICSelection = TIM_ICSelection_DirectTI;
	TIM_ICInit(TIM2,&ic_s);

在结构配置完成以后,需要对中断控制器进行配置:

void NVIC_Config(void)
{
    
    
	NVIC_InitTypeDef nvic_s;
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	nvic_s.NVIC_IRQChannel = TIM2_IRQn;
	nvic_s.NVIC_IRQChannelPreemptionPriority = 0;
	nvic_s.NVIC_IRQChannelSubPriority = 2;
	nvic_s.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&nvic_s);
}

配置完成以后打开中断TIM_ITConfig(TIM2,TIM_IT_Update | TIM_IT_CC3|TIM_IT_CC4,ENABLE);
TIM_IT_Update:计数器溢出中断
TIM_IT_CC3:通道3的捕获中断
TIM_IT_CC4:通道4的捕获中断

扫描二维码关注公众号,回复: 16511243 查看本文章
中断函数的编写

对于中断函数的编写流程如下(以上的过程,默认为PWM的周期小于定时器溢出的时间):
首次上升沿捕获成功触发中断,进入中断,在中断中使用TIM_SetCounter(TIMx,0)将对应的定时器中计数器清0.然后将对应的通道设置为下降沿捕获TIM_OCnPolarityConfig(TIMx,TIM_ICPolarity_Falling);,同时需要标记上升沿第一次来。对应通道捕获到下降沿,自动的将计数器CNT中的数值赋值到CCR中,同时触发中断,在中断中可以将CCR的值读出,该值就是所测波形的高电平时间,然后再将该通道设置为上升沿捕获。再次捕获到上升沿,判断是否是第二次捕获上升沿,如果是就将CCR中的值读出,该值是第一个上升沿到第二个上升沿的时间,如果是周期性PWM的话,该值就是PWM的周期时间。如果不是第二次捕获,就重复之前第一捕获的流程。
具体的代码为:

void TIM2_IRQHandler(void)
{
    
    
	if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)//计数器溢出中断判断
	{
    
    
	}
	if(TIM_GetITStatus(TIM2,TIM_IT_CC3) == SET)//定时器通道3捕获中断判断
	{
    
    
		if(C3_flag == 0)// 第一次上升沿到来
		{
    
    
			TIM_SetCounter(TIM2,0);
			TIM_OC3PolarityConfig(TIM2,TIM_ICPolarity_Falling);
			C3_flag = 1;
		}
		else if(C3_flag == 1)//第一次下降沿到来
		{
    
    
			c3_high = (uint32_t)TIM_GetCapture3(TIM2);
			TIM_OC3PolarityConfig(TIM2,TIM_ICPolarity_Rising);
			C3_flag = 2;
		}
		else if(C3_flag == 2)//第二次上升沿到来
		{
    
    
			c3_proide = (uint32_t)TIM_GetCapture3(TIM2);
			C3_flag = 0;
		}
	}
	TIM_ClearITPendingBit(TIM2,TIM_IT_Update | TIM_IT_CC3|TIM_IT_CC4);
}

注意到在上面提到两次PWM的周期小于定时器的溢出时间,是为中断函数的编写和便于把原理叙述清楚,如果没有这个假设,那就要考虑所有的情况
所有的情况大致有以下几类

  • PWM周期 = 定时器的溢出时间:此时对于上升沿的读取时间是没有问题的,对于周期的读取值会是0.
  • PWM周期 >定时器的溢出时间:此时又分为两种情况:定时器溢出发生在上升沿和下降沿之间,或者发生在下降沿和上升沿之间。这种情况因为发生定时器溢出时,计数器会被清0,所以需要统计定时器溢出的次数,在最后将对应的时间加上(计数器溢出次数*计数器溢出时间。)

猜你喜欢

转载自blog.csdn.net/qq_25105061/article/details/106680876