STM32定时器知识全面总结:从基础到高级应用
一、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 回调中处理。
更多推荐



所有评论(0)