第一次接触STM32定时器时,我完全被那些专业术语搞懵了。后来才发现,理解定时器最好的方式就是从我们最熟悉的软件延时开始对比。还记得刚学单片机时写的那个经典延时函数吗?
c复制void delay_us(uint32_t us) {
us *= 72;
while(us--);
}
这个函数虽然简单,但存在三个致命问题:首先CPU完全被占用,不能执行其他任务;其次延时精度受系统时钟和编译器优化影响;最后在多任务系统中会引发调度问题。而硬件定时器完美解决了这些痛点。
STM32的定时器本质是一个带自动重载功能的计数器,它的核心工作原理就像沙漏:
计算定时时间的公式很简单:
code复制定时时间 = (ARR + 1) × (PSC + 1) / 时钟频率
举个例子,要实现1秒定时(时钟72MHz):
基本定时器(TIM6/TIM7)是STM32定时器家族中最简单的成员,特别适合初学者入门。我以TIM6实现500ms定时中断为例,分享具体配置步骤:
c复制TIM_HandleTypeDef htim6;
htim6.Instance = TIM6;
htim6.Init.Prescaler = 7199; // 72MHz/(7199+1)=10KHz
htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
htim6.Init.Period = 4999; // 10KHz下5000次计数=500ms
htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
c复制void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if(htim->Instance == TIM6) {
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
}
}
实际调试时我踩过一个坑:如果发现定时不准,检查以下三点:
通用定时器(TIM2-TIM5)的强大之处在于PWM生成能力。我曾用TIM3制作呼吸灯效果,关键配置如下:
PWM模式配置要点:
c复制TIM_OC_InitTypeDef sConfigOC;
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 250; // 初始占空比50%
sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1);
动态调节占空比:
c复制// 在main循环中渐变占空比
for(int i=0; i<=500; i++) {
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, i);
HAL_Delay(10);
}
硬件连接注意事项:
实测发现,PWM频率选择有讲究:
高级定时器(TIM1/TIM8)在电机控制中大显身手,主要体现在三个核心功能:
H桥电路需要互补的PWM信号,但功率器件开关需要时间,这时死区时间就至关重要。配置代码示例:
c复制TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig;
sBreakDeadTimeConfig.DeadTime = 100; // 约5.56us
sBreakDeadTimeConfig.BreakState = TIM_BREAK_ENABLE;
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig);
紧急情况下需要立即停止PWM输出,刹车功能就是为此设计的:
c复制// 配置刹车输入引脚(通常连接过流检测电路)
// 发生刹车时自动关闭输出,并触发中断
void HAL_TIMEx_BreakCallback(TIM_HandleTypeDef *htim) {
// 执行安全处理程序
}
输出指定数量的PWM脉冲在步进电机控制中很实用:
c复制htim1.Init.RepetitionCounter = 99; // 输出100个脉冲后停止
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
在无刷电机控制项目中,我将这三个功能结合使用:
实际项目中,我经常组合使用多个定时器实现复杂功能:
案例1:高精度脉冲捕获
案例2:多通道同步采样
案例3:编码器接口
c复制TIM_Encoder_InitTypeDef sConfig;
sConfig.EncoderMode = TIM_ENCODERMODE_TI12;
sConfig.IC1Polarity = TIM_ICPOLARITY_RISING;
sConfig.IC2Polarity = TIM_ICPOLARITY_RISING;
HAL_TIM_Encoder_Init(&htim4, &sConfig);
这种配置下,定时器会自动根据编码器脉冲方向和数量更新计数值。
调试多定时器系统时,我总结了几点经验: