《STM32定时器PWM输入捕获与电机控制入门实战》

3、PWM输出原理:PWM信号参数、占空比与频率计算、STM32定时器PWM输出配置流程

PWM(Pulse Width Modulation,脉冲宽度调制)是嵌入式系统中最基础也最常用的信号形式之一。从电机调速、LED调光到舵机控制、音频输出,PWM几乎无处不在。理解PWM的本质——用数字引脚模拟模拟输出——是掌握STM32定时器高级应用的第一步。本章将深入剖析PWM信号的三个核心参数(频率、占空比、分辨率),推导占空比与频率的计算方法,并完整梳理STM32定时器输出PWM的配置流程,最后通过一个直流电机开环调速的实战案例,将理论落地为可运行的代码。

STM32定时器PWM输出原理与配置链路 PWM信号三要素 ① 频率 f = 1/T 决定信号快慢,单位Hz 电机控制常用 10kHz~50kHz ② 占空比 D = Ton/T 高电平时间占周期比例 0%~100%,决定输出平均电压 ③ 分辨率 = ARR+1 自动重载值决定占空比步进 如 ARR=999,分辨率0.1% STM32定时器PWM输出配置流程 1. 使能时钟 TIMx + GPIO 2. 配置GPIO 复用推挽输出 3. 配置时基 PSC + ARR 4. 配置输出比较 CCR + 模式 5. 配置输出通道 CCER + 极性 6. 使能输出 BDTR + CR1 PWM波形示意(频率=1kHz,占空比=60%) 0 t Ton=0.6ms T=1ms

上图展示了PWM信号的三个核心参数与STM32定时器PWM输出配置流程之间的映射关系。理解这张图的关键在于:频率由时基单元决定,占空比由比较寄存器决定,分辨率由自动重载值决定。下面我们逐一展开。

3.1 PWM信号参数:频率、占空比与分辨率

PWM信号本质上是一个周期性的数字方波,其输出电平在高低之间切换。描述一个PWM信号,需要三个基本参数:

  • 频率(f):单位Hz,表示每秒完成的周期数。频率的倒数是周期T(T=1/f)。频率决定了PWM信号的“快慢”,在电机控制中,频率过低会导致电机产生 audible noise(可听噪声)和转速波动;频率过高则会增加开关损耗。直流电机调速常用10kHz~50kHz,舵机控制通常为50Hz(周期20ms)。
  • 占空比(D):高电平持续时间(Ton)与整个周期(T)的比值,即 D = Ton / T × 100%。占空比决定了输出信号的平均电压。例如,5V幅值的PWM信号,占空比60%时,平均电压为3V。对于电机,占空比直接决定其平均电枢电压,从而控制转速。
  • 分辨率(Resolution):占空比可调节的最小步进。在STM32定时器中,分辨率由自动重载值ARR决定。若ARR=999,则占空比可以从0/1000到1000/1000,即0.1%步进。分辨率越高,控制越精细,但ARR过大会降低PWM频率(在时钟频率固定时)。

核心公式:

PWM频率 f = TIMxCLK / ((PSC+1) × (ARR+1))
占空比 D = CCR / (ARR+1) × 100%
分辨率 = 1 / (ARR+1) × 100%

其中TIMxCLK是定时器时钟源频率,PSC是预分频器值,ARR是自动重载值,CCR是捕获/比较寄存器值。这三个公式是PWM配置的基石,务必牢记。

3.2 占空比与频率的计算方法

在实际工程中,我们通常先确定所需的PWM频率和占空比范围,然后反推定时器配置参数。计算步骤如下:

  1. 确定定时器时钟源:STM32定时器时钟通常来自内部时钟(如APB1或APB2定时器时钟)。例如,STM32F103系列,APB1定时器时钟最高为72MHz,APB2为72MHz。具体值需查阅参考手册的时钟树。
  2. 选择预分频PSC:PSC将定时器时钟分频为计数时钟。计数时钟频率 = TIMxCLK / (PSC+1)。PSC的范围是0~65535。
  3. 计算自动重载ARR:根据目标频率f,ARR = TIMxCLK / ((PSC+1) × f) - 1。ARR决定了计数周期,也即PWM周期。
  4. 设置比较值CCR:根据目标占空比D,CCR = D × (ARR+1)。CCR的值在0~ARR+1之间。

举一个具体例子:假设STM32F103的TIM2时钟为72MHz,我们需要产生一个20kHz的PWM信号,占空比可在0%~100%之间调节,要求分辨率不低于0.1%。

参数 计算过程 结果
目标频率f 20kHz 20000 Hz
定时器时钟 TIM2CLK 72 MHz
预分频PSC 选择PSC=0,则计数时钟=72MHz 0
自动重载ARR ARR = 72e6 / (1 × 20000) - 1 = 3599 3599
分辨率 1/(3599+1) ≈ 0.0278% 优于0.1%要求
50%占空比CCR CCR = 0.5 × 3600 = 1800 1800

如果希望降低频率到1kHz,同时保持分辨率,可以增大PSC。例如PSC=71,则计数时钟=1MHz,ARR=999,频率=1kHz,分辨率=0.1%。这说明PSC和ARR共同决定了频率与分辨率的平衡。

