TIM定时中断

  • TIM(Timer)定时器

  • 定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断

  • 16位计数器、预分频器、自动重装寄存器的时基单元,在72MHz计数时钟下可以实现最大59.65s的定时

  • 不仅具备基本的定时中断功能,而且还包含内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等多种功能

  • 根据复杂度和应用场景分为了高级定时器、通用定时器、基本定时器三种类型(我们这里以通用为例)

  • 频率就是一秒内出现了多少个重复的周期。

  • 定时器类型:

    1. 类型 编号 总线 功能
      高级定时器 TIM1、TIM8 APB2 拥有通用定时器全部功能,并额外具有重复计数器、死区生成、互补输出、刹车输入等功能
      通用定时器 TIM2、TIM3、TIM4、TIM5 APB1 拥有基本定时器全部功能,并额外具有内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等功能
      基本定时器 TIM6、TIM7 APB1 拥有定时中断、主模式触发DAC的功能
    2. STM32F103C8T6定时器资源:TIM1、TIM2、TIM3、TIM4

  • 高级定时器:

  • 通用计时器:

  • 基本定时器:

  • 定时中断基本结构(重要,其实也是打通线路而已):

  • 预分频器时序:

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

  • 计数器时序:

  • 计数器无预装时序

  • 定时器显示

    -----------------Timer.c----------------------------------------------
    #include "stm32f10x.h"                  // Device header
    ​
    //初始化TIM2,通用计时器
    void Timer_Init(void)
    {
        //第一步开启时钟:用1开启时钟,因为TIM2是APB1总线的外设。
        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; //自动重装
        TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 -1; //预分频
        TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
        TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
        
        TIM_ClearFlag(TIM2, TIM_FLAG_Update);
        TIM_ITConfig(TIM2 , TIM_IT_Update , ENABLE); //使能中断的;更新中断到NVIC的通路。
        
        //NVIC分组,上个课题讲过 分组2
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
        
        NVIC_InitTypeDef NVIC_InitStructure;
        NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //指定2的通道
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //开启
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //抢占优先级
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //响应优先级
        NVIC_Init(&NVIC_InitStructure);
        
        //最后一步,启动计时器
        TIM_Cmd(TIM2 , ENABLE);
        
    }
    ​
    ​
    //中断函数
    //void TIM2_IRQHandler(void)
    //{
    //  if(TIM_GetITStatus(TIM2 , TIM_IT_Update) == SET)  //更新中断
    //  {
    //      
    //      //最后中断都是清除标志位
    //      TIM_ClearITPendingBit(TIM2 , TIM_IT_Update);
    //  }   
    //} 
    ​
    ​
    ---------------Timer.h--------------------------------------------------
    #ifndef __TIMER_H
    #define __TIMER_H
    ​
    void Timer_Init(void);
    ​
    #endif  
    ​
    ​
    ---------------main.c--------------------------------------------------------------
    #include "stm32f10x.h"   
    #include "OLED.h"
    #include "Timer.h"
    ​
    //1.方法一:extern是关键字,跨文件去寻找这个变量。其他文件也定义了这个,这个就相当于另外文件的引用。
    //2.方法二:将中断函数放到main来即可。
    //extern uint16_t Num;
    uint16_t Num;
    ​
    int main(void)
    {
        OLED_Init();
        Timer_Init();
        OLED_ShowString(1,1,"Num:");
        while(1)
        {
            OLED_ShowNum(1,5,Num,4);
            //查看CNT计数器值的变化情况,0-自动重装值(我这里是10000-1)
            OLED_ShowNum(2,5,TIM_GetCounter(TIM2), 5);
        }
    }
    ​
    void TIM2_IRQHandler(void)
    {
        if(TIM_GetITStatus(TIM2 , TIM_IT_Update) == SET)  //更新中断
        {
            Num++;
            //最后中断都是清除标志位
            TIM_ClearITPendingBit(TIM2 , TIM_IT_Update);
        }   
    }
            

    定时器外部中断(感光传感器)

    -----------------Timer.c---------------------------------------------------------------------------------
    #include "stm32f10x.h"                  // Device header
    ​
    //初始化TIM2,通用计时器
    void Timer_Init(void)
    {
        //因为用到了引脚,需要配置GPIO
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
        
        GPIO_InitTypeDef GPIO_InitStructure;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOB, &GPIO_InitStructure);
        
        
        //第一步开启时钟:用1开启时钟,因为TIM2是APB1总线的外设。
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , ENABLE);
        //第二步:不能选内部,通过ETR引脚的外部时钟2配置。
        //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 = 1
        0 - 1; //自动重装
        TIM_TimeBaseInitStructure.TIM_Prescaler = 1 -1; //预分频,不需要分频
        TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
        TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
        
        TIM_ClearFlag(TIM2, TIM_FLAG_Update);
        TIM_ITConfig(TIM2 , TIM_IT_Update , ENABLE); //使能中断的;更新中断到NVIC的通路。
        
        //NVIC分组,上个课题讲过 分组2
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
        
        NVIC_InitTypeDef NVIC_InitStructure;
        NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //指定2的通道
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //开启
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //抢占优先级
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //响应优先级
        NVIC_Init(&NVIC_InitStructure);
        
        //最后一步,启动计时器
        TIM_Cmd(TIM2 , ENABLE);
        
    }
    ​
    uint16_t Timer_GetCounter(void)
    {
        return TIM_GetCounter(TIM2);
    }   
    ​
    ​
    //中断函数
    //void TIM2_IRQHandler(void)
    //{
    //  if(TIM_GetITStatus(TIM2 , TIM_IT_Update) == SET)  //更新中断
    //  {
    //      
    //      //最后中断都是清除标志位
    //      TIM_ClearITPendingBit(TIM2 , TIM_IT_Update);
    //  }   
    //} 
    ​
    ----------------Timer.h----------------------------------------------------------------
    #ifndef __TIMER_H
    #define __TIMER_H
    ​
    void Timer_Init(void);
    uint16_t Timer_GetCounter(void);
    ​
    #endif  
    ​
    ----------------Timer.c-------------------------------------------------------------
    #include "stm32f10x.h"   
    #include "OLED.h"
    #include "Timer.h"
    ​
    //1.方法一:extern是关键字,跨文件去寻找这个变量。其他文件也定义了这个,这个就相当于另外文件的引用。
    //2.方法二:将中断函数放到main来即可。
    //extern uint16_t Num;
    uint16_t Num;
    ​
    int main(void)
    {
        OLED_Init();
        Timer_Init();
        OLED_ShowString(1,1,"Num:");
        OLED_ShowString(2,1,"CNT:");
        while(1)
        {
            OLED_ShowNum(1,5,Num,5);
            //查看CNT计数器值的变化情况,0-自动重装值(我这里是10000-1)
            //OLED_ShowNum(2,5,TIM_GetCounter(TIM2), 5);
            OLED_ShowNum(2,5,Timer_GetCounter(),5);
        }
    }
    ​
    void TIM2_IRQHandler(void)
    {
        if(TIM_GetITStatus(TIM2 , TIM_IT_Update) == SET)  //更新中断
        {
            Num++;
            //最后中断都是清除标志位
            TIM_ClearITPendingBit(TIM2 , TIM_IT_Update);
        }   
    }    

    作者:m0_48261292

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32——9.TIM定时中断

    发表回复