共计 2799 个字符,预计需要花费 7 分钟才能阅读完成。
硬件连接:搭建你的电机驱动系统
先来看硬件部分。STM32C8T6 作为主控,通过 TB6612 模块驱动带编码器的直流电机,这种组合在小型机器人、智能小车中很常见。关键是要正确连接三部分:
- 电源部分
- TB6612 的 VM 引脚接电机电源(建议 7.2V-12V)
- VCC 接 5V 逻辑电源(可与 C8T6 共用)
-
务必在 VM 和 GND 之间加 100μF 电解电容 +0.1μF 陶瓷电容滤波
-
控制信号连接
- PWM 输入:C8T6 的 TIM1_CH1(PA8)接 TB6612 的 PWMA
- 方向控制:PG6 接 AIN1,PG7 接 AIN2(注意 IO 口驱动能力)
-
待机控制:PG8 接 STBY(高电平使能)
-
编码器接口
- 编码器 A 相接 PA0(TIM5_CH1)
- 编码器 B 相接 PA1(TIM5_CH2)
- 推荐使用 1kΩ 上拉电阻增强信号

CubeMX 配置:让硬件动起来
PWM 生成配置(以 TIM1 为例)
- 打开 CubeMX,选择 TIM1
- Clock Source 选择 Internal Clock
- Channel1 选择 PWM Generation CH1
- 参数设置:
- Prescaler: 71 (72MHz/(71+1)=1MHz)
- Counter Period: 999 (产生 1kHz PWM)
- Pulse: 初始占空比设为 0
- 生成代码时勾选 ”Generate IRQ handler”
编码器模式配置(TIM5)
- 选择 TIM5
- Combined Channels 选择 Encoder Mode
- 参数注意:
- Polarity 保持 Rising Edge
- 取消勾选 ”auto-reload preload”
- 在 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
性能验证与优化
使用示波器抓取的关键信号:
- PWM 波形(应保持 1kHz 恒定频率)
- 编码器脉冲(检查上升 / 下降沿是否清晰)
- 电机电流(突加负载时不应有剧烈波动)
实测数据示例:
– 空载响应时间:<50ms
– 速度控制精度:±3RPM(@120RPM)
思考与拓展
在实际测试中,我们发现编码器采样频率与电机转速需要匹配:
– 低速时(<50RPM),建议降低采样频率以减少噪声
– 高速时(>300RPM),需要提高采样频率防止丢失脉冲
开放性问题:如何动态调整编码器采样频率以适应不同转速场景?可以考虑以下方向:
1. 根据转速自动重配置 TIM5 预分频器
2. 使用自适应滤波算法
3. 引入速度预测机制
正文完