经验法则:在电机控制中,PWM频率选择应避开机械共振频率,同时高于人耳可听范围(>20kHz)以避免噪声。如果使用IR2104等栅极驱动器,还需考虑死区时间与PWM频率的匹配。

3.3 STM32定时器PWM输出配置流程

STM32的通用定时器(TIM2~TIM5)和高级定时器(TIM1、TIM8)都支持PWM输出。配置流程可以归纳为六个步骤,下面以标准外设库(SPL)风格代码为例,展示完整配置过程。

步骤1:使能定时器和GPIO时钟

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

步骤2:配置GPIO为复用推挽输出

GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;  // TIM2_CH1 映射到 PA0
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  // 复用推挽
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);

步骤3:配置定时器时基单元

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Period = 3599;        // ARR
TIM_TimeBaseStructure.TIM_Prescaler = 0;        // PSC
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

步骤4:配置输出比较模式

TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;  // PWM模式1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 1800;              // CCR = 1800,占空比50%
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM2, &TIM_OCInitStructure);

步骤5:使能输出比较预装载(可选)

TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable);

步骤6:使能定时器

TIM_Cmd(TIM2, ENABLE);

如果是高级定时器(TIM1/TIM8),还需额外使能主输出:TIM_CtrlPWMOutputs(TIM1, ENABLE);。这是因为高级定时器带有刹车功能和死区插入,主输出默认关闭。

常见陷阱:忘记使能高级定时器的主输出(MOE位),导致PWM引脚无输出。另外,GPIO复用功能配置错误(如将PA0配置为普通推挽而非复用推挽)也会导致无波形。排查时先用示波器测量引脚,再检查寄存器配置。

3.4 实战案例:直流电机开环调速

下面通过一个完整的直流电机调速案例,将上述配置流程串联起来。场景:使用STM32F103C8T6最小系统板,通过TIM2_CH1(PA0)输出PWM,经过一个NPN三极管或MOSFET驱动电路,控制一个6V直流电机的转速。要求:PWM频率20kHz,占空比从0%到100%可调,通过按键增加/减少占空比。

硬件连接:

  • PA0 → 驱动电路栅极/基极
  • 电机正极 → VCC(6V),电机负极 → 驱动电路开关端
  • 按键1 → PB0(增加占空比),按键2 → PB1(减少占空比)

软件设计思路:主循环中检测按键,每次按下改变CCR值(步进为10,即约0.28%),并限制在0~3599范围内。PWM初始化代码与3.3节相同,只需将ARR设为3599,PSC设为0。

关键代码片段:

uint16_t duty = 1800;  // 初始50%

while(1) {
    if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == RESET) {
        while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == RESET); // 消抖
        if(duty < 3599) duty += 10;
        TIM_SetCompare1(TIM2, duty);
    }
    if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == RESET) {
        while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == RESET);
        if(duty > 10) duty -= 10;
        TIM_SetCompare1(TIM2, duty);
    }
}

测试结果与现象:上电后电机以50%占空比运转,按下PB0键,电机转速明显提升;按下PB1键,转速下降。用示波器测量PA0引脚,可以看到频率稳定在20kHz,脉宽随按键变化。用万用表测量电机两端平均电压,从0V到6V线性变化。

风险与代价:该电路为开环控制,电机转速受负载影响较大。如果负载增大,转速会下降,但PWM占空比不变,无法自动补偿。此外,驱动电路如果使用三极管,在大电流下会有较大压降和发热;建议使用MOSFET(如IRLZ44N)并加装续流二极管。

复盘经验:开环调速适合对精度要求不高的场景。若需精确转速控制,应增加编码器反馈,构成闭环PID调速。另外,PWM频率的选择需要权衡:20kHz虽然无声,但开关损耗较大;对于小功率电机,10kHz也足够,且驱动电路发热更小。

3.5 常见误区与总结

在PWM配置与使用中,初学者常犯以下错误:

  • 误区一:混淆PSC和ARR的作用。PSC是预分频,影响计数时钟频率;ARR是自动重载值,决定计数周期。两者共同决定PWM频率,但ARR还影响分辨率。
  • 误区二:忽略高级定时器的主输出使能。使用TIM1/TIM8时,必须调用TIM_CtrlPWMOutputs(),否则引脚无输出。
  • 误区三:GPIO复用配置错误。PWM输出引脚必须配置为复用推挽(AF_PP),而不是普通推挽输出。
  • 误区四:占空比计算错误。CCR值范围是0~ARR+1,当CCR=ARR+1时,占空比为100%(持续高电平);当CCR=0时,占空比为0%(持续低电平)。
  • 误区五:动态修改ARR时未考虑同步。如果运行中修改ARR,建议使用预装载功能(TIM_ARRPreloadConfig),否则可能产生不完整的PWM周期。

本章总结:PWM输出的本质是定时器计数与比较匹配的过程。频率由PSC和ARR决定,占空比由CCR决定,分辨率由ARR决定。配置流程遵循“时钟→GPIO→时基→输出比较→通道配置→使能”的顺序。掌握这些基础,后续的输入捕获、死区插入、互补输出等高级功能都将水到渠成。