1. 项目背景与核心需求
PWM(脉冲宽度调制)技术在电力电子、电机控制等领域有着广泛应用。在实际工程中,特别是驱动半桥或全桥电路时,经常需要两路互补的PWM信号,并且为了避免上下管直通,必须插入死区时间。STM32系列MCU因其丰富的外设和性价比优势,成为实现这类功能的理想选择。
这个项目要解决的核心问题是:如何在STM32上配置定时器,生成两路带死区的互补PWM信号,并通过仿真验证其正确性。这不仅是电力电子工程师的必备技能,也是学习STM32高级定时器功能的典型案例。
2. 硬件设计与定时器选型
2.1 STM32定时器资源分析
STM32的定时器分为基本定时器、通用定时器和高级定时器。其中,只有高级定时器(TIM1/TIM8等)支持互补输出和死区插入功能。以STM32F103系列为例:
- TIM1:高级定时器,支持6路PWM输出(其中3对互补)
- 死区时间可编程范围:0~1588ns(以72MHz系统时钟为例)
- 支持刹车功能,防止功率管损坏
提示:选择定时器时需注意引脚分配,确保PWM输出引脚与硬件设计匹配。
2.2 典型应用电路
在半桥驱动电路中,互补PWM的典型连接方式如下:
code复制STM32 PWMH -> 高端驱动器 -> 高端MOSFET
STM32 PWML -> 低端驱动器 -> 低端MOSFET
死区时间的设置必须大于MOSFET的开关延迟时间,通常建议:
- Si MOSFET:200-500ns
- SiC/GaN器件:50-100ns
3. 软件配置详解
3.1 定时器初始化流程
以下是使用STM32 HAL库配置互补PWM的关键步骤:
c复制// 1. 定时器时基配置
TIM_HandleTypeDef htim1;
htim1.Instance = TIM1;
htim1.Init.Prescaler = 0;
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = 999; // PWM频率 = 72MHz/(999+1) = 72kHz
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim1.Init.RepetitionCounter = 0;
HAL_TIM_PWM_Init(&htim1);
// 2. PWM通道配置
TIM_OC_InitTypeDef sConfigOC;
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 500; // 初始占空比50%
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1);
// 3. 死区时间配置
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig;
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
sBreakDeadTimeConfig.DeadTime = 54; // 死区时间 = 54*1/72MHz ≈ 750ns
sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig);
3.2 死区时间计算
死区时间由寄存器DTG[7:0]决定,计算公式如下:
- 当DTG[7:5]=0xx时:DT = DTG[7:0] × Tdtg
- 当DTG[7:5]=10x时:DT = (64 + DTG[5:0]) × 2 × Tdtg
- 当DTG[7:5]=110时:DT = (32 + DTG[4:0]) × 8 × Tdtg
- 当DTG[7:5]=111时:DT = (32 + DTG[4:0]) × 16 × Tdtg
其中Tdtg = TIMx时钟周期。例如72MHz时钟下:
- 设置DTG=54(二进制00110110):
属于第一种情况,DT = 54 × (1/72MHz) ≈ 750ns
4. 仿真验证方法
4.1 Proteus仿真搭建
- 在Proteus中添加STM32F103C8元件
- 添加逻辑分析仪和示波器
- 连接PWM输出到分析仪(TIM1_CH1和TIM1_CH1N)
- 配置电源和必要的上拉电阻
4.2 关键测试点
- 互补性验证:两路PWM应始终保持互补(一高一低)
- 死区验证:在电平跳变沿应有设定的死区时间
- 占空比精度:测量实际输出占空比与设定值的一致性
实测波形应类似下图:
code复制PWMH: _|¯¯|____|¯¯|____
PWML: ¯|__|¯¯¯¯|__|¯¯¯¯
↑死区↑
5. 常见问题与解决方案
5.1 无PWM输出
可能原因及排查:
- 定时器时钟未使能
- 检查__HAL_RCC_TIM1_CLK_ENABLE()是否调用
- GPIO配置错误
- 确认GPIO已配置为复用功能
- 检查GPIO时钟使能
- 定时器未启动
- 确保调用了HAL_TIM_PWM_Start()和HAL_TIMEx_PWMN_Start()
5.2 死区时间不生效
调试步骤:
- 确认使用的是高级定时器(TIM1/TIM8)
- 检查BreakDeadTimeConfig结构体配置
- 测量实际波形,确认死区时间计算正确
- 检查TIMx_BDTR寄存器的DTG位是否写入成功
5.3 波形抖动或失真
优化建议:
- 降低PWM频率(特别是长死区时)
- 检查电源稳定性
- 添加适当的RC滤波(通常10kΩ+100pF)
- 确保PCB布局合理,减少交叉干扰
6. 进阶应用技巧
6.1 动态调整死区时间
在某些应用中需要根据温度或负载调整死区时间:
c复制void Adjust_DeadTime(uint8_t new_deadtime)
{
TIM1->BDTR &= ~TIM_BDTR_DTG; // 清除原设置
TIM1->BDTR |= new_deadtime; // 设置新值
// 需要短暂关闭输出以防意外
TIM1->BDTR &= ~TIM_BDTR_MOE;
TIM1->BDTR |= TIM_BDTR_MOE;
}
6.2 与ADC同步采样
在电机控制中,常需要在PWM周期特定时刻采样电流:
c复制// 配置定时器触发ADC
hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1;
HAL_ADC_Init(&hadc1);
// 在PWM周期中间采样
sConfigOC.Pulse = htim1.Init.Period/2;
6.3 使用CubeMX快速配置
对于初学者,可以使用STM32CubeMX图形化工具:
- 选择TIM1
- 开启Channel1的PWM Generation CH1N
- 在Parameter Settings中设置死区时间
- 生成代码后只需添加启动代码
7. 实际项目经验分享
在开发工业变频器时,我们遇到过死区时间不足导致MOSFET损坏的问题。后来总结出以下经验:
- 死区时间实测应比计算值增加20%余量
- 上电顺序很重要:先使能PWM再接通功率电源
- 建议添加硬件刹车电路作为双重保护
- 在高温环境下测试死区时间的稳定性
一个实用的调试技巧:先用低压电源(如12V)和小功率负载验证PWM逻辑,确认无误后再接入高压大功率电路。
