一篇文章搞懂!PWM!

2025-06-20 10:13:205699

#针对PWM的学习记录,进行梳理

目录

一.PWM是什么,有什么用

二.PWM输入捕获/互补输出/输出比较功能(基于STM32)

1.输入捕获

2.互补输出

3.输出比较

一.PWM是什么,有什么用

1.PWM啥意思(结合deepseek深度思考)

PWM(脉宽调制)通过调节占空比来控制功率开关器件的导通时间,最终实现输出电压的稳定,其核心原理是 通过快速开关的周期性通断,控制能量的平均输出。

1. PWM的基本原理 占空比(Duty Cycle:指一个周期内开关导通时间(高电平时间)与整个周期时间的比值。 公式: 占空比 = (导通时间\周期时间)*100% 开关频率:PWM信号的周期倒数(10Hz=表示每秒开关10次)。 频率越高,输出纹波越小,但开关损耗可能增加。

2. 功率开关器件的导通控制 功率开关器件(如MOSFET、IGBT)在导通时允许电流流过,截止时阻断电流。 通过PWM控制导通时间: 占空比大 → 导通时间长 → 平均输出电压高。 占空比小 → 导通时间短 → 平均输出电压低。 例如: 若输入电压为12V,占空比为50%,则平均输出电压约为6V。 占空比为75%时,平均输出电压约为9V。

3. 如何实现“输出电压稳定” 关键在于 闭环反馈控制,典型应用场景是开关电源(如BUCK、BOOST电路): 步骤1:采样输出电压 通过电阻分压或传感器实时监测输出电压Vout。 步骤2:与参考电压比较 将采样电压与目标参考电压(Vref,如5V)输入误差放大器,生成误差信号。 步骤3:动态调整占空比 若 Vout< Vref→ 增大占空比 → 导通时间延长 → 提升输出电压。 若 Vout > Vref→ 减小占空比 → 导通时间缩短 → 降低输出电压。 步骤4:周期性调节 PWM控制器根据误差信号实时调整占空比,直到输出电压稳定在目标值。

4. 举例说明(BUCK降压电路) 输入电压Vin:24V 目标输出电压Vout:12V 理论占空比: D = Vout/Vin = 12/24= 50% 实际运行: 当负载突然增大 → Vout下降 → 控制器检测到误差 → 占空比增大至55% → 输出恢复12V。 当输入电压波动(如24V→22V)→ 占空比自动调整至更高值(如55%)以补偿输入降低的影响。

二.PWM输入捕获/互补输出/输出比较功能(基于STM32)

1.输入捕获

(STM32系列)应用于脉冲跳变沿时间测量, PWM 输入测量。选定输入通道,确定触发信号,然后设置触发信号的极性即可,因为是PWM 输入的缘故,另一路信号则由硬件配置,无需软件配置,从软件上来说,用 PWM 输入模式测量脉宽和周期更容易,付出的代价是需要占用两个捕获寄存器。

2.互补输出/输出比较(重点!常用)

应用:

• 电机控制(调节转速)。

• LED调光(调节亮度)。

• 直流调压电源(调节输出电压)。

• ⾳频信号⽣成(DAC模拟)。

通过定时器⽣成PWM信号,通常⽤于控制外部设备(如电机、LED亮度、电源开关等)。其核⼼原理是通过⽐较定时器计数器(CNT)和⽐较寄存器(CCR)的值,⽣成占空⽐可调的PWM波形。

⼯作原理

1. 计数器(CNT):定时器的计数器从0开始递增(或递减),直到达到⾃动重装载值(ARR)。

2. ⽐较寄存器(CCR):⽤⼾设置⼀个⽐较值,当CNT与CCR匹配时,触发输出电平变化。

3. 输出模式:

◦ PWM模式1:CNT < CCR时输出⾼电平,CNT ≥ CCR时输出低电平。

◦ PWM模式2:CNT < CCR时输出低电平,CNT ≥ CCR时输出⾼电平

配置步骤(以STM32为例)

1. 配置定时器时钟和预分频器。

2. 设置⾃动重装载值(ARR)决定PWM频率。

3. 设置⽐较寄存器(CCR)决定占空⽐。

4. 选择PWM模式并启动定时器。

代码实现

eg:TIM2,CH4单通道,输出比较配置见下:

void PWM_Configuration(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

/* TIM2 clock enable */

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA ,ENABLE);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 ;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOA, &GPIO_InitStructure);

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

PrescalerValue = (uint16_t) (SystemCoreClock / 24000000) - 1;

RCC_PLLConfig(RCC_PLLSource_HSE_Div2, RCC_PLLMul_9); // (16MHz/2) *9 = 72MHz

TIM_TimeBaseStructure.TIM_Prescaler = 71; // ?????1MHz

TIM_TimeBaseStructure.TIM_Period = 999;

TIM_TimeBaseStructure.TIM_Prescaler = PrescalerValue;

TIM_TimeBaseStructure.TIM_ClockDivision = 0;

TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

TIM_OCInitTypeDef TIM_OCInitStructure;

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;

TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

/* PWM1 Mode configuration: Channel2 */

TIM_OCInitStructure.TIM_Pulse = 0;

TIM_OC2Init(TIM2, &TIM_OCInitStructure);

TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);

TIM_Cmd(TIM2, ENABLE);

}

void PWM_Configuration_wjtest(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

TIM_TimeBaseInitTypeDef Tim2_st;

TIM_OCInitTypeDef TIM_OCst;

/* Enable Clock */

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA ,ENABLE);

GPIO_InitStructure.GPIO_Mode = GPIO_Pin_3;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

/* Gpio Init */

GPIO_Init(GPIOA, &GPIO_InitStructure);

/* Time Config :

in STM32F103x_data sheet, PA3 AF is TIM5_CH4 or TIM2_CH4 */

/* Clock Enble */

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);

Tim2_st.TIM_Prescaler = 72-1;/* 7200-1; */ /* PSC */

Tim2_st.TIM_CounterMode = TIM_CounterMode_Down;

Tim2_st.TIM_Period = 100;/* 10000-1; */ /* ARR */

Tim2_st.TIM_ClockDivision = TIM_CKD_DIV1;

Tim2_st.TIM_RepetitionCounter = 0; /* Only advanced Timer have. */

/*

T = (ARR + 1) * (1 / CLK_cnt)

= (1000 - 1 + 1) * (1 / 1MHz)

= 1000 * (1 / 1000000 s)

= 0.001 s

= 1 ms

*/

TIM_OCst.TIM_OCMode = TIM_OCMode_PWM1; /* ?????PWM??1 */

TIM_OCst.TIM_OutputState = TIM_OutputState_Enable; /* ?????? */

TIM_OCst.TIM_OutputNState = TIM_OutputNState_Enable; /* ?????????? */

TIM_OCst.TIM_Pulse = 50;/* 5000; */ /* ?????????? */

TIM_OCst.TIM_OCPolarity = TIM_OCPolarity_Low; /* ????????????????? */

TIM_OCst.TIM_OCNPolarity = TIM_OCPolarity_Low; /* ????????????????????? */

TIM_OCst.TIM_OCIdleState = TIM_OCIdleState_Set; /* ???????????????????? */

TIM_OCst.TIM_OCNIdleState = TIM_OCNIdleState_Reset; /* ???????????????????????? */

/* Tim2 Init. */

TIM_TimeBaseInit(TIM2,&Tim2_st);

TIM_OC4Init(TIM2, &TIM_OCst);

TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Enable);

TIM_Cmd(TIM2, ENABLE);

// ????????????????????????????????

TIM_CtrlPWMOutputs(TIM2, ENABLE);

}