1. TB6612电机驱动模块基础解析
TB6612FNG是专为直流电机驱动设计的双H桥集成电路,相比传统的L298N,它的效率更高、发热更少。我在多个机器人项目中实测发现,TB6612在12V电压下持续工作半小时,芯片表面温度仅比环境温度高10℃左右,而L298N在同样条件下会烫到无法触碰。
这个模块最实用的特性是支持双路电机独立控制,每路可输出1.2A连续电流(峰值3.2A)。对于四轮小车,我们通常使用两个TB6612模块,或者选择现成的四路驱动板。模块的VM引脚接7-12V电源,VCC接5V逻辑电源,要注意这两个电源必须共地。
PWM控制原理可以用水龙头来类比:PWM频率相当于开关水龙头的速度,占空比相当于每次打开时水流的大小。在TB6612中:
- 当PWM占空比为100%时,电机获得全电压
- 50%占空比时,电机平均电压减半
- 0%占空比则完全停止
实际接线时有个容易踩坑的地方:STBY(待机)引脚必须接高电平,否则所有电机都不会工作。我遇到过好几次电机不转的情况,最后发现都是忘记连接这个引脚。
2. STM32定时器多通道PWM配置实战
STM32的定时器功能强大但也最让人头疼。以TIM4为例,它的四个通道对应引脚是PB6-PB9,但不同型号的STM32引脚映射可能不同。比如在STM32F103C8T6上确实如此,但在F407上就变成了PD12-PD15。建议在CubeMX里确认具体映射关系。
配置过程可以分解为五个关键步骤:
- 时钟使能:先打开TIM4和GPIOB的时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);- 定时器基础设置:
TIM_TimeBaseStructure.TIM_Period = 999; // ARR值 TIM_TimeBaseStructure.TIM_Prescaler = 71; // 72分频 TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);这里计算实际PWM频率:72MHz/(71+1)/(999+1)=1kHz
- 通道配置(以通道1为例):
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OC1Init(TIM4, &TIM_OCInitStructure); TIM_OC1PreloadConfig(TIM4, TIM_OCPreload_Enable);- GPIO复用配置:
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOB, &GPIO_InitStructure);- 方向控制引脚:
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOD, &GPIO_InitStructure);调试时常见问题:
- PWM无输出:检查时钟使能、GPIO复用模式
- 频率不对:重新计算Prescaler和Period
- 电机抖动:尝试调整PWM频率(1-5kHz最佳)
3. MSP432定时器配置的差异与技巧
MSP432的Timer_A与STM32的定时器有很大不同。最明显的区别是MSP432的CCR寄存器是数组形式,通过索引访问,而STM32是独立寄存器。实测发现MSP432P401R的Timer_A0有7个CCR寄存器,但只有CCR1-CCR4有对应输出引脚。
配置流程对比:
| 功能 | STM32实现方式 | MSP432实现方式 |
|---|---|---|
| 时钟源选择 | 默认APB时钟 | 显式选择SMCLK/ACLK |
| 分频设置 | Prescaler寄存器 | clockSourceDivider参数 |
| 输出模式 | PWM1/PWM2模式 | 8种输出模式组合 |
| 引脚配置 | 复用推挽输出 | 外设模块功能输出 |
MSP432的关键配置代码:
pwmConfig.clockSource = TIMER_A_CLOCKSOURCE_SMCLK; pwmConfig.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_64; pwmConfig.timerPeriod = 4499; // 对应ARR pwmConfig.compareOutputMode = TIMER_A_OUTPUTMODE_TOGGLE_SET;特别注意:MSP432的GPIO配置更简洁:
GPIO_setAsPeripheralModuleFunctionOutputPin( GPIO_PORT_P2, GPIO_PIN4 | GPIO_PIN5, GPIO_PRIMARY_MODULE_FUNCTION);我在调试时发现一个坑:如果PWM频率超过10kHz,某些廉价电机驱动模块会出现响应延迟,导致控制不精准。建议保持在1-5kHz范围内。
4. 四轮驱动控制算法实现
要让小车实现精准运动,需要建立运动模型。假设四个电机分别位于A(右前)、B(右后)、C(左后)、D(左前)位置:
基础运动模式:
- 前进:A=B=C=D=正速
- 后退:A=B=C=D=负速
- 右转:A=D=负速,B=C=正速
- 左转:A=D=正速,B=C=负速
更复杂的差速转向需要计算内外轮速比。以右转为例:
float ratio = 0.3; // 转向系数 motor( base_speed * (1-ratio), // 右前轮 base_speed * (1+ratio), // 右后轮 base_speed * (1-ratio), // 左后轮 base_speed * (1+ratio) // 左前轮 );实际项目中我推荐使用结构体封装电机参数:
typedef struct { int speed; GPIO_Pin dir_pin; TIM_TypeDef* timer; uint32_t channel; } Motor_TypeDef;这样驱动函数更清晰:
void drive_motor(Motor_TypeDef* m) { if(m->speed >=0) { GPIO_WriteBit(m->dir_port, m->dir_pin, 0); *m->ccr = m->speed; } else { GPIO_WriteBit(m->dir_port, m->dir_pin, 1); *m->ccr = -m->speed; } }对于需要精确控制的场合,可以加入PID算法。我常用的位置式PID实现:
typedef struct { float Kp, Ki, Kd; float integral; float last_error; } PID_Controller; float pid_update(PID_Controller* pid, float error) { pid->integral += error; float derivative = error - pid->last_error; pid->last_error = error; return pid->Kp*error + pid->Ki*pid->integral + pid->Kd*derivative; }调试时建议先用示波器观察PWM波形,再用万用表测量电机两端电压,最后实际上车测试。记得给电机两端并联续流二极管,防止反向电动势损坏驱动芯片。