基于HAL库的C8T6与TB6612驱动编码器电机实战指南

1次阅读
没有评论

共计 2799 个字符,预计需要花费 7 分钟才能阅读完成。

image.webp

硬件连接:搭建你的电机驱动系统

先来看硬件部分。STM32C8T6 作为主控,通过 TB6612 模块驱动带编码器的直流电机,这种组合在小型机器人、智能小车中很常见。关键是要正确连接三部分:

  1. 电源部分
  2. TB6612 的 VM 引脚接电机电源(建议 7.2V-12V)
  3. VCC 接 5V 逻辑电源(可与 C8T6 共用)
  4. 务必在 VM 和 GND 之间加 100μF 电解电容 +0.1μF 陶瓷电容滤波

  5. 控制信号连接

  6. PWM 输入:C8T6 的 TIM1_CH1(PA8)接 TB6612 的 PWMA
  7. 方向控制:PG6 接 AIN1,PG7 接 AIN2(注意 IO 口驱动能力)
  8. 待机控制:PG8 接 STBY(高电平使能)

  9. 编码器接口

  10. 编码器 A 相接 PA0(TIM5_CH1)
  11. 编码器 B 相接 PA1(TIM5_CH2)
  12. 推荐使用 1kΩ 上拉电阻增强信号

基于 HAL 库的 C8T6 与 TB6612 驱动编码器电机实战指南

CubeMX 配置:让硬件动起来

PWM 生成配置(以 TIM1 为例)

  1. 打开 CubeMX,选择 TIM1
  2. Clock Source 选择 Internal Clock
  3. Channel1 选择 PWM Generation CH1
  4. 参数设置:
  5. Prescaler: 71 (72MHz/(71+1)=1MHz)
  6. Counter Period: 999 (产生 1kHz PWM)
  7. Pulse: 初始占空比设为 0
  8. 生成代码时勾选 ”Generate IRQ handler”

编码器模式配置(TIM5)

  1. 选择 TIM5
  2. Combined Channels 选择 Encoder Mode
  3. 参数注意:
  4. Polarity 保持 Rising Edge
  5. 取消勾选 ”auto-reload preload”
  6. 在 NVIC 中启用 TIM5 全局中断
// PWM 启动示例
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);

核心代码实现

电机驱动函数

// 设置电机方向和速度
void Motor_Set(int16_t speed) {
    // 速度限制在±1000
    speed = constrain(speed, -1000, 1000);

    // 方向控制
    if(speed > 0) {HAL_GPIO_WritePin(GPIOG, GPIO_PIN_6, GPIO_PIN_SET);
        HAL_GPIO_WritePin(GPIOG, GPIO_PIN_7, GPIO_PIN_RESET);
    } else {HAL_GPIO_WritePin(GPIOG, GPIO_PIN_6, GPIO_PIN_RESET);
        HAL_GPIO_WritePin(GPIOG, GPIO_PIN_7, GPIO_PIN_SET);
    }

    // PWM 输出
    __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, abs(speed));
}

编码器速度计算

// 全局变量
int32_t encoder_count = 0;
float rpm = 0;

// 在 TIM5 中断回调中
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) {if(htim == &htim5) {
        static uint16_t last_count = 0;
        uint16_t current_count = __HAL_TIM_GET_COUNTER(&htim5);

        // 处理溢出(编码器 13 线,4 倍频后每转 52 脉冲)int16_t delta = (current_count - last_count) & 0xFFFF;
        if(delta > 32767) delta -= 65536;

        encoder_count += delta;
        last_count = current_count;

        // 每 100ms 计算一次 RPM
        static uint32_t last_tick = 0;
        if(HAL_GetTick() - last_tick > 100) {rpm = (delta * 600.0f) / (52.0f * 0.1f);
            last_tick = HAL_GetTick();}
    }
}

PID 闭环控制实现

// PID 结构体
typedef struct {
    float Kp, Ki, Kd;
    float integral;
    float last_error;
} PID_Controller;

// PID 计算
float PID_Update(PID_Controller *pid, float error, float dt) {float derivative = (error - pid->last_error) / dt;
    pid->integral += error * dt;
    pid->last_error = error;

    // 积分限幅
    pid->integral = constrain(pid->integral, -1000, 1000);

    return pid->Kp * error + 
           pid->Ki * pid->integral + 
           pid->Kd * derivative;
}

// 使用示例
PID_Controller speed_pid = {0.8f, 0.2f, 0.05f};

void Control_Loop() {
    float target_rpm = 120.0f; // 目标转速
    float current_rpm = get_filtered_rpm(); // 获取滤波后的转速

    float output = PID_Update(&speed_pid, target_rpm - current_rpm, 0.01f);
    Motor_Set((int16_t)output);
}

常见问题解决方案

电机抖动问题

  • 现象:电机启动时明显抖动
  • 解决方案:
  • 检查电源:用示波器观察 VBAT 电压,波动应小于 5%
  • 增加硬件滤波:在电机两端并联 0.1μF 陶瓷电容
  • 软件处理:PWM 启动时采用渐变方式
// 软启动示例
for(int i=0; i<100; i+=5) {__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, i);
    HAL_Delay(10);
}

编码器计数丢失

  • 现象:高速旋转时计数不准确
  • 解决方案:
  • 检查接线:编码器线建议使用双绞线
  • 调整采样频率:降低 TIM5 的输入滤波参数
  • 修改代码:
// 在 CubeMX 中将 TIM5 的输入捕获滤波器 (IC Filter) 设为 2
// 对应寄存器设置:TIM5->CCMR1 |= (2 << 12); // IC1F=2
TIM5->CCMR1 |= (2 << 4);  // IC2F=2

性能验证与优化

使用示波器抓取的关键信号:

  1. PWM 波形(应保持 1kHz 恒定频率)
  2. 编码器脉冲(检查上升 / 下降沿是否清晰)
  3. 电机电流(突加负载时不应有剧烈波动)

实测数据示例:
– 空载响应时间:<50ms
– 速度控制精度:±3RPM(@120RPM)

思考与拓展

在实际测试中,我们发现编码器采样频率与电机转速需要匹配:
– 低速时(<50RPM),建议降低采样频率以减少噪声
– 高速时(>300RPM),需要提高采样频率防止丢失脉冲

开放性问题:如何动态调整编码器采样频率以适应不同转速场景?可以考虑以下方向:
1. 根据转速自动重配置 TIM5 预分频器
2. 使用自适应滤波算法
3. 引入速度预测机制

正文完
 0
评论(没有评论)