STM32高级定时器实现H桥PWM电机驱动全解析
1. H桥驱动与PWM基础原理
在智能车电机控制系统中,H桥电路是实现直流电机正反转和调速的核心功率拓扑结构。这种由四个开关管组成的H形电路,通过不同的导通组合可以改变电机两端的电压极性,从而实现电机的双向控制。
H桥工作模式解析:
- 正向导通模式:当Q1和Q4导通时,电流从左至右流过电机,实现正转
- 反向导通模式:当Q2和Q3导通时,电流方向反转,电机反转
- 制动模式:通过特定开关组合使电机两端短接,产生制动效果
// H桥控制真值表示例 typedef enum { MOTOR_STOP = 0x00, // 所有MOSFET关断 MOTOR_FWD = 0x05, // Q1和Q4导通 (二进制0101) MOTOR_REV = 0x0A, // Q2和Q3导通 (二进制1010) MOTOR_BRAKE = 0x0F // Q1Q3或Q2Q4导通 (二进制1111) } MotorState;PWM调制技术通过快速切换开关状态来调节平均电压,其关键参数包括:
| 参数 | 典型值 | 说明 |
|---|---|---|
| 频率 | 20kHz | 超出人耳听觉范围,减少噪音 |
| 分辨率 | 16bit | STM32高级定时器最大分辨率 |
| 死区时间 | 100-500ns | 防止上下管直通 |
重要提示:死区时间设置不足会导致桥臂直通烧毁MOSFET,过长则会引入非线性失真。需要根据具体MOSFET的开关特性调整。
2. STM32高级定时器配置
STM32的TIM1/TIM8等高级定时器专为电机控制设计,具备互补输出、死区插入和紧急关断等高级功能。以下是基于HAL库的配置步骤:
2.1 定时器基础配置
TIM_HandleTypeDef htim1; TIM_OC_InitTypeDef sConfigOC; TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig; htim1.Instance = TIM1; htim1.Init.Prescaler = 0; htim1.Init.CounterMode = TIM_COUNTERMODE_UP; htim1.Init.Period = SystemCoreClock / 20000 - 1; // 20kHz PWM htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim1.Init.RepetitionCounter = 0; htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; HAL_TIM_PWM_Init(&htim1);2.2 互补通道配置
sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 0; // 初始占空比0% 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); HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2);2.3 死区时间计算与设置
死区时间与系统时钟频率相关,计算公式为:
T_dt = (DTG[7:0] + 1) * T_dts其中T_dts由时钟分频决定:
| CKD[1:0] | T_dts |
|---|---|
| 00 | t_CK_INT |
| 01 | 2 * t_CK_INT |
| 10 | 4 * t_CK_INT |
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE; sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE; sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF; sBreakDeadTimeConfig.DeadTime = 54; // 约300ns @72MHz sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE; sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH; sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE; HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig);3. 完整驱动实现方案
3.1 初始化流程
- GPIO配置:设置PWM输出引脚为复用推挽输出
- 定时器配置:按上述步骤初始化TIM1
- 启动PWM:
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1) - 启动互补通道:
HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1)
3.2 动态控制接口
void Motor_SetDuty(int16_t duty) { uint16_t pulse = (uint32_t)abs(duty) * htim1.Init.Period / 10000; if(duty > 0) { __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, pulse); __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, 0); } else { __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, 0); __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, pulse); } }3.3 保护机制实现
过流保护电路设计要点:
- 在电机回路串联采样电阻(通常5-50mΩ)
- 使用比较器实时监测电压降
- 触发保护时立即关闭PWM输出
// 紧急停止函数 void Motor_EmergencyStop(void) { HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_1); HAL_TIMEx_PWMN_Stop(&htim1, TIM_CHANNEL_1); HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_2); HAL_TIMEx_PWMN_Stop(&htim1, TIM_CHANNEL_2); // 配置刹车输入引脚 GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = BRAKE_PIN; GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(BRAKE_PORT, &GPIO_InitStruct); }4. 实测波形分析与优化
使用示波器观察H桥输出时,应重点关注以下信号质量指标:
关键测量参数:
- 上升/下降时间(应<100ns)
- 过冲电压(应<电源电压的20%)
- 死区时间实际值
- 开关节点振铃幅度
常见问题解决方案:
| 问题现象 | 可能原因 | 解决方法 |
|---|---|---|
| 波形振荡 | 栅极驱动电阻过大 | 减小栅极电阻(4.7Ω→2.2Ω) |
| MOSFET过热 | 开关损耗大 | 提高死区时间或降低频率 |
| 电机抖动 | PWM分辨率不足 | 改用32位定时器或提高时钟 |
布局布线建议:
- 功率回路与信号回路严格分离
- 栅极驱动走线尽量短(<3cm)
- 在MOSFET的DS极间并联RC缓冲电路
- 使用低ESR的陶瓷电容进行电源去耦
5. 与编码器及PID的协同工作
完整的电机控制系统需要速度反馈闭环,典型架构如下:
[PID控制器] → [PWM生成] → [H桥] → [电机] ↑ | └──[编码器反馈]←──┘速度计算实现:
// 编码器接口配置 TIM_Encoder_InitTypeDef sEncoderConfig; sEncoderConfig.EncoderMode = TIM_ENCODERMODE_TI12; sEncoderConfig.IC1Polarity = TIM_ICPOLARITY_RISING; sEncoderConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI; sEncoderConfig.IC1Prescaler = TIM_ICPSC_DIV1; sEncoderConfig.IC1Filter = 6; sEncoderConfig.IC2Polarity = TIM_ICPOLARITY_RISING; sEncoderConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI; sEncoderConfig.IC2Prescaler = TIM_ICPSC_DIV1; sEncoderConfig.IC2Filter = 6; HAL_TIM_Encoder_Init(&htim3, &sEncoderConfig); // 速度计算 int32_t GetMotorSpeed(void) { static int32_t last_count = 0; int32_t current_count = __HAL_TIM_GET_COUNTER(&htim3); int32_t speed = (current_count - last_count) * 1000 / CONTROL_PERIOD_MS; last_count = current_count; return speed; }PID参数整定经验值:
| 电机类型 | Kp | Ki | Kd | 控制周期 |
|---|---|---|---|---|
| 直流有刷 | 0.5-2.0 | 0.1-0.5 | 0.01-0.1 | 1-10ms |
| 直流无刷 | 1.0-3.0 | 0.2-1.0 | 0.05-0.2 | 0.1-1ms |
实际调试时,建议先设置Ki=Kd=0,逐渐增大Kp直到出现轻微振荡,然后取该值的50%作为最终Kp。接着以类似方法调整Ki和Kd。