文章目录

  • 一、STM32定时器是什么?
  • 二、STM32定时器的功能
  • 1.计时&&中断
  • 2. PWM产生
  • 3.输入捕获
  • 三、总结
  • 一、STM32定时器是什么?

    定时器顾名思义就是可以用来定时的,我们可以设置想要的定时时间,然后去做很多事情。STM32的定时器功能很强大,可以用来定时、计数、PWM产生、输入捕获以及定时器中断等。下面就一一介绍一下这些功能。

    二、STM32定时器的功能

    1.计时&&中断

    定时器的计数和定时器的定时功能息息相关,我个人理解为控制计数的数量来控制定时的时间,由于定时器的计数频率和计数量可调,所以可以控制定时器的计时时间。
    计数频率和系统时钟、重装载值(arr)和预分频系数(psc)有关。系统时钟在前面关于时钟的学习总结中已经讲解,我们会在主函数的最开始设置系统时钟,STM32单片机的时钟一般设置为最高的72M。预分频系数是指系统时钟经过几分频作为定时器的时钟,预分频系数设置为0的时候就是1分频,也就是不分频,设置为1时候是2分频,3的时候就是4分频,4的时候…总的来说就是PSC+1倍分频。 最大重装载值就是定时器的最大计数值,STM32定时器有一个十六位的计数寄存器,最大计数值就是65535。每次配置定时器都要设置arr和psc,下面给出一段定时器配置的程序。

    	TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;
    	TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;
    	TIM_TimeBaseInitStruct.TIM_Period=arr;
    	TIM_TimeBaseInitStruct.TIM_Prescaler=psc;
    	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);//定时器初始化,配置参数
    

    这段程序中,预分频系数和最大重装载值在调用定时器初始化函数时设置。
    这里顺便说一下定时器初始化结构体中的几个常用成员的含义。

  • TIM_ClockDivision 定时器时钟分频因子ClockDivision是决定数字滤波器采样频率的参数,之后的输入捕获会用到这个
  • TIM_CounterMode 定时器的计数方式,可以选择向上计数还是向下计数
  • TIM_Period 最大重装载值
  • TIM_Prescaler 预分频系数
  • 和定时器计时功能关系密切的还有一个功能,那就是定时器中断。定时器中断就是在定时器的计数值达到想要的最大计数值时(可以理解为爆表),也就是想要的计时时间后,进入一次中断,在中断中执行特定的代码。
    话不多说,还是通过程序来看定时器中断的配置

    void TIM2_Int_Init(u16 arr,u16 psc)//定时器2中断初始化  arr为重装载值 psc为分频系数 主函数要进行中断分组
    {
    	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
    	NVIC_InitTypeDef NVIC_InitStruct;
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//定时器时钟使能
    	
    	TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;
    	TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;
    	TIM_TimeBaseInitStruct.TIM_Period=arr;
    	TIM_TimeBaseInitStruct.TIM_Prescaler=psc;
    	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);//定时器初始化,配置参数
    	
    	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//设置更新中断
    	
    	NVIC_InitStruct.NVIC_IRQChannel=TIM2_IRQn;
    	NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
    	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1;
    	NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;
    	
    	NVIC_Init(&NVIC_InitStruct);
    	TIM_ARRPreloadConfig(TIM2,ENABLE);
    	TIM_Cmd(TIM2,ENABLE);//使能TIM2定时器
    }
    

    在这一段程序中,设置了定时器的计数时间,中断的触发方式(更新中断,也就是爆表),以及中断的优先级,以及最重要的使能中断。
    有中断就肯定要有中断服务函数

    void TIM2_IRQHandler()//定时器中断服务函数
    {
    	if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)
    	{
    		TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
    	}
    }
    
  • 设置定时器的时基参数
  • 设置定时器更新中断
  • 设置中断参数,包括优先级,中断使能等
  • 使能定时器
  • 编写中断服务函数,在启动文件中找固定的中断向量
  • 2. PWM产生

    利用定时器的输出比较可以产生PWM波,PWM是控制电机速度必不可少的一个东西。STM32一个定时器有四个通道,总共可以产生四路PWM,我们在设置产生PWM时除了要设置基本的定时器的分频系数和重装载值之外,还要设置产生PWM的通道的参数以及调用相关的使能函数。下面还是通过一段程序来展示怎么设置产生PWM。

    void TIM3_PWM_Init(u16 arr,u16 psc) // 定时器3 通道2和通道1、3、4输出两路PWM波
    {
    	GPIO_InitTypeDef GPIO_InitStruct;
    	TIM_OCInitTypeDef TIM_OCInitStruct;
    	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
    	
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能定时器时钟和GPIO时钟
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//使能定时器时钟和GPIO时钟
    	
    
    	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;//配置其为复用推挽输出
    	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7;
    	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA,&GPIO_InitStruct);//配置PA6,PA7口
    	
    	TIM_TimeBaseInitStruct.TIM_Period=arr;
    	TIM_TimeBaseInitStruct.TIM_Prescaler=psc;
    	TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;
    	TIM_TimeBaseInitStruct.TIM_ClockDivision=0;
    	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);//初始化定时器
    	
    	TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_Low;
    	TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM2;
    	TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;
    	TIM_OC1Init(TIM3,&TIM_OCInitStruct);//配置定时器输出通道1
    	
    	TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_Low;
    	TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM2;
    	TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;
    	TIM_OC2Init(TIM3,&TIM_OCInitStruct);//配置定时器输出通道2
    	
    	TIM_OC1PreloadConfig(TIM3,TIM_OCPreload_Enable);//使能重装载寄存器
    	TIM_OC2PreloadConfig(TIM3,TIM_OCPreload_Enable);//使能重装载寄存器
    	
    	TIM_Cmd(TIM3,ENABLE);//使能整个TIM3
    }
    

    在这段程序中,设置了定时器的计数周期和通道1和通道2的输出参数并在其他地方调用输出比较函数产生PWM。

    代码如下

    	TIM3_PWM_Init(20000-1,72-1);
    	TIM_SetCompare1(TIM3,10000);//PID算法实现;
    	TIM_SetCompare2(TIM3,10000);//PID算法实现;
    

    这样就可以产生PWM波了!
    我们总结一下PWM波的设置步骤

  • 使能相关定时器时钟和GPIO时钟
  • 设置GPIO为推挽复用输出(不是用作普通的IO)
  • 设置定时器的时基参数
  • 设置定时器输出通道的参数
  • 使能定时器
  • 设置输出比较值,产生PWM
  • 3.输入捕获

    输入捕获也是定时器的一大功能之一,他可以测量脉冲数量和高电平以及低电平时间,话不多说,马上上程序。

    	GPIO_InitTypeDef GPIO_InitStruct;
    	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
    	TIM_ICInitTypeDef TIM5_ICInitStructure;
    	NVIC_InitTypeDef NVIC_InitStructure;
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    	
    	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPD;
    	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
    	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_10MHz;
    	GPIO_Init(GPIOA,&GPIO_InitStruct);
    	GPIO_ResetBits(GPIOA,GPIO_Pin_0);
    	
    	TIM_TimeBaseInitStruct.TIM_Period=arr;
    	TIM_TimeBaseInitStruct.TIM_Prescaler=psc;
    	TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;
    	TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;
    	TIM_TimeBaseInit(TIM5,&TIM_TimeBaseInitStruct);
    	
    		TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1; //CC1S=01 	选择输入端 IC1映射到TI1上
      	TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;	//上升沿捕获
      	TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上
      	TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;	 //配置输入分频,不分频 
      	TIM5_ICInitStructure.TIM_ICFilter = 0x00;//IC1F=0000 配置输入滤波器 不滤波
      	TIM_ICInit(TIM5, &TIM5_ICInitStructure);
    	
    		NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;  //TIM5中断
    		NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;  //先占优先级2级
    		NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  //从优先级0级
    		NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
    		NVIC_Init(&NVIC_InitStructure);  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器 
    		
    		TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);//允许更新中断 ,允许CC1IE捕获中断	
    		
    		TIM_Cmd(TIM5,ENABLE ); 	//使能定时器5
    

    设置输入捕获的关键在于输入捕获初始化函数——TIM_ICInit,例程中设置了捕获通道一的上升沿。除此之外,还设置了捕获中断,在中断服务函数中计算高电平时间。代码如下

    void TIM5_IRQHandler()
    {
    	 	if((TIM5CH1_CAPTURE_STA&0X80)==0)//还未成功捕获	
    	{	  
    		if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET)
    		 
    		{	    
    			if(TIM5CH1_CAPTURE_STA&0X40)//已经捕获到高电平了
    			{
    				if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)//高电平太长了
    				{
    					TIM5CH1_CAPTURE_STA|=0X80;//标记成功捕获了一次
    					TIM5CH1_CAPTURE_VAL=0XFFFF;
    				}else TIM5CH1_CAPTURE_STA++;
    			}	 
    		}
    	if (TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET)//捕获1发生捕获事件
    		{	
    			if(TIM5CH1_CAPTURE_STA&0X40)		//捕获到一个下降沿 		
    			{	  			
    				TIM5CH1_CAPTURE_STA|=0X80;		//标记成功捕获到一次上升沿
    				TIM5CH1_CAPTURE_VAL=TIM_GetCapture1(TIM5);
    		   		TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising); //CC1P=0 设置为上升沿捕获
    			}else  								//还未开始,第一次捕获上升沿
    			{
    				TIM5CH1_CAPTURE_STA=0;			//清空
    				TIM5CH1_CAPTURE_VAL=0;
    	 			TIM_SetCounter(TIM5,0);
    				TIM5CH1_CAPTURE_STA|=0X40;		//标记捕获到了上升沿
    		   		TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling);		//CC1P=1 设置为下降沿捕获
    			}		    
    		}
    	}		
    	TIM_ClearITPendingBit(TIM5, TIM_IT_CC1|TIM_IT_Update); //清除中断标志位
    }
    

    三、总结

    定时器的功能非常强大,而且比较复杂,我们可以看出,不管是定时器中断还是产生PWM亦或是输入捕获,都要设置定时器的基本参数,arr和psc以及时钟分频,然后再设置相关的参数,如中断优先级、输入捕获参数、输出比较参数以及使能,这些步骤都是必不可少的,所以我们在使用定时器时一定要细心,否则找错误很麻烦。今天关于定时器的学习总结就写到这里,有错误的地方,请各位在评论区批评指正。

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32定时器学习总结

    发表评论