一、STM32定时器概述

        定时器(Timer)是STM32微控制器中功能最丰富、应用最广泛的外设之一。它不仅是简单的计时工具,更是实现PWM输出、输入捕获、编码器接口、事件触发等复杂功能的核心模块。STM32系列根据型号不同,集成了多种类型的定时器,包括基本定时器、通用定时器和高级定时器。

二、定时器类型与特性

1. 基本定时器(TIM6/TIM7)

  • 功能特点:仅支持向上计数,主要用于时基生成和DAC触发
  • 时钟源:内部时钟(CK_INT)
  • 主要寄存器:TIMx_ARR(自动重装载寄存器)、TIMx_PSC(预分频器)
  • 应用场景:系统滴答定时、简单延时、DAC转换触发

2. 通用定时器(TIM2-TIM5, TIM9-TIM14)

  • 功能特点:支持向上/向下/中央对齐计数,具备输入捕获、输出比较、PWM生成功能
  • 时钟源:内部时钟、外部时钟模式1/2、内部触发输入
  • 通道数量:通常4个独立通道(TIM2-TIM5)
  • 应用场景:电机控制、测量脉冲宽度、频率测量、PWM信号生成

3. 高级定时器(TIM1/TIM8)

  • 功能特点:在通用定时器基础上增加互补输出、死区插入、刹车功能
  • 特殊功能:支持六步PWM、紧急刹车、重复计数器
  • 应用场景:三相电机控制、数字电源、高级PWM应用

三、定时器基本概念

1. 时钟源与预分频

定时器的时钟源可以来自:

  • 内部时钟(CK_INT):APB总线时钟,最常见的选择
  • 外部时钟模式1:外部引脚输入(TIx)
  • 外部时钟模式2:外部触发输入(ETR)
  • 内部触发输入:其他定时器作为主模式触发

预分频器(PSC)将输入时钟分频,得到计数器实际计数时钟:CK_CNT = CK_PSC / (PSC + 1)

2. 计数模式

  • 向上计数模式:从0计数到ARR值,然后产生更新事件并重新从0开始
  • 向下计数模式:从ARR值向下计数到0,产生更新事件
  • 中央对齐模式:先向上计数到ARR,再向下计数到0

3. 自动重装载寄存器(ARR)

ARR决定了计数器的周期,当计数器值达到ARR时(向上计数)或从ARR减到0时(向下计数),会产生更新事件(UEV)。

4. 计数器分辨率与频率计算

定时器溢出时间计算公式:Tout = (ARR + 1) * (PSC + 1) / Tclk

其中Tclk为定时器输入时钟频率。

四、基本定时器

        基本定时器执行的是最基本的定时过程,包括ARR、PSC、CNT等寄存器的使用,其基本的实现流程可看下图:

        值得注意的是,其实如果单纯计数的作用不需要控制预分频器,但是由于自动重装载寄存器和预分频器均是16位的寄存器,所以要保证可计数的时间,需要将内部时钟提前进行分频,当CNT计数到ARR时溢出产生更新事件。

        同时由于预分频器和自动重装载寄存器均有影子寄存器,所以其实其中作用的是影子寄存器,起到缓冲的作用,如果不使用影子寄存器,当改变ARR和PSC的值会立刻生效,但当影子寄存器存在时,更改不会立刻生效,而是在执行完一次更新事件中断之后才会生效。

五、通用定时器

1. 基本原理框图

        相较于基本定时器,通用定时器增加了计数方式,输入捕获模式,以及输出比较模式(PWM模式)。相对应的其中的控制模式更加多样,除了内部时钟模式,还有两种外部时钟的模式,其中的具体的原理如下图:

对于外部时钟1的CubeMx配置:

对于外部时钟2的CubeMx配置:

