STM32F103C8T6定时器与PWM实战:从基础配置到超声波测距
1. STM32F103C8T6定时器基础入门STM32F103C8T6作为一款经典的Cortex-M3内核微控制器其定时器功能是嵌入式开发中最常用的外设之一。我第一次接触这款芯片时就被它灵活的定时器配置所吸引。不同于简单的51单片机定时器STM32的定时器更像是一个多功能瑞士军刀。这款芯片内置了4个定时器1个高级定时器(TIM1)和3个通用定时器(TIM2-TIM4)。每个定时器都是16位的最大计数值为65535。实际项目中我经常用TIM2来做基础定时功能因为它配置简单中断响应快。定时器的核心是时基单元由三部分组成预分频器(PSC)对72MHz主时钟进行分频计数器(CNT)根据分频后的时钟进行计数自动重装载寄存器(ARR)设定计数目标值举个例子如果要实现1ms定时可以这样计算 预分频值设为720-1即720分频这样计数器时钟72MHz/720100kHz ARR设为100-1定时时间(720*100)/72MHz1ms// 定时器初始化代码示例 TIM_TimeBaseInitTypeDef TIM_InitStruct; TIM_InitStruct.TIM_Prescaler 720-1; // 预分频值 TIM_InitStruct.TIM_Period 100-1; // 自动重装值 TIM_InitStruct.TIM_CounterMode TIM_CounterMode_Up; // 向上计数 TIM_TimeBaseInit(TIM2, TIM_InitStruct);2. PWM原理与配置实战PWM脉冲宽度调制是我在电机控制和LED调光中最常用的技术。它的核心是通过调节占空比来模拟不同电压输出。记得我第一次用PWM做呼吸灯时看着LED慢慢变亮又变暗那种成就感至今难忘。STM32的PWM配置有几个关键参数频率由ARR和PSC共同决定公式为72MHz/((PSC1)*(ARR1))占空比由CCR寄存器控制占空比CCR/(ARR1)极性决定有效电平是高还是低配置PWM输出需要以下步骤配置定时器基础时钟设置PWM模式通常用PWM模式1配置输出比较参数使能通道输出// PWM初始化代码片段 TIM_OCInitTypeDef PWM_InitStruct; PWM_InitStruct.TIM_OCMode TIM_OCMode_PWM1; PWM_InitStruct.TIM_OutputState TIM_OutputState_Enable; PWM_InitStruct.TIM_Pulse 50; // 初始占空比50% PWM_InitStruct.TIM_OCPolarity TIM_OCPolarity_High; TIM_OC1Init(TIM2, PWM_InitStruct);实际调试时我习惯先用示波器观察波形。曾经遇到过PWM输出不稳定的情况最后发现是GPIO没有配置为复用推挽输出模式。这个小细节让我调试了整整一个下午。3. 定时器控制LED闪烁实战用定时器控制LED闪烁是入门STM32的经典实验。虽然看起来简单但包含了定时器最核心的中断应用。我建议初学者从这个实验开始逐步理解定时器的工作机制。具体实现步骤配置GPIO为推挽输出模式初始化定时器时基单元使能更新中断配置NVIC中断优先级编写中断服务函数// LED闪烁的中断服务函数 void TIM2_IRQHandler(void) { if(TIM_GetITStatus(TIM2, TIM_IT_Update) ! RESET) { GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)(1-GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_0))); TIM_ClearITPendingBit(TIM2, TIM_IT_Update); } }调试技巧先用简单延时法测试LED电路是否正常逐步减小定时周期观察LED闪烁频率变化在中断函数中设置断点确认中断是否正常触发4. PWM呼吸灯完整实现呼吸灯效果是展示PWM威力的最佳案例。通过动态调整占空比可以让LED产生平滑的亮度变化。我在实际项目中常用这个效果作为设备状态指示。实现呼吸灯的关键点选择合适的PWM频率通常100Hz-1kHz设计亮度变化曲线线性或非线性控制占空比变化速度// 呼吸灯主循环代码 uint8_t brightness 0; int8_t direction 1; while(1) { TIM_SetCompare1(TIM2, brightness*brightness/255); // 非线性变化 brightness direction; if(brightness 0 || brightness 255) direction -direction; Delay_ms(10); }进阶技巧使用gamma校正使亮度变化更符合人眼感知采用查表法预存亮度曲线减少实时计算多个LED同步控制时注意时序优化5. PWM信号采集与分析采集PWM信号是调试和逆向工程中常用的技术。STM32的输入捕获功能可以精确测量PWM的周期和占空比。我曾经用这个功能成功解码了一个未知设备的控制信号。实现步骤配置定时器为输入捕获模式设置上升沿和下降沿触发在中断中记录捕获值计算周期和占空比// 输入捕获中断处理 void TIMx_IRQHandler(void) { if(TIM_GetITStatus(TIMx, TIM_IT_CC1) ! RESET) { static uint16_t lastCapture 0; uint16_t currentCapture TIM_GetCapture1(TIMx); period currentCapture - lastCapture; lastCapture currentCapture; TIM_OC1PolarityConfig(TIMx, TIM_ICPolarity_Falling); // 切换为下降沿捕获 } else if(TIM_GetITStatus(TIMx, TIM_IT_CC2) ! RESET) { pulseWidth TIM_GetCapture2(TIMx); TIM_OC2PolarityConfig(TIMx, TIM_ICPolarity_Rising); // 切换回上升沿捕获 } TIM_ClearITPendingBit(TIMx, TIM_IT_CC1 | TIM_IT_CC2); }调试经验信号抖动问题可以通过输入滤波解决高频率信号测量需要降低预分频值多通道捕获时注意中断优先级设置6. 超声波测距模块集成HC-SR04超声波模块是入门级距离测量的首选。通过STM32的定时器可以精确测量回波时间实现厘米级测距。我在智能小车避障系统中就采用了这个方案。硬件连接要点Trig引脚接普通GPIOEcho引脚接定时器输入捕获通道注意电平匹配HC-SR04是5V器件软件实现关键发送至少10us的Trig触发信号测量Echo引脚高电平持续时间计算距离距离(cm)高电平时间(us)/58// 超声波测距核心代码 float GetDistance(void) { GPIO_SetBits(TRIG_PORT, TRIG_PIN); Delay_us(20); GPIO_ResetBits(TRIG_PORT, TRIG_PIN); while(GPIO_ReadInputDataBit(ECHO_PORT, ECHO_PIN) RESET); TIM_SetCounter(TIMx, 0); while(GPIO_ReadInputDataBit(ECHO_PORT, ECHO_PIN) SET); uint32_t echoTime TIM_GetCounter(TIMx); return (float)echoTime / 58.0f; }实际应用技巧多次测量取平均值提高精度增加温度补偿提高测量准确性设置超时机制防止长时间等待注意最小测量距离限制约2cm7. 常见问题与调试技巧在STM32定时器应用开发中我踩过不少坑也积累了一些实用经验时钟配置问题确认APB1总线时钟是否正确TIM2-TIM4挂载在APB1检查时钟树配置特别是PLL倍频设置PWM输出异常GPIO必须配置为复用推挽输出检查TIMx重映射设置是否正确确认CCR寄存器值是否在有效范围内中断不触发NVIC优先级配置是否正确是否调用了TIM_ITConfig使能中断中断服务函数名称是否与启动文件一致输入捕获不准输入信号是否超过定时器最大频率是否开启了输入滤波器预分频值设置是否合理超声波测距不稳定确保供电电压稳定添加硬件滤波电路避免测量表面过于光滑的物体调试工具推荐逻辑分析仪观察PWM波形和时序ST-Link调试器单步调试和变量监控串口打印实时输出测量数据万用表检查电源和信号电平