基于STM32CubeIDE与H桥的直流有刷电机PWM驱动实战

张开发
2026/5/4 4:52:40 15 分钟阅读
基于STM32CubeIDE与H桥的直流有刷电机PWM驱动实战
1. 直流有刷电机驱动基础直流有刷电机是最常见的电机类型之一它的工作原理简单来说就是通过电刷和换向器的机械接触改变线圈中的电流方向从而产生持续的旋转力矩。这种电机在玩具、家电、工业设备中随处可见比如电动牙刷、打印机、电动窗帘等。在实际项目中我们通常需要控制电机的三个基本动作启动/停止、正转/反转、调速。这就引出了我们今天要讨论的核心技术——PWM脉冲宽度调制驱动。PWM就像是一个高速开关通过快速打开和关闭电流来控制电机的平均电压。占空比高电平时间占整个周期的比例越大电机转速越快。我刚开始接触电机驱动时最大的困惑就是H桥电路。后来发现可以把它想象成一个十字路口的红绿灯当对角线方向的两个开关MOS管同时导通时电流就会沿着这个方向流过电机实现一个方向的转动反过来导通另一组对角线开关电流方向就反转了。AT8236芯片就是帮我们封装好了这个H桥电路让我们可以更安全方便地控制电机。2. STM32CubeIDE环境搭建工欲善其事必先利其器。STM32CubeIDE是ST官方推出的免费开发环境它集成了STM32CubeMX配置工具特别适合新手快速上手。我建议直接从ST官网下载最新版本安装过程基本一路Next就行。安装完成后新建工程时要注意选择正确的芯片型号。我曾经因为选错型号浪费了半天时间调试不成功。以常见的STM32F103C8T6为例创建工程后会自动打开CubeMX配置界面。这里有个小技巧在Pinout视图里直接搜索TIM1可以快速找到定时器相关引脚。时钟配置是很多新手容易出错的地方。建议先配置好系统时钟树确保APB2总线时钟TIM1挂载在此有正确的频率。我一般会先在Clock Configuration选项卡里选择HSE外部晶振作为时钟源然后根据芯片手册设置合适的PLL倍频系数最后确认TIM1的时钟频率是否正确。3. TIM1定时器配置详解TIM1是STM32的高级定时器特别适合电机控制场景。在CubeMX中配置TIM1时主要关注以下几个参数PrescalerPSC这个值决定了定时器的分频系数。比如系统时钟是72MHzPSC设为71那么定时器时钟就是1MHz72MHz/(711)。Counter PeriodARR这个值决定了PWM的周期。结合上面的例子如果ARR设为999那么PWM频率就是1MHz/(9991)1kHz。Pulse这个值决定了PWM的初始占空比。设为500就是50%占空比。实际项目中我发现电机对PWM频率很敏感。太低会有噪音太高会导致MOS管发热。经过多次测试5-20kHz是比较理想的区间。配置互补输出时一定要勾选CH Polarity和CHN Polarity这个决定了PWM的有效电平。AT8236芯片通常需要配置为高电平有效。刹车功能也很重要可以在Break and Dead Time Configuration里启用。当发生异常时硬件会自动切断PWM输出保护电机和驱动电路。我建议把Break Input配置为高电平有效这样可以通过一个IO口快速触发刹车。4. H桥驱动电路实战AT8236是一款性价比很高的H桥驱动芯片它内置了死区控制和过流保护。硬件连接时要注意VM接电机电源通常7-24VVCC接逻辑电源3.3V或5VIN1和IN2分别接TIM1_CH1和TIM1_CH1NOUT1和OUT2接电机两端调试时有个常见问题电机不转但有电流声。这通常是死区时间不足导致的。可以在CubeMX中调整Dead Time参数我一般设为1us左右。另一个常见问题是电机只能单向转这多半是互补输出配置错误检查CH1和CH1N的极性是否相反。实际布线时电机电源和MCU电源最好分开供电并用0.1uF电容就近滤波。我有次因为电源干扰导致PWM波形畸变电机转速不稳。后来在AT8236的VM引脚加了个100uF的电解电容就解决了。5. 电机控制代码实现CubeMX生成的代码框架已经帮我们初始化好了定时器我们只需要调用HAL库函数控制电机。先看基础功能实现// 启动电机正转 void Motor_Forward(uint16_t duty) { HAL_TIMEx_PWMN_Stop(htim1, TIM_CHANNEL_1); // 先关闭反向通道 __HAL_TIM_SET_COMPARE(htim1, TIM_CHANNEL_1, duty); // 设置占空比 HAL_TIM_PWM_Start(htim1, TIM_CHANNEL_1); // 开启正向通道 } // 启动电机反转 void Motor_Backward(uint16_t duty) { HAL_TIM_PWM_Stop(htim1, TIM_CHANNEL_1); // 先关闭正向通道 __HAL_TIM_SET_COMPARE(htim1, TIM_CHANNEL_1, duty); // 设置占空比 HAL_TIMEx_PWMN_Start(htim1, TIM_CHANNEL_1); // 开启反向通道 } // 刹车功能 void Motor_Brake(void) { HAL_TIM_PWM_Stop(htim1, TIM_CHANNEL_1); HAL_TIMEx_PWMN_Stop(htim1, TIM_CHANNEL_1); // 将两个输出都置为低电平 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_RESET); }在实际项目中我建议把电机控制封装成一个结构体方便管理状态typedef struct { uint8_t state; // 0:停止 1:正转 2:反转 uint16_t duty; // 当前占空比 uint16_t max_duty; // 最大占空比限制 } MotorCtrl; void Motor_SetSpeed(MotorCtrl *motor, int16_t speed) { // 限制速度范围 speed (speed motor-max_duty) ? motor-max_duty : speed; speed (speed 0) ? 0 : speed; if(speed 0) { Motor_Brake(); motor-state 0; } else if(speed 0) { Motor_Forward(speed); motor-state 1; } else { Motor_Backward(-speed); motor-state 2; } motor-duty abs(speed); }6. 调试技巧与常见问题调试电机驱动时示波器是必不可少的工具。我习惯先测量TIM1_CH1和CH1N的波形确认PWM参数是否正确。正常应该看到两个互补的方波之间有死区时间。如果发现波形畸变检查以下几点定时器时钟配置是否正确GPIO是否配置为复用推挽输出是否有其他外设冲突使用相同定时器电机启动时电流很大容易导致电源电压跌落。我遇到过MCU因此复位的状况。解决方法是在电源端加大电容或者采用软启动策略——逐步增加PWM占空比void Motor_SoftStart(MotorCtrl *motor, uint16_t target_duty) { uint16_t step target_duty / 10; for(uint16_t i0; itarget_duty; istep) { __HAL_TIM_SET_COMPARE(htim1, TIM_CHANNEL_1, i); HAL_Delay(50); } __HAL_TIM_SET_COMPARE(htim1, TIM_CHANNEL_1, target_duty); motor-duty target_duty; }另一个常见问题是电机停止时有惯性滑行。如果需要精确定位可以启用刹车功能。但要注意频繁刹车会导致H桥发热建议配合机械刹车使用。7. 进阶功能实现基础功能稳定后可以尝试更复杂的控制策略。比如通过编码器实现闭环控制// 使用TIM2编码器模式读取电机转速 int32_t Motor_GetSpeed(void) { static int32_t last_count 0; int32_t current_count TIM2-CNT; int32_t speed current_count - last_count; last_count current_count; return speed; } // PID速度控制 void Motor_PIDControl(MotorCtrl *motor, int32_t target_speed) { static int32_t last_error 0; static int32_t integral 0; int32_t actual_speed Motor_GetSpeed(); int32_t error target_speed - actual_speed; // 比例项 int32_t P error * motor-Kp; // 积分项 integral error; int32_t I integral * motor-Ki; // 微分项 int32_t D (error - last_error) * motor-Kd; last_error error; int32_t output P I D; Motor_SetSpeed(motor, output); }在实际项目中我还遇到过需要多电机同步的场景。这时可以使用TIM1的主从模式用一个定时器触发其他定时器确保所有PWM同步。具体做法是在CubeMX中将TIM1设为MasterTIM2/TIM3设为Slave触发源选择ITR0。

更多文章