STM32循迹小车系列教程(二)—— 深入TB6612电机驱动与PWM调速实战
1. TB6612电机驱动芯片深度解析第一次拿到TB6612芯片时我盯着那密密麻麻的引脚有点发懵。这玩意儿比L298N小巧精致多了但功能却强大不少。实测下来TB6612的发热控制确实优秀连续工作半小时芯片也只是微温这点比L298N强太多。TB6612内部其实是两个完整的H桥电路每个H桥由四个MOSFET组成。简单来说H桥就像个智能开关矩阵通过不同开关组合实现电机的正反转控制。我画了个简化示意图帮助理解VM ----[MOS1]----电机----[MOS4]----GND | | [MOS2] [MOS3]当MOS1和MOS4导通时电流从左到右流过电机正转MOS2和MOS3导通时电流反向电机就反转。如果四个MOS管全关电机自然就停了。这种设计巧妙避免了电源短路的风险。芯片的引脚功能需要特别注意VM接电机电源建议6-12VVCC接逻辑电源3.3V或5VSTBY必须接高电平才能工作AO1/AO2和BO1/BO2接电机PWMA/PWMB接PWM信号AIN1/AIN2和BIN1/BIN2控制转向注意VM和VCC一定要分开供电我有次偷懒共用了电源结果电机一启动芯片就重启排查了半天才发现问题。2. PWM调速的实战技巧PWM调速看似简单但实际调试时遇到过不少坑。先说频率选择经过多次测试我发现10kHz是个比较理想的数值。频率太低电机会啸叫太高又会导致MOS管开关损耗增大。在STM32上配置PWM时有几个关键参数要注意定时器时钟通常72MHz预分频值(Prescaler)决定定时器计数频率自动重装载值(Period)决定PWM周期计算公式是 PWM频率 定时器时钟 / (Prescaler 1) / (Period 1)比如要得到10kHz PWM 72,000,000 / (72-1) / (100-1) ≈ 10.1kHz占空比调节有个细节容易被忽略STM32的PWM占空比是相对于Period值计算的。如果Period设为100那么50就是50%占空比。但有些新手会误以为占空比是直接百分比数值结果电机要么不动要么全速。// 正确的占空比设置示例 __HAL_TIM_SET_COMPARE(htim3, TIM_CHANNEL_1, 70); // 70%占空比实测中发现电机在低占空比时可能出现启动困难。这时可以先用较高占空比启动再缓慢降低到目标值类似汽车的斜坡启动策略。3. 硬件连接避坑指南第一次组装循迹小车时我在电机驱动这部分栽了不少跟头。最惨痛的是电源问题 - 电机启动瞬间的电流冲击会导致电压骤降导致单片机复位。后来学乖了给STM32和TB6612使用独立稳压供电问题迎刃而解。接线时要特别注意电机电源与逻辑电源必须共地PWM信号线要尽量短避免干扰大电流走线要足够粗建议18AWG以上最好在VM端加个大容量电解电容1000uF以上常见故障排查电机不转先检查STBY引脚是否接高电平只能单向转检查AIN1/AIN2电平组合转速异常用示波器查看PWM波形是否正常芯片发热严重检查电机是否堵转或短路有个特别隐蔽的坑杜邦线接触不良。有次调试时电机时好时坏最后发现是杜邦线插接松动导致的。后来我都改用焊接连接可靠性大幅提升。4. 闭环速度控制实现开环PWM控制有个明显缺点负载变化时转速会波动。为了精准控制我尝试给小车加上编码器实现闭环控制。这里分享下我的实现方案。首先需要在电机上安装编码器模块常见的有霍尔编码器和光电编码器。我选用的是600线光电编码器通过STM32的定时器编码器接口读取脉冲数。速度计算的核心代码// 在定时器中断中计算转速 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if(htim htim4) // 编码器定时器 { static int32_t last_count 0; int32_t current_count __HAL_TIM_GET_COUNTER(htim4); int32_t delta current_count - last_count; speed_rpm delta * 60 / ENCODER_RESOLUTION; // 转为RPM last_count current_count; } }然后实现PID控制器// 简易PID实现 float pid_update(PID_TypeDef *pid, float current, float target) { float error target - current; pid-integral error; if(pid-integral pid-max_i) pid-integral pid-max_i; if(pid-integral -pid-max_i) pid-integral -pid-max_i; float derivative error - pid-last_error; pid-last_error error; return pid-kp * error pid-ki * pid-integral pid-kd * derivative; }调试PID参数是个耐心活我的经验是从小到大逐步调整先设kikd0增大kp直到出现轻微震荡然后加入ki消除静差最后加kd抑制超调5. 进阶技巧与性能优化当基本功能都实现后我开始琢磨如何进一步提升驱动性能。首先是对PWM波形进行优化发现互补输出带死区控制可以显著降低MOS管损耗。STM32的高级定时器如TIM1/TIM8支持死区插入配置代码如下// 死区时间配置 BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig {0}; sBreakDeadTimeConfig.OffStateRunMode TIM_OSSR_DISABLE; sBreakDeadTimeConfig.OffStateIDLEMode TIM_OSSI_DISABLE; sBreakDeadTimeConfig.LockLevel TIM_LOCKLEVEL_OFF; sBreakDeadTimeConfig.DeadTime 54; // 约750ns死区时间 sBreakDeadTimeConfig.BreakState TIM_BREAK_DISABLE; sBreakDeadTimeConfig.BreakPolarity TIM_BREAKPOLARITY_HIGH; sBreakDeadTimeConfig.AutomaticOutput TIM_AUTOMATICOUTPUT_DISABLE; if (HAL_TIMEx_ConfigBreakDeadTime(htim1, sBreakDeadTimeConfig) ! HAL_OK) { Error_Handler(); }另一个优化点是电流检测。TB6612虽然没有内置电流检测但可以在电机回路串联小阻值电阻如0.1Ω通过运放放大电压信号实现电流采样。这对过流保护很有帮助。最后分享一个实用技巧利用STM32的硬件刹车功能。当检测到异常时可以立即触发刹车输入快速切断电机驱动// 紧急刹车函数 void motor_brake(void) { HAL_TIMEx_PWMN_Stop(htim1, TIM_CHANNEL_1); HAL_TIM_PWM_Stop(htim1, TIM_CHANNEL_1); HAL_GPIO_WritePin(BRAKE_GPIO_Port, BRAKE_Pin, GPIO_PIN_SET); }