STM32F103ZET6与TB6612电机驱动实战:从CubeMX配置到代码调试的全流程避坑指南
当你第一次尝试用STM32驱动直流电机时,可能会遇到各种令人抓狂的问题——PWM没有输出、电机纹丝不动、转速控制不精准,甚至出现莫名其妙的反转现象。本文将以正点原子精英板和TB6612驱动模块为例,带你系统性地解决这些典型问题。不同于网上零散的教程,我们将重点关注那些容易忽略的细节配置和调试技巧,确保你的电机控制项目一次成功。
1. 硬件连接与TB6612逻辑解析
在开始软件配置前,正确的硬件连接是基础。TB6612作为一款高效的双路直流电机驱动芯片,其逻辑控制需要特别注意。
典型连接方案:
- STM32的PWM输出引脚(如TIM4_CH1)连接TB6612的PWMA
- 两个GPIO(如PE1、PE2)分别连接AIN1和AIN2
- VM接5V电源(注意电流需满足电机需求)
- VCC接3.3V逻辑电源
- AO1和AO2连接电机两极
TB6612真值表:
| IN1 | IN2 | PWM | 电机状态 |
|---|---|---|---|
| 0 | 0 | X | 刹车 |
| 1 | 0 | 有效 | 正转 |
| 0 | 1 | 有效 | 反转 |
| 1 | 1 | X | 刹车 |
关键提示:实际使用中发现,某些TB6612模块需要将STBY引脚拉高才能工作,这个细节常被忽略导致电机不转。
2. CubeMX关键配置详解
2.1 时钟树配置陷阱
新手最常见的错误就是时钟配置不当。STM32F103ZET6的最高主频为72MHz,但默认内部时钟只有8MHz。
正确配置步骤:
- 在RCC配置中启用HSE(外部高速晶振)
- 进入Clock Configuration界面
- 将PLL源选择为HSE
- 设置PLL倍频系数为9(8MHz × 9 = 72MHz)
- 系统时钟选择PLLCLK
// 验证系统时钟的简易方法
printf("System Clock: %ld Hz\n", HAL_RCC_GetSysClockFreq());
2.2 定时器PWM生成配置
以TIM4为例,生成10kHz PWM的配置要点:
- 选择内部时钟源(Internal Clock)
- 设置预分频器(PSC)为71(72MHz / (71+1) = 1MHz)
- 自动重装载值(ARR)设为99(1MHz / (99+1) = 10kHz)
- PWM模式选择PWM Mode 1
- 使能输出比较预装载(Output Compare Preload)
参数计算公式:
PWM频率 = 定时器时钟 / (PSC + 1) / (ARR + 1)
占空比 = CCR / (ARR + 1)
调试技巧:用示波器测量PWM输出前,先确认GPIO模式已正确设置为复用推挽输出(Alternate Function Push-Pull)
3. 代码实现中的典型问题
3.1 PWM启动时机问题
很多初学者忘记启动PWM,或者启动顺序错误:
// 错误的初始化顺序
Motor_SetSpeed(50); // 此时PWM还未启动
HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_1);
// 正确的初始化顺序
HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_1); // 先启动PWM
Motor_SetSpeed(50); // 再设置速度
3.2 电机控制函数实现
一个健壮的电机控制函数应处理各种边界情况:
// motor.c
void Motor_SetSpeed(int16_t speed)
{
// 限制速度值在合理范围内
speed = (speed > 100) ? 100 : speed;
speed = (speed < -100) ? -100 : speed;
if(speed > 0) {
// 正转
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_1, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_2, GPIO_PIN_RESET);
__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_1, speed);
}
else if(speed < 0) {
// 反转
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_1, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_2, GPIO_PIN_SET);
__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_1, -speed);
}
else {
// 停止
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_1, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_2, GPIO_PIN_RESET);
__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_1, 0);
}
}
4. 调试技巧与问题排查
当电机不工作时,建议按照以下步骤排查:
-
检查电源 :
- 测量VM电压是否达到电机要求
- 确认逻辑电源VCC为3.3V
-
验证PWM信号 :
# 使用STM32CubeMonitor实时监控PWM输出 $ stm32cubemonitor --pwm TIM4 1 -
逻辑信号测试 :
// 临时测试代码 HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_1); // 手动切换IN1 HAL_Delay(500); -
常见问题速查表 :
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 电机完全不转 | STBY引脚未拉高 | 将STBY连接至3.3V |
| PWM无输出 | 定时器未启动 | 调用HAL_TIM_PWM_Start() |
| 电机振动但不转 | PWM频率过高 | 调整ARR降低频率至1-20kHz |
| 方向控制相反 | IN1/IN2接线反了 | 交换IN1和IN2的连接 |
| 转速不稳定 | 电源功率不足 | 使用独立电源供电 |
5. 进阶优化与性能提升
5.1 死区时间配置
为防止H桥上下管直通,可配置死区时间:
// 在CubeMX中配置Dead Time
htim4.Instance->BDTR |= (10 << 0); // 设置约1us的死区时间
5.2 速度平滑处理
加入简单的滤波算法使速度变化更平滑:
#define FILTER_WEIGHT 0.2f
float current_speed = 0;
void Smooth_SetSpeed(float target)
{
current_speed = (1-FILTER_WEIGHT)*current_speed + FILTER_WEIGHT*target;
Motor_SetSpeed((int16_t)current_speed);
}
5.3 使用编码器反馈
如果需要精确速度控制,可增加编码器接口:
- 配置TIM2为编码器模式
- 连接编码器A/B相
- 定期读取计数器值计算转速
// 编码器速度计算示例
int32_t last_count = 0;
float rpm = 0;
void Update_Speed(void)
{
int32_t current_count = __HAL_TIM_GET_COUNTER(&htim2);
rpm = (current_count - last_count) * 60 / ENCODER_PPR;
last_count = current_count;
}
在项目后期调试中发现,电机线缆过长会引入干扰,导致PWM信号畸变。这种情况下,可以在GPIO输出端添加100Ω电阻和100nF电容组成简单滤波电路,效果立竿见影。
445

被折叠的 条评论
为什么被折叠?



