【HAL库实战】STM32F103精准控制PWM脉冲数:中断与门控双方案解析
1. PWM脉冲数控制的核心需求在电机控制、步进驱动等嵌入式应用场景中精确控制PWM脉冲数量是刚需。比如控制步进电机转动特定角度每个脉冲对应固定的步进角度这时候如果脉冲数不准确就会导致定位偏差。我在去年做的3D打印机项目中就遇到过这个问题Z轴电机因为脉冲丢失导致打印层高错位整个模型直接报废。STM32F103的HAL库提供了两种主流方案来实现这个功能中断计数法和主从定时器门控法。前者实现简单但占用CPU资源后者硬件自动完成但需要两个定时器配合。实测下来当脉冲频率超过10kHz时中断方式就会明显增加系统负担而门控方式依然能稳定工作。2. 硬件准备与基础配置2.1 硬件选型要点我用的是STM32F103ZET6最小系统板选择TIM1的通道1PE9引脚作为PWM输出。这里有个坑要注意TIM1是高级定时器相比通用定时器多了刹车功能等特性在CubeMX配置时需要特别注意相关参数。开发环境配置STM32CubeMX 6.5.0Keil MDK 5.32ST-Link V2调试器2.2 CubeMX基础配置在CubeMX中操作时在Pinout界面启用TIM1_CH1配置时钟树确保TIM1有正确的时钟源在TIM1配置页面PWM Generation CH1模式Prescaler设为7172MHz时钟下得到1MHz计数频率Counter Period设为9991kHz PWM频率Pulse初始值设为50050%占空比生成代码前务必勾选Generate peripheral initialization as a pair of .c/.h files选项这样后续维护更方便。3. 中断计数方案详解3.1 实现原理与代码中断方式的本质就是在每个PWM周期结束时触发中断在中断服务程序中进行计数。当计数达到设定值时关闭PWM输出。具体实现代码如下// 启动PWM输出并开启中断 HAL_TIM_PWM_Start_IT(htim1, TIM_CHANNEL_1); // 中断回调函数 void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim) { static uint16_t pulse_count 0; pulse_count; if(pulse_count 10) // 达到10个脉冲 { HAL_TIM_PWM_Stop_IT(htim1, TIM_CHANNEL_1); pulse_count 0; // 计数器清零 } }3.2 实测问题与优化在实际测试中发现两个典型问题中断延迟当系统有其他高优先级中断时可能导致脉冲计数不准确。解决方法是将TIM1中断优先级设为最高。停止时机偏差最后一个脉冲的完整度可能受影响。优化方案是提前一个周期判断if(pulse_count 9) // 第9个周期时准备停止 { __HAL_TIM_SET_AUTORELOAD(htim1, 特殊值); // 精确控制最后一个周期 }用逻辑分析仪抓取的波形显示优化后脉冲数量误差可以控制在±1以内。4. 主从定时器门控方案4.1 硬件级工作原理这种方法利用了STM32定时器的主从模式特性主定时器TIM1负责PWM波形生成从定时器TIM2作为脉冲计数器硬件连接上TIM1的触发输出TRGO连接到TIM2的触发输入ITRx。当TIM2计数达到设定值时会自动通过硬件信号关闭TIM1的输出完全不占用CPU资源。4.2 具体配置步骤CubeMX配置TIM1配置与之前相同额外开启主模式Trigger OutputTIM2配置为从模式Trigger Mode触发源选择ITR0TIM1关键代码// 设置脉冲数量为10 __HAL_TIM_SET_AUTORELOAD(htim2, 10-1); // 启动定时器 HAL_TIM_Base_Start(htim2); HAL_TIM_PWM_Start(htim1, TIM_CHANNEL_1);4.3 性能对比测试在72MHz主频下进行对比测试指标中断方式门控方式最大频率15kHz1MHzCPU占用率8%0%脉冲误差±10响应延迟1.2μs0.05μs门控方式在高速场景下优势明显但会多占用一个定时器资源。5. 方案选型建议根据我的项目经验给出以下实用建议选择中断计数方案当脉冲频率低于5kHz系统定时器资源紧张对脉冲数精度要求不高±2以内可接受选择门控方案当需要输出MHz级高频脉冲系统有富余的定时器资源要求硬件级精确控制在工业伺服电机控制项目中我最终选择了门控方案。虽然多占用了一个定时器但换来了0误差的脉冲控制和极低的CPU占用系统可以同时处理更多任务。