用STM32F103C8T6的TIM1捕获PWM信号:CubeMX配置+中断处理全流程(附串口打印代码)
STM32F103C8T6实战TIM1捕获PWM信号的全流程解析与避坑指南在嵌入式开发中精确测量PWM信号的频率和占空比是常见需求。无论是调试舵机控制、电机驱动还是与其他MCU通信这项技能都至关重要。本文将手把手带你用STM32F103C8T6BluePill开发板常用芯片的高级定时器TIM1实现PWM信号捕获从CubeMX配置到代码实现再到实际调试技巧完整呈现一个工业级解决方案。1. 硬件准备与CubeMX基础配置1.1 硬件连接要点在开始软件配置前确保硬件连接正确PWM信号源连接到TIM1_CH1PA8引脚确保共地连接信号电压不超过3.3V如需测量5V信号需分压注意TIM1是STM32F103的高级定时器相比通用定时器具有更丰富的功能特别适合PWM测量这种需要精确时序控制的应用。1.2 CubeMX关键配置步骤时钟配置系统时钟设为72MHzTIM1时钟源APB2预分频器保持/1确保TIM1时钟为72MHzTIM1配置// 定时器基础配置参数 Prescaler 71 // 72MHz/(711) 1MHz计数频率 Counter Mode Up Period (ARR) 30000 // 30ms最大测量周期 Auto-reload preload Enable输入捕获设置Channel 1 → Input Capture direct modeIC1 Filter 0x0无滤波IC1 Prescaler 0x0每个边沿都捕获中断配置使能TIM1更新中断和捕获中断设置适当的中断优先级建议高于系统滴答定时器串口配置用于输出结果选择USART1PA9-TX, PA10-RX波特率1152008N1模式2. 工程代码深度解析2.1 全局变量定义与初始化在main.c中添加以下变量// 测量相关变量 #define CNT_CLK 1000000 // 1MHz (72MHz/(711)) #define ARR_VAL 30000 // 与CubeMX配置一致 volatile uint32_t ccr_val1, ccr_val2; // 捕获值存储 volatile uint32_t overflow_cnt 0; // 溢出计数 volatile uint8_t capture_stage 0; // 捕获阶段标志 volatile uint8_t measurement_ready 0; // 测量完成标志 float frequency_hz 0.0f; // 计算得到的频率 float duty_cycle_percent 0.0f; // 计算得到的占空比提示使用volatile关键字确保中断与主循环间变量同步。2.2 定时器启动与主循环处理在main函数中添加// 启动定时器及其中断 HAL_TIM_Base_Start_IT(htim1); HAL_TIM_IC_Start_IT(htim1, TIM_CHANNEL_1); while (1) { if (measurement_ready) { // 计算频率和占空比 uint32_t total_period overflow_cnt * (ARR_VAL 1) ccr_val2 1; frequency_hz (float)CNT_CLK / total_period; duty_cycle_percent (float)(overflow_cnt * (ARR_VAL 1) ccr_val1 1) * 100 / total_period; // 通过串口输出结果 printf(Freq: %.2f Hz, Duty: %.2f%%\r\n, frequency_hz, duty_cycle_percent); measurement_ready 0; // 重置标志 } HAL_Delay(100); // 控制输出频率 }2.3 中断回调函数实现这是整个系统的核心逻辑处理边沿捕获和计数器溢出void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim-Instance TIM1) { overflow_cnt; // 记录溢出次数 } } void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) { if (htim-Instance ! TIM1) return; switch (capture_stage) { case 0: // 第一个上升沿 __HAL_TIM_SET_COUNTER(htim, 0); // 重置计数器 overflow_cnt 0; // 重置溢出计数 __HAL_TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_FALLING); capture_stage 1; break; case 1: // 第一个下降沿 ccr_val1 HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); __HAL_TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_RISING); capture_stage 2; break; case 2: // 第二个上升沿 ccr_val2 HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); __HAL_TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_FALLING); capture_stage 0; measurement_ready 1; // 测量完成 break; } }3. 关键参数计算与优化3.1 定时器参数设计原理定时器配置的核心是平衡测量精度和范围预分频器(PSC)决定定时器计数频率计数频率 定时器时钟 / (PSC 1) 例72MHz/(711) 1MHz → 每个计数1μs自动重装载值(ARR)决定最大可测量周期最大测量周期 (ARR 1) / 计数频率 例30000/1MHz 30ms → 最小可测频率≈33Hz3.2 测量范围与精度权衡配置参数高精度模式宽范围模式PSC0 (72MHz)719 (100kHz)ARR6553565535时间分辨率13.89ns10μs最大测量周期0.91ms655ms适用场景高频PWM(1kHz)低频PWM(100Hz)提示实际项目中可根据预期信号频率动态调整这些参数。4. 常见问题与调试技巧4.1 硬件连接问题排查无信号输入检查PA8引脚连接用示波器确认信号源正常确认共地连接测量值不稳定增加输入捕获滤波器CubeMX中IC1 Filter检查电源稳定性缩短信号线长度4.2 软件调试技巧中断优先级配置确保TIM1中断优先级高于其他可能阻塞的中断在CubeMX中检查NVIC设置printf重定向 确保已实现串口输出int __io_putchar(int ch) { HAL_UART_Transmit(huart1, (uint8_t *)ch, 1, HAL_MAX_DELAY); return ch; }实时调试使用ST-Link和STM32CubeIDE的实时变量监控在关键位置设置断点观察变量变化4.3 特殊场景处理高频PWM测量优化// 对于10kHz的PWM可减少ARR值提高效率 #define ARR_VAL 10000 // 10ms最大周期低频PWM测量优化// 对于100Hz的PWM增加PSC值扩展测量范围 htim1.Init.Prescaler 719; // 100kHz计数频率多通道同时测量 TIM1支持最多4个输入捕获通道可通过类似方法配置其他通道注意每个通道需要独立的变量存储捕获值中断回调中需判断触发通道增加处理逻辑复杂度