STM32 HAL库驱动TB6612模块:精准控制编码电机转速与转向(附CubeMX配置)
STM32 HAL库驱动TB6612模块:精准控制编码电机转速与转向(附CubeMX配置)
在智能小车、机械臂等嵌入式项目中,电机控制往往是核心环节。TB6612作为一款高效直流电机驱动芯片,配合STM32的PWM输出和编码器接口,能够实现精准的转速与方向控制。本文将手把手带你完成从CubeMX配置到闭环控制的全流程实现。
1. 硬件架构与工作原理
TB6612FNG采用MOSFET构建H桥电路,相比传统晶体管方案具有更低导通损耗和更高开关频率。其核心功能可分解为三个部分:
- 功率驱动:VM引脚输入4.5-15V驱动电压,通过AO1/AO2和BO1/BO2输出到电机
- 逻辑控制:VCC引脚2.7-5.5V供电,接收来自MCU的PWM和方向信号
- 保护机制:内置过热关断和低压检测电路
编码电机则通过正交编码器提供转速反馈,典型接线方式如下:
| 线序 | 功能描述 | 连接目标 |
|---|---|---|
| 1 | 电机正极 | TB6612 AO1/AO2 |
| 2 | 编码器GND | MCU GND |
| 3 | 编码器B相(正交信号) | 定时器输入通道 |
| 4 | 编码器A相(正交信号) | 定时器输入通道 |
| 5 | 编码器电源(通常5V) | MCU 5V输出 |
| 6 | 电机负极 | TB6612 AO1/AO2 |
2. CubeMX基础配置
2.1 PWM生成配置
- 选择高级定时器(如TIM1/TIM8)
- 开启PWM Generation模式
- 设置预分频器(Prescaler)和自动重载值(ARR):
// 示例:72MHz主频下生成20kHz PWM htim1.Instance->PSC = 71; // 72MHz/(71+1) = 1MHz htim1.Instance->ARR = 49; // 1MHz/(49+1) = 20kHz - 配置Pulse值为ARR的一半作为初始占空比
2.2 编码器接口配置
- 选择通用定时器(如TIM2-TIM5)
- 设置为Encoder Mode
- 配置通道极性为Rising Edge
- 设置编码器分辨率:
// 4倍频计数模式 htim2.Init.Period = 65535; // 16位最大值
2.3 GPIO控制引脚
| 引脚功能 | 模式设置 | 初始化状态 |
|---|---|---|
| AIN1 | Output Push-Pull | Low |
| AIN2 | Output Push-Pull | Low |
| STBY | Output Push-Pull | High |
3. 电机驱动实现
3.1 方向控制逻辑
根据TB6612真值表实现方向控制函数:
void Motor_SetDirection(GPIO_TypeDef* IN1_Port, uint16_t IN1_Pin, GPIO_TypeDef* IN2_Port, uint16_t IN2_Pin, MotorDirection dir) { switch(dir) { case MOTOR_BRAKE: HAL_GPIO_WritePin(IN1_Port, IN1_Pin, GPIO_PIN_RESET); HAL_GPIO_WritePin(IN2_Port, IN2_Pin, GPIO_PIN_RESET); break; case MOTOR_CW: HAL_GPIO_WritePin(IN1_Port, IN1_Pin, GPIO_PIN_RESET); HAL_GPIO_WritePin(IN2_Port, IN2_Pin, GPIO_PIN_SET); break; case MOTOR_CCW: HAL_GPIO_WritePin(IN1_Port, IN1_Pin, GPIO_PIN_SET); HAL_GPIO_WritePin(IN2_Port, IN2_Pin, GPIO_PIN_RESET); break; } }3.2 速度控制实现
PWM占空比调节函数示例:
void Motor_SetSpeed(TIM_HandleTypeDef* htim, uint32_t Channel, uint16_t duty) { // 限制占空比范围 duty = (duty > htim->Instance->ARR) ? htim->Instance->ARR : duty; switch(Channel) { case TIM_CHANNEL_1: htim->Instance->CCR1 = duty; break; case TIM_CHANNEL_2: htim->Instance->CCR2 = duty; break; // 其他通道处理... } }4. 编码器测速与闭环控制
4.1 速度计算
采用定时中断法测量转速:
// 全局变量 int32_t encoder_count = 0; float rpm = 0.0f; // 定时器中断回调 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if(htim == &htim3) { // 1ms定时器 static int32_t last_count = 0; int32_t delta = encoder_count - last_count; // 计算RPM:delta/(PPR*4) * (60000/采样周期ms) rpm = (delta / (13.0f * 4)) * (60000.0f / 10.0f); last_count = encoder_count; encoder_count = 0; // 清零计数器 } }4.2 简易PID控制器
实现位置式PID算法:
typedef struct { float Kp, Ki, Kd; float integral; float prev_error; } PID_Controller; float PID_Update(PID_Controller* pid, float setpoint, float measurement) { float error = setpoint - measurement; pid->integral += error; if(pid->integral > 1000) pid->integral = 1000; if(pid->integral < -1000) pid->integral = -1000; float derivative = error - pid->prev_error; pid->prev_error = error; return pid->Kp * error + pid->Ki * pid->integral + pid->Kd * derivative; }5. 系统集成与调试技巧
5.1 典型问题排查
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 电机不转 | STBY引脚未使能 | 检查STBY引脚是否为高电平 |
| 只有一个转向 | 方向控制逻辑错误 | 验证真值表实现代码 |
| PWM无输出 | 定时器未启动 | 调用HAL_TIM_PWM_Start() |
| 编码器读数异常 | 信号线接触不良 | 检查接线并添加上拉电阻 |
5.2 性能优化建议
- PWM频率选择:
- 普通直流电机:5-20kHz
- 空心杯电机:建议>25kHz
- 抗干扰措施:
// 在编码器输入引脚配置上拉 GPIO_InitStruct.Pull = GPIO_PULLUP; - 速度滤波算法:
// 移动平均滤波 #define FILTER_SIZE 5 float speed_buffer[FILTER_SIZE]; float filtered_speed(float new_speed) { static uint8_t index = 0; speed_buffer[index++] = new_speed; if(index >= FILTER_SIZE) index = 0; float sum = 0; for(uint8_t i=0; i<FILTER_SIZE; i++) { sum += speed_buffer[i]; } return sum / FILTER_SIZE; }
在实际项目中,我发现电机启动时的电流冲击容易导致MCU复位。通过增加软启动算法——即PWM占空比从0开始按指数曲线递增,能有效避免这个问题。具体实现时,可以将目标速度作为PID的设定值,而不是直接控制PWM占空比。
