目录
[一、STM32 定时器分类与层级](#一、STM32 定时器分类与层级)
[四、普通 PWM 输出实战(呼吸灯、调速、调压)](#四、普通 PWM 输出实战(呼吸灯、调速、调压))
[六、高级定时器互补 PWM + 死区时间(电机、电源必备)](#六、高级定时器互补 PWM + 死区时间(电机、电源必备))
前言
本篇回归单片机最核心、最高频、最万能的外设 ------ 通用定时器。
定时器是单片机的心脏:延时、定时中断、毫秒系统节拍、电机 PWM、LED 呼吸灯、输入捕获测速、脉宽测量、电源互补推挽、死区控制,全部依赖定时器。
很多新手只会简单 HAL_Delay、定时中断,但是:
- 不会配置精准 PWM、输出波形抖动
- 输入捕获测速数据跳动
- 互补 PWM 烧 MOS 管、死区配置不会
- 定时器时钟看不懂、分频乱配导致频率错误
- 多定时器冲突、抢占混乱
本篇一次性讲透:定时中断、基础计数、标准 PWM、输入捕获、互补 PWM、死区时间、工程避坑、时钟架构,全部配套可直接量产代码。
一、STM32 定时器分类与层级
STM32 定时器分为三类,用途完全不同:
- 基本定时器(TIM6/TIM7) 只定时、无 IO 功能、纯中断,适合系统计时、任务节拍。
- 通用定时器(TIM2/3/4/5) 最常用!支持定时中断、PWM 输出、输入捕获、任意通道复用,90% 项目全靠它。
- 高级定时器(TIM1/TIM8) 带互补 PWM、死区时间、刹车保护,专用于电机、逆变器、大功率开关电源。
工程准则:普通 PWM 用通用定时器,电机电源必须用高级定时器。
二、定时器核心计算公式(必考、万能公式)
所有定时器配置只靠这一条公式:
定时频率 = 定时器时钟 / (预分频 + 1) / (自动重装载值 + 1)
- 预分频:缩小时钟频率
- 自动重装载值:计数最大值
- 这两个参数决定:中断周期、PWM 频率、捕获精度
新手所有定时不准、PWM 频率错误,全是公式带入错误。
三、基础定时中断(系统节拍、周期任务)
适合:定时扫描按键、定时刷新屏幕、100ms 周期任务、状态机轮询
配置思路
72MHz 定时器时钟,分频 72,重装值 9999 得到:100Hz = 10ms 中断一次
void TIM3_Init(void)
{
TIM_HandleTypeDef htim3;
htim3.Instance = TIM3;
htim3.Init.Prescaler = 71;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 9999;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_Base_Init(&htim3);
HAL_TIM_Base_Start_IT(&htim3);
}
void TIM3_IRQHandler(void)
{
HAL_TIM_IRQHandler(&htim3);
}
//定时回调 10ms一次
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM3)
{
//周期任务
}
}
四、普通 PWM 输出实战(呼吸灯、调速、调压)
PWM 原理:固定频率、改变占空比 ARR 决定频率,CCR 值决定高电平时间
工程代码
//TIM2_CH1 PWM初始化
void TIM2_PWM_Init(uint16_t freq,uint16_t duty)
{
TIM_HandleTypeDef htim2;
TIM_OC_InitTypeDef sConfigOC = {0};
htim2.Instance = TIM2;
htim2.Init.Prescaler = 71;
htim2.Init.Period = 999; //72KHz基础频率
HAL_TIM_PWM_Init(&htim2);
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = duty; //占空比 0~999
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_1);
}
//动态修改占空比
void PWM_SetDuty(uint16_t duty)
{
__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_1,duty);
}
PWM1 模式:
- 计数器从 0→ARR
- CCR 值前高电平,后低电平
适合:LED 呼吸、风扇调速、电磁阀调压
五、输入捕获实战(测速、测频率、脉宽检测)
输入捕获是定时器最硬核、最常用的高级功能 用途:
- 霍尔电机测速
- 方波频率测量
- 遥控器 PPM 信号解析
- 超声波高精准计时
原理: 捕获上升沿记录时间,捕获下降沿记录时间,差值即为高电平脉宽
核心代码(脉宽捕获)
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM4)
{
if(g_edge_state == 0)
{
//上升沿
g_ic_start = HAL_TIM_ReadCapturedValue(&htim4,TIM_CHANNEL_1);
g_edge_state = 1;
}
else
{
//下降沿
g_ic_end = HAL_TIM_ReadCapturedValue(&htim4,TIM_CHANNEL_1);
g_pulse_width = g_ic_end - g_ic_start;
g_edge_state = 0;
}
}
}
优势:纯硬件捕获,不占用 CPU,精度远超软件延时读取
六、高级定时器互补 PWM + 死区时间(电机、电源必备)
普通 PWM 只有一路输出,不能驱动上下 MOS 管 上下管同时导通 = 电源短路 = 炸机
所以必须: 互补输出 + 死区时间
1、死区作用
上下管切换时,预留几 us 空白时间,确保上管完全关闭,下管再打开,杜绝直通短路
2、高级定时器关键配置
//高级定时器TIM1 互补PWM
htim1.Init.RepetitionCounter = 0;
//互补通道配置
sBreakConfig.BreakState = TIM_BREAK_DISABLE;
sBreakConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_ENABLE; //刹车解除自动输出
//设置死区时间 0~255
__HAL_TIM_SET_DEADTIME(&htim1,40);
- 死区值越大,安全越高,波形滞后越大
- 电机、逆变器必须开启自动输出
七、定时器九大高频踩坑点
- 分频公式算错:预分频是 (N+1),很多人直接填 N,频率翻倍
- 开启中断忘记清标志:进不停中断、卡死
- PWM 极性搞反:设备反向动作、呼吸灯反向
- 多定时器同时开启冲突:时钟总线混淆
- 输入捕获不开启中断:数据永远不更新
- 高级定时器不开启自动输出:上电无波形
- 没有死区直接推互补 PWM:直接炸 MOS 管
- 中断里写延时、浮点运算:导致系统卡顿
- 重装值为 0、分频为 0:定时器直接报错卡死
八、定时器工程选型总结
- 系统定时、周期任务 → 基本定时器
- 普通 PWM、呼吸灯、低速调速 → 通用定时器
- 测速、测频率、信号解析 → 通用定时器输入捕获
- 电机驱动、逆变电源、桥式电路 → 高级定时器互补 PWM + 死区