STM32G474定时器TIMER进阶实战:从PWM生成到输入捕获全解析

张开发
2026/4/15 9:26:52 15 分钟阅读

分享文章

STM32G474定时器TIMER进阶实战:从PWM生成到输入捕获全解析
1. STM32G474定时器基础回顾STM32G474系列微控制器内置了丰富多样的定时器资源包括高级控制定时器、通用定时器、基本定时器以及高精度定时器HRTIM。其中通用定时器因其灵活性和适中的资源占用成为大多数嵌入式项目的首选。我刚开始接触STM32定时器时最困惑的就是如何理解那些专业术语——时基单元、预分频器、自动重载寄存器后来发现用生活中的水龙头比喻就很好理解预分频器就像调节水流大小的阀门计数器就像水表读数自动重载值就是水表转满一圈的刻度值。通用定时器的核心功能模块可以概括为四个部分时基单元包含16位/32位计数器、预分频器和自动重载寄存器时钟源支持内部时钟、外部触发和内部触发三种模式输入捕获用于测量外部信号的时间参数输出比较用于生成特定波形如PWM在实际项目中我特别喜欢使用STM32CubeMX来配置定时器它能直观地展示各个参数之间的关系。比如配置1ms定时中断时只需要输入期望的周期值工具会自动计算ARR和PSC的最佳组合避免了手动计算的繁琐和错误。2. PWM波形生成实战2.1 PWM基础原理PWM脉冲宽度调制是控制电机速度、LED亮度的核心技术。它的本质是通过调节高电平在一个周期内的占比占空比来控制平均功率输出。记得我第一次用PWM调LED亮度时发现占空比从0%增加到100%LED并不是线性变亮这是因为人眼对光强的感知本身就不是线性的。STM32G474的通用定时器支持多达12路独立PWM输出每路都可以单独配置频率和占空比。关键寄存器包括TIMx_ARR决定PWM频率周期ARR1TIMx_CCRx决定通道的占空比TIMx_CCMRx配置输出模式2.2 CubeMX配置步骤在Pinout界面启用TIM3选择Channel1为PWM Generation CH1在Configuration选项卡设置Prescaler 169170分频Counter Mode UpPeriod 999ARR值Pulse 500初始占空比50%生成代码后添加以下关键语句HAL_TIM_PWM_Start(htim3, TIM_CHANNEL_1); // 启动PWM输出 __HAL_TIM_SET_COMPARE(htim3, TIM_CHANNEL_1, 300); // 动态修改占空比我在调试四轴飞行器电机时发现PWM频率选择很关键。太低会导致电机啸叫典型值应20kHz太高又会增加MOS管开关损耗。经过实测24kHz是个不错的折中点。2.3 高级PWM技巧互补PWM在电机驱动中尤为重要STM32G474的高级定时器支持带死区时间的互补输出。虽然通用定时器不能直接生成互补PWM但可以通过以下方式模拟配置两个通用定时器为主从模式从定时器设置为单脉冲模式主定时器更新事件触发从定时器// 主从定时器配置示例 TIM_MasterConfigTypeDef sMasterConfig {0}; sMasterConfig.MasterOutputTrigger TIM_TRGO_UPDATE; sMasterConfig.MasterSlaveMode TIM_MASTERSLAVEMODE_ENABLE; HAL_TIMEx_MasterConfigSynchronization(htim1, sMasterConfig); TIM_SlaveConfigTypeDef sSlaveConfig {0}; sSlaveConfig.SlaveMode TIM_SLAVEMODE_TRIGGER; sSlaveConfig.InputTrigger TIM_TS_ITR0; HAL_TIM_SlaveConfigSynchronization(htim2, sSlaveConfig);3. 输入捕获技术详解3.1 输入捕获工作原理输入捕获功能就像高速拍照的快门当检测到指定边沿上升沿/下降沿时立即冻结当前计数器的值到CCR寄存器。通过记录两个边沿的捕获值就能计算出脉冲宽度或频率。我在开发超声波测距模块时就是利用这个原理测量回波时间。STM32G474的输入捕获有三大亮点支持4个独立捕获通道最高捕获分辨率可达58.8ns170MHz时钟内置滤波器可消除信号抖动3.2 编码器接口配置对于电机测速应用正交编码器接口是最佳选择。CubeMX配置步骤如下选择TIM2-Combined Channels-Encoder Mode设置Encoder Mode为TI1 and TI2配置IC1和IC2为上升沿触发生成代码后启用编码器接口HAL_TIM_Encoder_Start(htim2, TIM_CHANNEL_ALL);实际使用中我遇到过编码器计数方向反了的问题解决方法很简单交换TI1和TI2的接线或者修改TIMx_CCER寄存器的CC1P/CC2P极性位3.3 频率测量方案对比测量信号频率有三种常用方法各有优缺点方法精度适用频率范围资源占用输入捕获高中低频中等外部时钟定时器最高低频高中断计数法低高频低在智能车竞赛中我采用输入捕获定时器溢出计数的混合方案用输入捕获测量脉冲宽度同时开启定时器溢出中断统计周期数这样既能保证高频信号的测量精度又不会丢失低频信号。4. 闭环控制系统实现4.1 系统架构设计结合PWM生成和输入捕获可以构建完整的电机闭环控制系统PWM驱动电机转动编码器反馈转速信号输入捕获测量实际转速PID算法调节PWM占空比关键代码结构void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) { if(htim-Instance TIM3) { static uint32_t last 0; uint32_t current HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); uint32_t period current - last; // 计算脉冲周期 last current; // 转速换算假设编码器1000线period单位为us float rpm 60000000.0f / (1000 * period); pid_update(rpm); // PID算法更新 } }4.2 PID参数整定技巧调试PID时我总结出几个实用经验先调P比例让系统有基本响应再加D微分抑制超调最后加I积分消除静差采样周期应为控制周期的1/5~1/10一个经过验证的PID实现typedef struct { float Kp, Ki, Kd; float integral; float prev_error; } PID_Controller; float pid_compute(PID_Controller *pid, float setpoint, float input) { float error setpoint - input; pid-integral error; float derivative error - pid-prev_error; pid-prev_error error; // 抗积分饱和处理 if(pid-integral 1000) pid-integral 1000; else if(pid-integral -1000) pid-integral -1000; return pid-Kp*error pid-Ki*pid-integral pid-Kd*derivative; }4.3 抗干扰措施工业现场常见的干扰问题可以通过以下方法解决信号线使用双绞线并加磁环在GPIO口添加RC滤波如100Ω100nF软件上采用中值滤波算法#define FILTER_SIZE 5 float median_filter(float new_val) { static float buffer[FILTER_SIZE] {0}; static uint8_t index 0; buffer[index] new_val; if(index FILTER_SIZE) index 0; // 排序取中值 float temp[FILTER_SIZE]; memcpy(temp, buffer, sizeof(temp)); bubble_sort(temp, FILTER_SIZE); // 实现略 return temp[FILTER_SIZE/2]; }5. 性能优化技巧5.1 定时器级联技术当需要超长定时如1小时时可以级联多个定时器。我曾用TIM2作主定时器TIM3作从定时器实现24小时计时配置TIM2每1秒产生更新事件TIM3设置为从模式时钟源为ITR1TIM2TIM3的ARR设为3600-11小时// 主定时器配置 TIM_MasterConfigTypeDef sMasterConfig {0}; sMasterConfig.MasterOutputTrigger TIM_TRGO_UPDATE; HAL_TIMEx_MasterConfigSynchronization(htim2, sMasterConfig); // 从定时器配置 TIM_SlaveConfigTypeDef sSlaveConfig {0}; sSlaveConfig.SlaveMode TIM_SLAVEMODE_EXTERNAL1; sSlaveConfig.InputTrigger TIM_TS_ITR1; HAL_TIM_SlaveConfigSynchronization(htim3, sSlaveConfig);5.2 DMA加速技巧频繁的定时器数据搬运会消耗CPU资源使用DMA可以大幅提升效率。例如用DMA自动更新PWM占空比// 配置DMA从内存到TIMx_CCR1 hdma_tim1_ch1.Init.PeriphInc DMA_PINC_DISABLE; hdma_tim1_ch1.Init.MemInc DMA_MINC_ENABLE; hdma_tim1_ch1.Init.Direction DMA_MEMORY_TO_PERIPH; HAL_DMA_Init(hdma_tim1_ch1); // 启动DMA传输 uint16_t pwm_values[100] {...}; // 预计算的PWM波形 HAL_TIM_PWM_Start_DMA(htim1, TIM_CHANNEL_1, (uint32_t*)pwm_values, 100);5.3 低功耗优化在电池供电设备中定时器的低功耗配置很关键选择LPTIM低功耗定时器降低时钟频率HSI16代替HSE使用停止模式定时器唤醒// 进入停止模式前配置唤醒定时器 HAL_RTCEx_SetWakeUpTimer_IT(hrtc, 0xFFFF, RTC_WAKEUPCLOCK_RTCCLK_DIV16); // 唤醒后重新初始化定时器 HAL_TIM_Base_Start_IT(htim1);通过以上实战技巧的组合应用我在多个工业控制项目中实现了精确的电机控制和速度测量。特别是在自动化生产线改造项目中基于STM32G474的定时器方案将电机控制精度提升到了±0.5RPM远超客户要求的±2RPM指标。

更多文章