2. 输入捕获

        是通用定时器的重要功能之一,用于精确测量外部信号的脉冲宽度、周期或频率。其核心原理是:当检测到输入引脚上指定边沿(上升沿或下降沿)时,将当前计数器的值锁存到对应的捕获/比较寄存器(CCRx)中,通过读取两次捕获值的时间差即可计算出脉宽或周期。其中两次读取是通过直接捕获和间接捕获来实现的。比如要计算高电平持续时间:首先直接捕获上升沿时,通过TI1FP1通过预分频器,最后进入捕获寄存器中存储,对于间接捕获,通过TI1FP2来捕获下降沿的时刻到捕获寄存器2中储存,且可引发中断及时读取,两者之差即为高电平持续时间。用TI2FP2和TI2FP1是相同的原理。

3. 输出比较

        有多种模式:冻结模式、强制有效、强制无效、匹配时有效、匹配时无效、匹配时翻转(了解即可)

        最常用的模式PWM模式:其中PWM可分为两种PWM1和PWM2两种,两种原理相同,比较相反即可。对于PWM的模式下,涉及一个新的寄存器(CCR输出比较寄存器)。在PWM1模式下,当计数的CNT<CCR设置的数值时,输出高电平,相反则输出低电平。该方法即为控制PWM的占空比的方法,也可计算其中的周期T,通过总的内部时钟频率(APB1)的除(PSC+1)即为分频之后的频率,取倒数可求周期,再用这个时间来成(ARR+1)得出的结果就是PWM的一个周期。

4. 编码器模式

AB相的编码器,CubeMx会有专门的编码器模式:

        A相和B相一般会有90的相位差,对于上下两相可知,当边沿的时候会进行读取,但有个问题就是当A相为下降沿时,B相为低电平时,编码器加一;A相为上升沿时,B相为高电平时,编码器又加一,所以其实会造成两次计数,最后读取的值应除二为结果。并将AB两相分别接到TI1和TI2之上就可以实现编码计数的功能。

六、高级定时器

        高级定时器(TIM1/TIM8)是STM32定时器家族中功能最强大的成员,相较于通用定时器,增加了重复计数器、互补输出比较、断路的选择。

1. 重复计数器功能

重复计数器(RCR)允许定时器在多次计数周期后才产生更新事件:

  • 减少中断频率:当RCR=N时,每N+1个周期才产生一次更新中断
  • 应用场景:高频率PWM生成时减少CPU中断负载
  • 配置方法:通过TIMx_RCR寄存器设置重复计数值

2. 互补输出与死区控制

互补输出是高级定时器最重要的特性之一,常用于驱动H桥电路

  • 互补通道对:CH1/CH1N、CH2/CH2N、CH3/CH3N(加N为互补通道)
  • 死区时间:通过DTG寄存器配置,防止上下管同时导通
  • 输出极性:可独立配置每个通道的有效电平极性
  • 刹车保护:当刹车输入有效时,所有输出进入安全状态

