STM32(六):TIMER定时器进阶应用(标准库函数) 1. TIMER定时器进阶功能概览STM32的定时器远不止基础计时这么简单就像瑞士军刀除了刀刃还有各种隐藏工具。我最初用定时器只是做简单的延时后来发现它还能玩出这么多花样。通用定时器TIM2-TIM5这几个家伙每个都像多面手能干不少技术活。最常用的进阶功能有两个PWM输出和输入捕获。PWM就像调光开关通过调节占空比控制设备功率。我做智能灯项目时就靠它实现呼吸灯效果。输入捕获则像秒表功能可以精确测量脉冲宽度。上次做转速检测就是靠它捕捉电机编码器信号。定时器内部结构其实很有意思。拿TIM3来说它有个16位自动重装载寄存器(ARR)就像水桶的刻度线预分频器(PSC)像是调节水流速度的阀门。当计数器(CNT)这个水位线涨到ARR设定值时就会触发溢出事件。这个机制构成了所有高级功能的基础。2. PWM信号生成实战2.1 PWM原理与配置要点PWM本质上是通过调节高低电平比例来控制能量输出。就像用快速开关的水龙头开得久出水量就大。在STM32中每个通用定时器有4个独立通道可以输出PWM高级定时器还能输出互补带死区的PWM。配置时要注意三个关键参数时钟源通常用内部72MHz时钟经过预分频得到计数频率ARR值决定PWM周期比如设为1000就是计数到1000溢出CCRx值比较寄存器决定占空比。当CNTCCRx输出高电平void TIM3_PWM_Init(u16 arr,u16 psc) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // PB5(TIM3_CH2)配置 GPIO_InitStructure.GPIO_Pin GPIO_Pin_5; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOB, GPIO_InitStructure); TIM_TimeBaseStructure.TIM_Period arr; TIM_TimeBaseStructure.TIM_Prescaler psc; TIM_TimeBaseStructure.TIM_ClockDivision 0; TIM_TimeBaseStructure.TIM_CounterMode TIM_CounterMode_Up; TIM_TimeBaseInit(TIM3, TIM_TimeBaseStructure); TIM_OCInitStructure.TIM_OCMode TIM_OCMode_PWM2; TIM_OCInitStructure.TIM_OutputState TIM_OutputState_Enable; TIM_OCInitStructure.TIM_OCPolarity TIM_OCPolarity_High; TIM_OC2Init(TIM3, TIM_OCInitStructure); TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); TIM_Cmd(TIM3, ENABLE); }2.2 呼吸灯实现技巧用PWM做呼吸灯时直接线性改变占空比会有突兀感。我推荐使用正弦曲线变化效果更自然。可以预先计算好亮度值存入数组uint16_t breathTable[100]; for(int i0; i100; i){ breathTable[i] (uint16_t)((sin(i*3.14/100)1) * 500); }然后在主循环中动态修改CCR值while(1){ for(int i0; i100; i){ TIM_SetCompare2(TIM3, breathTable[i]); Delay_ms(20); } }调试时遇到过PWM输出异常的问题后来发现是GPIO没有重映射。TIM3_CH2默认在PA7我的板子接在PB5需要开启部分重映射GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);3. 输入捕获高级应用3.1 脉宽测量方案对比测量脉冲宽度有三种常用方法输入捕获精度最高适合高频信号外部中断定时器实现简单但占用资源PWM输入模式自动测量占空比和周期输入捕获模式下定时器会在信号边沿时冻结当前计数值。就像运动会终点的高速摄像机能准确记录冲线瞬间的时间戳。配置时要注意选择正确的触发边沿上升沿/下降沿开启捕获中断处理计数器溢出情况void TIM4_Cap_Init(u16 arr,u16 psc) { TIM_ICInitTypeDef TIM_ICInitStructure; // 时基初始化...同PWM配置 TIM_ICInitStructure.TIM_Channel TIM_Channel_2; TIM_ICInitStructure.TIM_ICPolarity TIM_ICPolarity_Rising; TIM_ICInitStructure.TIM_ICSelection TIM_ICSelection_DirectTI; TIM_ICInitStructure.TIM_ICPrescaler TIM_ICPSC_DIV1; TIM_ICInitStructure.TIM_ICFilter 0x00; TIM_ICInit(TIM4, TIM_ICInitStructure); TIM_ITConfig(TIM4,TIM_IT_CC2,ENABLE); TIM_Cmd(TIM4, ENABLE); }3.2 高精度转速测量我在直流电机测速项目中用编码器输出脉冲到TIM4_CH2。通过测量两个上升沿之间的时间差计算转速。关键是要处理计数器溢出u32 captureCount 0; float rpm 0; void TIM4_IRQHandler(void) { static u32 lastCapture 0; if(TIM_GetITStatus(TIM4, TIM_IT_CC2) SET){ u32 currentCapture TIM_GetCapture2(TIM4); if(currentCapture lastCapture){ captureCount currentCapture - lastCapture; }else{ captureCount (0xFFFF - lastCapture) currentCapture; } lastCapture currentCapture; rpm 60.0 / (captureCount * (1.0/72000000) * 20); //20是编码器线数 TIM_ClearITPendingBit(TIM4, TIM_IT_CC2); } }实测发现当转速过高时会出现测量误差。解决方法是将预分频系数设为71这样计数器频率降为1MHz可测量范围扩大到65ms。4. 定时器中断组合应用4.1 多定时器协同工作复杂系统经常需要多个定时器配合。比如我用TIM2做1ms系统时钟基准TIM3输出PWM控制电机TIM4测量转速。关键是要合理分配中断优先级NVIC_InitTypeDef NVIC_InitStructure; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // TIM2中断最高优先级 NVIC_InitStructure.NVIC_IRQChannel TIM2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority 0; NVIC_Init(NVIC_InitStructure); // TIM4中断 NVIC_InitStructure.NVIC_IRQChannel TIM4_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 1; NVIC_Init(NVIC_InitStructure);4.2 定时器级联技巧需要更长定时周期时可以将定时器串联。比如让TIM2作为主定时器TIM3作为从定时器// TIM2主模式配置 TIM_SelectMasterSlaveMode(TIM2, TIM_MasterSlaveMode_Enable); TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update); // TIM3从模式配置 TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_External1); TIM_SelectInputTrigger(TIM3, TIM_TS_ITR1);这样TIM2每次溢出都会触发TIM3计数相当于扩展成32位定时器。我在需要小时级定时的环境监测设备中就采用这种方案。5. 常见问题排查指南调试定时器时最容易遇到的几个坑时钟未使能忘记开启APB1时钟TIM2-TIM5或APB2时钟TIM1/TIM8RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);GPIO模式错误PWM输出需要配置为复用推挽输出GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP;中断未清除标志导致重复进入中断TIM_ClearITPendingBit(TIM4, TIM_IT_CC2);ARR值设置过小导致PWM频率超出硬件限制寄存器未生效修改CCR/ARR等寄存器后需要有时基更新TIM_GenerateEvent(TIM3, TIM_EventSource_Update);遇到异常时建议按以下步骤排查用示波器检查PWM输出波形在中断入口加调试灯检查寄存器值是否符合预期确认时钟树配置正确