目录

一、概述

                1.定时器的类型

                2.计数模式

                3.主要功能 

                4.通用定时器的结构

                5.时钟源

                6.功能寄存器

二、基本定时功能

三、输出比较功能

四、输入捕获功能 

五、编码器模式


一、概述

        STM32内部集成了多个定时/计数器TIM,根据型号不同,STM32系列芯片最多包含8个定时/计数器。其中,TIM6、TIM7为基本定时器,TIM2~TIM5为通用定时器,TIM1、TIM8为高级控制定时器。

1.定时器的类型

  • 基本定时器
  • 通用定时器
  • 高级控制定时器
  • 窗口看门狗定时器
  • 独立看门狗定时器
  • 系统滴答定时器
  • 2.计数模式

  • 向上计数模式:计数器从0计数到自动加载值(ARR),并产生向上溢出事件。

  • 向下计数模式:计数器从自动加载值(ARR)向下计数到0,并产生向下溢出事件。 

  • 中央对齐模式:计数器从0开始计数到自动加载值-1,产生向上溢出事件,然后向下计数到1,产生向下溢出事件,最后再从0开始重新计数。

  • 3.主要功能 

  • 基本定时功能
  • 输出比较
  • 输入捕获
  • 编码器接口模式
  • 单脉冲模式
  • 死区控制和刹车功能
  •         注:本文将介绍前四种常用的功能。 

    4.通用定时器的结构

            STM32通用定时器主要包括1个外部触发引脚(TIMx_ETR),4个输入/输出通道(TIMx_CH1~4),1个内部时钟(CK_INT),1个触发控制器1个时基单元(由预分频器PSC、自动重装载寄存器ARR和计数器CNT组成)等。如图所示:

    5.时钟源

    定时/计数器时钟可由下列时钟源(如上图所示)提供: 

  • 内部时钟(CK_INT)
  • 外部时钟模式1(TIMx_CH1~4)
  • 外部时钟模式2(TIMx_ETR)
  • 内部触发输入(ITR0~3,使用一个定时器作为另一个定时器的预分频器)
  • 当时钟源来自内部时,可实现定时功能;当时钟源来自外部时,可实现计数功能。

    6.功能寄存器

            略。

    二、基本定时功能

            下面介绍TIM定时器最基础的功能:基本定时功能。这种功能常用于周期性事件的触发。主要使用流程和步骤如下:

    1. 配置时基单元
    2. 配置NVIC
    3. 编写中断服务函数
    void Timer_Init(void)
    {
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);			
        //开启TIM2的时钟
    	
    	TIM_InternalClockConfig(TIM2);		
        //选择时钟源为内部时钟,若不调用此函数,TIM2默认也为内部时钟
    	
    	/*配置时基单元*/
    	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;			
    	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;		
        //时钟分频,选择1分频,即不分频
    	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;			
        //重复计数器,高级定时器才会用到
    	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
    	
    	TIM_ClearFlag(TIM2, TIM_FLAG_Update);						
        //清除定时器更新标志位,TIM_TimeBaseInit函数末尾,手动产生了更新事件,
        //若不清除此标志位,则开启中断后,会立刻进入一次中断,
        //如果不介意此问题,则不清除此标志位也可。
    																
    	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);					//开启TIM2的更新中断
    	
    	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);				//设置NVIC分组
    
    	/*配置NVIC*/
    	NVIC_InitTypeDef NVIC_InitStructure;						
    	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;				//选择配置NVIC的TIM2线
    	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				//使能
    	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;	//设置抢占优先级为2
    	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;			//设置响应优先级为1
    	NVIC_Init(&NVIC_InitStructure);	
    	
    	TIM_Cmd(TIM2, ENABLE);			                            //使能TIM2,运行TIM2
    }
    
    
    
    
    void TIM2_IRQHandler(void)                                      //定时器中断服务函数
    {
    	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
    	{    
                
    
            //此处编写要周期实现的功能
    		
    
    		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
    	}
    }
    

     三、输出比较功能

             当定时器的计数器值(CNT)与捕获比较寄存器(CCR)的值相等时,产生比较事件,并根据配置对输出管脚进行相应的操作,如翻转或置位。其应用场景如下:

  • PWM(脉宽调制)信号的产生:输出占空比可调的PWM信号,用于电机控制、LED调光等。
  • 定时脉冲:在特定时间产生一个脉冲信号,用于精确事件触发。
  • DAC触发:精确触发模拟信号输出。
  • 下面是产生PWM波的主要流程:

    1.  配置GPIO(用于输出PWM,根据引脚定义表配置)
    2. 配置时基单元
    3. 配置输出比较模式
    void PWM_Init(void)
    {
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);			//开启TIM2的时钟
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);			//开启GPIOA的时钟
    	
    
    	/*配置GPIO*/
    	GPIO_InitTypeDef GPIO_InitStructure;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;                 //复用推挽输出
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA, &GPIO_InitStructure);								
    	//受外设控制的引脚,均需要配置为复用模式
    	
    
    	TIM_InternalClockConfig(TIM2);		
        //选择时钟源为内部时钟,若不调用此函数,TIM默认也为内部时钟
    	
    
    	/*配置时基单元*/
    	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;     
        //时钟分频,选择1分频,即不分频
    	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; 
        //计数模式,选择向上计数
    	TIM_TimeBaseInitStructure.TIM_Period = 100 - 1;                 
        //计数周期,即ARR的值
    	TIM_TimeBaseInitStructure.TIM_Prescaler = 36 - 1;               
        //预分频器,即PSC的值
    	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;            
        //重复计数器,高级定时器才会用到
    	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);            
    
    	
    	/*配置输出比较模式*/ 
    	TIM_OCInitTypeDef TIM_OCInitStructure;	
    	TIM_OCStructInit(&TIM_OCInitStructure);                         
        //结构体初始化,若结构体没有完整赋值,则最好执行此函数,给结构体所有成员都赋一个默认值,避免结构体初值不确定的问题
    	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;               
        //输出比较模式,选择PWM模式1
    	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;       
        //输出极性,选择为高,若选择极性为低,则输出高低电平取反
    	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;   
        //输出使能
    	TIM_OCInitStructure.TIM_Pulse = 0;								
        //初始的CCR值,也可以不定为0,直接定为想要的占空比所需的CCR值
    	TIM_OC3Init(TIM2, &TIM_OCInitStructure);                        
    
    
    	TIM_Cmd(TIM2, ENABLE);			
        //使能TIM2,运行TIM2
    }
    
    
    TIM_SetCompare3(TIM2, CCR值);		            
    //设置CCR的值,设置CCR几的值取决于使用哪个引脚,PA2对应的是CCR3
    //该行代码用于改变占空比,一般放在主函数或者中断服务函数
    
    

     另外,PWM的三项重要数据的计算方法如下:

    1. 占空比:CCR/(ARR+1)
    2. 分辨率:1/(ARR+1)
    3. 频率:CK_PSC/(PSC+1)/(ARR+1),CK_PSC为主频72MHz(STM32F103C8T6)。

    四、输入捕获功能 

            输入捕获模式用于测量外部信号的时间特性,例如周期、频率、脉宽等。它通过将外部输入信号的某个边沿(上升沿或下降沿)捕获并保存计数器的值,从而实现时间测量。 

            下面介绍通过输入捕获功能实现频率测量的步骤:

    1.  配置GPIO(用于接收需要测频率的信号,根据引脚定义表配置)
    2. 配置时基单元
    3. 配置输入捕获功能
    void IC_Init(void)
    {
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);			//开启TIM3的时钟
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);			//开启GPIOA的时钟
    	
    
    	/*配置GPIO*/
    	GPIO_InitTypeDef GPIO_InitStructure;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;				    //上拉输入
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA, &GPIO_InitStructure);			
    	
    
    	TIM_InternalClockConfig(TIM3);		
        //选择TIM3为内部时钟,若不调用此函数,TIM默认也为内部时钟
    	
    	/*配置时基单元*/
    	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;     
        //时钟分频,选择1分频,即不分频
    	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; 
        //计数模式,选择向上计数
    	TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;               
        //计数周期,即ARR的值,取最大
    	TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;               
        //预分频器,即PSC的值
    	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;            
        //重复计数器,高级定时器才会用到
    	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
    
    	
    	/*配置输入捕获功能*/
    	TIM_ICInitTypeDef TIM_ICInitStructure;
    	TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;				
        //选择配置定时器通道1
    	TIM_ICInitStructure.TIM_ICFilter = 0xF;							
        //输入滤波器参数,可以过滤信号抖动
    	TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;		
        //极性,选择为上升沿触发捕获
    	TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;			
        //捕获预分频,选择不分频,每次信号都触发捕获
    	TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;	
        //输入信号交叉,选择直通,不交叉
    	TIM_ICInit(TIM3, &TIM_ICInitStructure);	
    	
    
    	/*选择触发源及从模式*/
    	TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);					
        //触发源选择TI1FP1
    	TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);					
        //从模式选择复位,即TI1产生上升沿时,会触发CNT归零
    	
    
    	TIM_Cmd(TIM3, ENABLE);			//使能TIM3,运行TIM3
    }
    
    
    
    
    
    uint32_t IC_GetFreq(void)           //计算频率
    {
    	return 1000000 / (TIM_GetCapture1(TIM3) + 1);		
        //测周法得到频率fx = fc / N,这里不执行+1的操作也可
    }
    

             频率测量方法有两种,一种是适用于测量高频信号的测频法,一种是适用于测量低频信号的测周法。其原理如下图所示:

     五、编码器模式

            编码器接口模式用于解码旋转编码器的信号。它可以直接连接增量型旋转编码器的A相和B相信号,并解码出编码器的旋转方向和位置。 每个高级定时器和通用定时器都拥有1个编码器接口,两个输入引脚借用了输入捕获的通道1和通道2。

            下面介绍使用编码器模式来测量电机转速的主要步骤,硬件上,将带编码器的电机的编码输出连接到STM32的PA6和PA7,具体如下:

    1. 配置GPIO(用于接收正交编码,根据引脚定义表配置)
    2. 配置时基单元
    3. 配置输入捕获模式
    4. 配置编码器模式
    void Encoder_Init(void)
    {
    	
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);			//开启TIM3的时钟
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);			//开启GPIOA的时钟
    	
    
        /*配置GPIO*/
    	GPIO_InitTypeDef GPIO_InitStructure;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;           //浮空输入
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;          //配置PA6和PA7引脚
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA, &GPIO_InitStructure);							
    	  
      
        /*配置时基单元*/
    	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;				
    	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;     //1分频,即不分频
    	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式
    	TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;               //计数周期,即ARR的值,取最大
    	TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1;                //预分频器,即PSC的值,不分频
    	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;            
    	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);             
    	
    
        /*配置输入捕获模式*/
    	TIM_ICInitTypeDef TIM_ICInitStructure;							
    	TIM_ICStructInit(&TIM_ICInitStructure);																																		
    	TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;				
    	TIM_ICInitStructure.TIM_ICFilter = 0x10;							
        //输入滤波器参数,可以过滤信号抖动
    	TIM_ICInit(TIM3, &TIM_ICInitStructure);	
    						
    	TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;				
    	TIM_ICInitStructure.TIM_ICFilter = 0x10;							
        //输入滤波器参数,可以过滤信号抖动
    	TIM_ICInit(TIM3, &TIM_ICInitStructure);							
    	
    	TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Falling, TIM_ICPolarity_Rising);
    	//配置编码器模式以及两个输入通道是否反相
    
    	TIM_ClearFlag(TIM3, TIM_FLAG_Update);                           //清除一次更新中断标志
    	TIM_SetCounter(TIM3, 0);                                        //计数器清0
    	TIM_Cmd(TIM3, ENABLE);			                                //使能TIM3
    }
    
    
    //使用前面第二点的基本定时功能,在中断服务函数中编写计算速度的代码。
    //这里需要另外配置一个定时器,相关代码参考第二点,这里不再赘述。
    //先计算电机转一圈,STM32收到的n个编码;这取决于电机本身的参数。
    //再每隔T时间输出STM32一共接收到的N个编码;则N/n即这段时间T里电机转过的圈数。
    //最后用N/n/T即可求出转速。其中:
    
        int n=xxx                     //根据电机参数计算
        int N=TIM_GetCounter(TIM3);   //STM32接收到的编码数
        TIM_SetCounter(TIM3, 0);      //拿到T时间内的编码数后,计数清零,重新计数
        float Speed=N/n/T;            //T为定时周期
        
        
    
    

    作者:鱼与仙人掌

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32:通用定时器

    发表回复