STM32定时器基础与应用:从配置到实战

📅 2026/7/18 9:31:33
STM32定时器基础与应用:从配置到实战
1. STM32定时器基础概念与分类STM32系列微控制器内置了多种定时器资源根据功能复杂度可分为三大类基本定时器(TIM6/TIM7)16位向上计数器仅支持定时功能无外部IO接口典型应用系统时钟基准、简单延时通用定时器(TIM2-TIM5)16位可向上/向下计数支持PWM输出、输入捕获每个定时器4个外部IO典型应用电机控制、信号测量高级定时器(TIM1/TIM8)包含通用定时器所有功能支持三相电机互补输出每个定时器8个外部IO典型应用变频器、复杂PWM控制注意不同STM32子系列定时器配置可能不同使用前需查阅对应型号的参考手册。2. 基本定时器功能实现详解2.1 时钟源配置STM32定时器时钟源来自APB1总线基本定时器挂载在APB1时钟配置需注意// 使能TIM6时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);时钟路径 APB1预分频器 → 定时器时钟(TIMxCLK) → 预分频器(PSC) → 计数器时钟(CK_CNT)计算公式 CK_CNT TIMxCLK / (PSC 1)例如APB1时钟为36MHz预分频系数2时 TIMxCLK 36MHz × 2 72MHz 若PSC71则CK_CNT 72MHz / (711) 1MHz2.2 定时器初始化结构体标准库使用TIM_TimeBaseInitTypeDef结构体配置定时器typedef struct { uint16_t TIM_Prescaler; // 预分频值 (0-65535) uint16_t TIM_CounterMode; // 计数模式(基本定时器只能向上) uint32_t TIM_Period; // 自动重装载值(0-65535) uint16_t TIM_ClockDivision; // 时钟分频(基本定时器无此功能) uint8_t TIM_RepetitionCounter; // 重复计数器(高级定时器专用) } TIM_TimeBaseInitTypeDef;基本定时器只需配置TIM_Prescaler和TIM_Period两个成员。2.3 定时时间计算定时时间公式 T (ARR 1) × (PSC 1) / TIMxCLK示例实现1ms定时TIMxCLK 72MHz设置PSC71 → CK_CNT1MHz设置ARR999 → 中断周期(9991)/1MHz1ms3. 完整代码实现与解析3.1 硬件设计本例使用TIM6实现1秒定时控制LED闪烁硬件连接LED连接任意GPIO(如PA5)无需外部电路仅使用MCU内部资源3.2 软件实现3.2.1 定时器配置void TIM6_Config(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; // 使能TIM6时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); // 定时器基础配置 TIM_TimeBaseStructure.TIM_Period 999; // 自动重装载值 TIM_TimeBaseStructure.TIM_Prescaler 71999; // 预分频值 TIM_TimeBaseInit(TIM6, TIM_TimeBaseStructure); // 清除更新中断标志 TIM_ClearFlag(TIM6, TIM_FLAG_Update); // 使能更新中断 TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE); // 启动定时器 TIM_Cmd(TIM6, ENABLE); }配置说明时钟72MHz预分频71999 → CK_CNT72MHz/720001kHzARR999 → 中断周期1kHz/10001s3.2.2 中断优先级配置void TIM6_NVIC_Config(void) { NVIC_InitTypeDef NVIC_InitStructure; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); NVIC_InitStructure.NVIC_IRQChannel TIM6_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority 1; NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE; NVIC_Init(NVIC_InitStructure); }3.2.3 中断服务程序volatile uint32_t timerCount 0; // 全局计时变量 void TIM6_IRQHandler(void) { if (TIM_GetITStatus(TIM6, TIM_IT_Update) ! RESET) { timerCount; TIM_ClearITPendingBit(TIM6, TIM_FLAG_Update); } }3.2.4 主函数实现int main(void) { // 初始化LED GPIO LED_Init(); // 配置定时器 TIM6_Config(); TIM6_NVIC_Config(); while (1) { if (timerCount 1) { // 1秒到达 timerCount 0; LED_Toggle(); // 翻转LED状态 } } }4. 进阶应用与问题排查4.1 精确延时实现利用定时器实现微秒级延时函数void Delay_us(uint32_t us) { TIM6-CNT 0; // 计数器清零 TIM6-ARR us - 1; // 设置重装载值 TIM_Cmd(TIM6, ENABLE); // 启动定时器 while (!TIM_GetFlagStatus(TIM6, TIM_FLAG_Update)); // 等待更新标志 TIM_ClearFlag(TIM6, TIM_FLAG_Update); // 清除标志 TIM_Cmd(TIM6, DISABLE); // 关闭定时器 }4.2 常见问题排查定时器不工作检查时钟是否使能验证APB1预分频系数确认TIM_Cmd()已调用中断不触发检查NVIC配置确认TIM_ITConfig()已使能中断确保中断服务程序名称正确定时时间不准确检查时钟树配置确认PSC和ARR计算正确考虑中断响应延迟调试技巧在中断服务程序中设置断点通过查看CNT寄存器值验证定时器是否正常运行。5. 不同场景下的配置建议5.1 短时间定时us级使用较高的CK_CNT频率减小PSC设置较小的ARR值考虑直接查询标志位代替中断5.2 长时间定时秒级使用较大的PSC值降低CK_CNT结合软件计数器扩展定时范围启用中断处理5.3 低功耗应用选择RUN模式下可用的最低时钟频率合理配置自动唤醒功能考虑使用RTC替代定时器通过本文的详细讲解和代码实现开发者可以快速掌握STM32基本定时器的使用方法并能够根据实际需求进行灵活配置和应用扩展。