
基于STM32主从定时器的双通道PWM信号发生器设计与实现引言在嵌入式系统开发中PWM信号生成是一项基础但至关重要的功能。无论是电机控制、LED调光还是音频合成精确的PWM信号都是实现这些功能的核心。STM32系列微控制器凭借其丰富的外设资源特别是高级定时器模块为开发者提供了强大的PWM生成能力。本文将深入探讨如何利用STM32的TIM1和TIM2定时器构建一个双通道PWM信号发生器实现频率、占空比和相位的动态调整。这个项目的独特之处在于双通道独立控制两路PWM信号共享相同频率但占空比和相位差可独立调节实时动态调整所有参数可通过上位机实时修改无需重新初始化硬件高频率输出设计目标支持最高50kHz的PWM频率无中断依赖采用主从定时器硬件同步机制避免频繁中断带来的性能瓶颈1. 硬件架构设计1.1 系统整体框架我们的双通道PWM信号发生器系统由以下几个核心部分组成STM32微控制器作为系统的核心处理单元负责定时器配置和PWM生成定时器模块TIM1主定时器生成基准PWM信号通道1TIM2从定时器生成相位可调的PWM信号通道2通信接口通常使用UART或USB与上位机通信接收参数调整指令电平转换电路可选根据负载需求可能需要的信号调理电路1.2 定时器资源分配STM32的定时器资源丰富不同系列配置略有差异。以STM32F1系列为例定时器类型定时器编号特性本项目用途高级定时器TIM1, TIM8支持互补输出、死区控制主定时器(TIM1)通用定时器TIM2-TIM5支持编码器接口从定时器(TIM2)基本定时器TIM6, TIM7仅支持基本定时功能不使用关键硬件连接TIM1_CH1 → PA8 (通道1输出)TIM2_CH1 → PA0 (通道2输出)USART1_TX → PA9 (上位机通信)2. 定时器配置原理2.1 主从定时器同步机制STM32的主从定时器同步功能是实现相位可调PWM的核心。其工作原理如下主定时器(TIM1)配置为PWM模式1生成基准PWM信号设置触发输出(TRGO)为OC2REF通道2比较匹配事件从定时器(TIM2)配置为复位模式(Slave Mode Reset)触发源(Trigger Source)选择ITR0连接TIM1时钟源(Clock Source)禁用完全由TIM1触发当TIM1的通道2发生比较匹配时会产生TRGO信号这个信号会触发TIM2计数器复位并重新开始计数从而在两路PWM之间形成可控的相位差。2.2 关键寄存器配置以下是实现该功能需要配置的核心寄存器// TIM1 主定时器配置 TIM1-CR2 | TIM_CR2_MMS_1; // TRGO选择OC2REF TIM1-CCMR1 | TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1; // PWM模式1 TIM1-CCMR2 | TIM_CCMR2_OC2M_0 | TIM_CCMR2_OC2M_1; // Toggle模式 // TIM2 从定时器配置 TIM2-SMCR | TIM_SMCR_SMS_2; // 复位模式 TIM2-SMCR | TIM_SMCR_TS_0; // 触发源选择ITR03. 软件实现细节3.1 初始化流程完整的定时器初始化应遵循以下步骤配置TIM1为主定时器设置预分频器(PSC)和自动重载值(ARR)确定基准频率配置通道1为PWM输出模式配置通道2为Toggle模式用于触发从定时器配置TIM2为从定时器设置与TIM1相同的PSC和ARR值配置从模式为复位模式选择TIM1作为触发源启动定时器先启动主定时器(TIM1)再启动从定时器(TIM2)void PWM_Init(uint32_t frequency, uint16_t duty1, uint16_t duty2, uint16_t phase) { // 计算ARR值 (假设系统时钟72MHz) uint16_t arr (72000000 / frequency) - 1; // TIM1 配置 TIM1-PSC 0; TIM1-ARR arr; TIM1-CCR1 (arr * duty1) / 100; TIM1-CCR2 (arr * phase) / 100; // TIM2 配置 TIM2-PSC 0; TIM2-ARR arr; TIM2-CCR1 (arr * duty2) / 100; // 启动定时器 TIM1-CR1 | TIM_CR1_CEN; TIM2-CR1 | TIM_CR1_CEN; }3.2 参数动态调整实现参数实时调整的关键在于正确处理寄存器更新时机频率调整同时修改TIM1和TIM2的ARR值保持占空比和相位比例不变占空比调整独立修改TIM1_CCR1通道1占空比独立修改TIM2_CCR1通道2占空比相位调整修改TIM1_CCR2值改变触发点位置相位差 (CCR2 / ARR) * 360°void PWM_UpdateParams(uint32_t frequency, uint16_t duty1, uint16_t duty2, uint16_t phase) { // 禁用定时器更新中断 __disable_irq(); // 计算新ARR值 uint16_t arr (72000000 / frequency) - 1; // 更新TIM1参数 TIM1-ARR arr; TIM1-CCR1 (arr * duty1) / 100; TIM1-CCR2 (arr * phase) / 100; // 更新TIM2参数 TIM2-ARR arr; TIM2-CCR1 (arr * duty2) / 100; // 重新启用定时器更新中断 __enable_irq(); }4. 上位机通信协议设计4.1 通信协议格式为方便上位机控制我们设计简单的ASCII协议F频率 D1占空比1 D2占空比2 P相位差\n示例命令F10000 D150 D230 P25\n表示设置频率为10kHz通道1占空比50%通道2占空比30%相位差25%。4.2 命令解析实现void USART1_IRQHandler(void) { static char rxBuffer[32]; static uint8_t index 0; if(USART1-SR USART_SR_RXNE) { char ch USART1-DR; if(ch \n) { rxBuffer[index] \0; ParseCommand(rxBuffer); index 0; } else { rxBuffer[index] ch; if(index sizeof(rxBuffer)) index 0; } } } void ParseCommand(char* cmd) { uint32_t freq 1000; // 默认1kHz uint16_t duty1 50; // 默认50% uint16_t duty2 50; // 默认50% uint16_t phase 0; // 默认0° char* token strtok(cmd, ); while(token ! NULL) { switch(token[0]) { case F: freq atoi(token1); break; case D: if(token[1] 1) duty1 atoi(token2); else if(token[1] 2) duty2 atoi(token2); break; case P: phase atoi(token1); break; } token strtok(NULL, ); } PWM_UpdateParams(freq, duty1, duty2, phase); }5. 性能优化与问题排查5.1 高频PWM输出优化当需要输出高频PWM如50kHz时需注意以下优化点预分频器设置尽量使用较小的PSC值理想为0高频率时ARR值较小需确保足够的分辨率时钟源选择使用最高性能的时钟配置如72MHz考虑使用外部晶振提高时钟精度代码优化参数更新时禁用中断使用寄存器直接操作替代库函数5.2 常见问题与解决方案问题现象可能原因解决方案两路PWM无相位差主从定时器未正确配置检查TIM1的TRGO设置和TIM2的触发源高频时波形不稳定中断处理时间过长避免在中断中处理复杂逻辑使用DMA占空比调节不线性ARR值过小导致分辨率不足提高系统时钟或降低频率要求相位差精度不足CCR2值计算错误确保相位计算考虑当前频率5.3 波形质量测量技巧使用示波器验证PWM信号质量时重点关注上升/下降时间反映驱动能力是否足够频率精度对比设定值与实际测量值占空比线性度在不同设定值下的实际占空比相位差稳定性长时间工作的相位漂移情况提示测量高频PWM时建议使用至少100MHz带宽的示波器和10X探头以减小测试引入的失真