死区时间计算公式:Tdt = (DTG[7:5] × tdtg + DTG[4:0]) × tdts(可查数据手册)

    3. 刹车输入与保护机制

    刹车功能是高级定时器的安全特性:

    • 刹车源:外部刹车输入引脚、内部比较器输出、系统故障
    • 刹车响应:立即关闭所有输出通道,进入安全状态
    • 刹车极性:可配置为高电平有效或低电平有效
    • 自动恢复:刹车条件解除后可自动或手动恢复输出

    七、HAL库定时器编程示例

    其中大部分的内容均可又CubeMx中来自动生成,了解原理,学习调用函数即可。

    1. 基本定时器配置(1ms中断)

    // 定时器6初始化,生成1ms中断
    TIM_HandleTypeDef htim6;
    
    void MX_TIM6_Init(void)
    {
        htim6.Instance = TIM6;
        htim6.Init.Prescaler = 90 - 1;      // 90MHz/90 = 1MHz
        htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
        htim6.Init.Period = 1000 - 1;       // 1MHz/1000 = 1kHz (1ms)
        htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
        if (HAL_TIM_Base_Init(&htim6) != HAL_OK)
        {
            Error_Handler();
        }
        
        // 使能更新中断
        HAL_TIM_Base_Start_IT(&htim6);
    }
    
    // 中断回调函数
    void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
    {
        if (htim->Instance == TIM6)
        {
            // 1ms定时任务
            ms_tick++;
        }
    }

    2. PWM输出配置(通道1输出50%占空比)

    // TIM2通道1输出PWM,频率1kHz,占空比50%
    TIM_HandleTypeDef htim2;
    TIM_OC_InitTypeDef sConfigOC = {0};
    
    void MX_TIM2_Init(void)
    {
        // 时基配置
        htim2.Instance = TIM2;
        htim2.Init.Prescaler = 90 - 1;      // 90MHz/90 = 1MHz
        htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
        htim2.Init.Period = 1000 - 1;       // 1MHz/1000 = 1kHz
        htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
        htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
        HAL_TIM_PWM_Init(&htim2);
        
        // PWM通道配置
        sConfigOC.OCMode = TIM_OCMODE_PWM1;
        sConfigOC.Pulse = 500;              // 占空比50% (500/1000)
        sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
        sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
        HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1);
        
        // 启动PWM输出
        HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
    }

    3. 输入捕获测量脉冲宽度

    // TIM3通道1输入捕获,测量高电平脉宽
    TIM_HandleTypeDef htim3;
    uint32_t capture_value1 = 0, capture_value2 = 0;
    uint32_t pulse_width = 0;
    
    void MX_TIM3_Init(void)
    {
        // 时基配置
        htim3.Instance = TIM3;
        htim3.Init.Prescaler = 90 - 1;      // 90MHz/90 = 1MHz (1us分辨率)
        htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
        htim3.Init.Period = 0xFFFFFFFF;     // 32位计数器
        htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
        HAL_TIM_IC_Init(&htim3);
        
        // 输入捕获配置
        TIM_IC_InitTypeDef sConfigIC;
        sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;  // 上升沿捕获
        sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
        sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
        sConfigIC.ICFilter = 0;
        HAL_TIM_IC_ConfigChannel(&htim3, &sConfigIC, TIM_CHANNEL_1);
        
        // 启动输入捕获中断
        HAL_TIM_IC_Start_IT(&htim3, TIM_CHANNEL_1);
    }
    
    // 捕获中断回调
    void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
    {
        if (htim->Instance == TIM3)
        {
            if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
            {
                static uint8_t capture_stage = 0;
                
                if (capture_stage == 0)
                {
                    // 第一次捕获(上升沿)
                    capture_value1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
                    // 改为下降沿捕获
                    __HAL_TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_FALLING);
                    capture_stage = 1;
                }
                else if (capture_stage == 1)
                {
                    // 第二次捕获(下降沿)
                    capture_value2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
                    pulse_width = capture_value2 - capture_value1;  // 计算脉宽(us)
                    // 恢复上升沿捕获
                    __HAL_TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_RISING);
                    capture_stage = 0;
                }
            }
        }
    }

    八、总结

            STM32定时器通过预分频器(PSC)和自动重装载寄存器(ARR)实现精准定时,实际分频系数为 (PSC+1),计数周期为 (ARR+1),中断频率 = 定时器时钟 / [(PSC+1) × (ARR+1)]。它分为基本、通用和高级三类,支持向上、向下及中央对齐计数模式,可工作在定时更新、输出比较、PWM输出、输入捕获和编码器接口等模式。HAL 库中通过配置 TIM_HandleTypeDef 及相应模式结构体并调用 HAL_TIM_xxx_Init 和 _Start 系列函数启动,更新事件中断需要重新写弱定义的中断回调函数,在 HAL_TIM_PeriodElapsedCallback 回调中处理。

    Logo

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

    更多推荐