1. 项目背景与核心需求
直流电机正反转控制在机器人底盘、智能小车、工业传送带等场景中极为常见。BTS7960作为一款大电流半桥驱动芯片,能够轻松驱动两个直流电机实现正反转、调速等操作。这个项目要解决的问题是:如何通过单片机程序精确控制BTS7960模块,实现双直流电机的独立正反转控制。
我在去年设计一个自动搬运机器人时,就遇到过电机突然反转导致货物散落的问题。后来发现是PWM信号占空比切换时的时序没处理好。这个项目会分享经过实战验证的稳定控制方案,包含硬件连接细节、软件防抖策略以及异常处理机制。
2. 硬件架构解析
2.1 BTS7960模块特性
BTS7960是英飞凌推出的43A大电流半桥驱动芯片,其主要参数:
- 工作电压:5.5V-27V
- 峰值电流:43A(需配合散热片)
- 内置过流、过温、欠压保护
- 典型导通电阻:16mΩ
双电机驱动通常需要两个BTS7960模块,每个模块包含:
- 两路半桥电路(IN/INH引脚控制)
- 电流检测输出(IS引脚)
- 故障状态输出(SR引脚)
2.2 典型接线方案
以STM32F103为例的接线方式:
| MCU引脚 | BTS7960引脚 | 功能说明 |
|---|---|---|
| PA8 | IN1 | 电机1方向 |
| PA9 | IN2 | 电机1方向 |
| PA10 | INH1 | 电机1使能 |
| PB6 | IN3 | 电机2方向 |
| PB7 | IN4 | 电机2方向 |
| PB8 | INH2 | 电机2使能 |
关键提示:INH引脚必须接PWM才能调速,若仅需开关控制可接普通IO口
3. 核心控制逻辑实现
3.1 正反转真值表
每个电机的控制逻辑如下:
| IN1 | IN2 | INH | 电机状态 |
|---|---|---|---|
| 0 | 1 | PWM | 正转 |
| 1 | 0 | PWM | 反转 |
| 0 | 0 | X | 刹车 |
| 1 | 1 | X | 禁止状态(可能短路) |
3.2 基础驱动代码(基于HAL库)
c复制// 电机控制结构体
typedef struct {
GPIO_TypeDef* IN1_Port;
uint16_t IN1_Pin;
GPIO_TypeDef* IN2_Port;
uint16_t IN2_Pin;
TIM_HandleTypeDef* PWM_Timer;
uint32_t PWM_Channel;
} MotorCtrl_TypeDef;
// 电机动作枚举
typedef enum {
MOTOR_STOP,
MOTOR_CW, // 顺时针
MOTOR_CCW // 逆时针
} MotorAction;
void Motor_Control(MotorCtrl_TypeDef* motor, MotorAction action, uint8_t speed) {
switch(action) {
case MOTOR_CW:
HAL_GPIO_WritePin(motor->IN1_Port, motor->IN1_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(motor->IN2_Port, motor->IN2_Pin, GPIO_PIN_SET);
__HAL_TIM_SET_COMPARE(motor->PWM_Timer, motor->PWM_Channel, speed);
break;
case MOTOR_CCW:
HAL_GPIO_WritePin(motor->IN1_Port, motor->IN1_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(motor->IN2_Port, motor->IN2_Pin, GPIO_PIN_RESET);
__HAL_TIM_SET_COMPARE(motor->PWM_Timer, motor->PWM_Channel, speed);
break;
default: // STOP
HAL_GPIO_WritePin(motor->IN1_Port, motor->IN1_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(motor->IN2_Port, motor->IN2_Pin, GPIO_PIN_RESET);
__HAL_TIM_SET_COMPARE(motor->PWM_Timer, motor->PWM_Channel, 0);
}
}
4. 高级控制策略
4.1 软启动/软停止实现
突然的启停会导致机械冲击,通过PWM渐变实现平滑控制:
c复制void Motor_SoftStart(MotorCtrl_TypeDef* motor, MotorAction action, uint16_t duration_ms) {
uint32_t start_tick = HAL_GetTick();
uint8_t step = 0;
while((HAL_GetTick() - start_tick) < duration_ms) {
step = (HAL_GetTick() - start_tick) * 255 / duration_ms;
Motor_Control(motor, action, step);
HAL_Delay(10);
}
Motor_Control(motor, action, 255); // 确保达到全速
}
4.2 堵转检测方案
通过电流检测引脚(IS)监测异常:
c复制#define MOTOR_NORMAL_CURRENT 200 // ADC原始值基准
uint8_t Check_Stall(ADC_HandleTypeDef* hadc, uint16_t threshold) {
uint32_t adc_val = 0;
HAL_ADC_Start(hadc);
adc_val = HAL_ADC_GetValue(hadc);
if(adc_val > (MOTOR_NORMAL_CURRENT + threshold)) {
return 1; // 堵转发生
}
return 0;
}
5. 实战经验与避坑指南
5.1 死区时间配置
方向切换时必须插入5-10ms延时,防止H桥上下管直通:
c复制void Motor_ChangeDirection(MotorCtrl_TypeDef* motor, MotorAction new_action) {
Motor_Control(motor, MOTOR_STOP, 0); // 先停止
HAL_Delay(8); // 关键死区时间
Motor_Control(motor, new_action, 100); // 以较低速启动
}
5.2 PCB布局建议
- 电源走线宽度不小于2mm(10A电流时)
- 每个BTS7960的VBB引脚就近放置100uF电解电容
- 电机接口采用端子台或XT30连接器
- 散热片与芯片间涂抹导热硅脂
5.3 典型问题排查表
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 电机单方向不转 | IN1/IN2信号反相 | 检查控制逻辑真值表 |
| PWM调速无反应 | INH未使能 | 确认INH引脚接的是PWM信号 |
| 芯片异常发热 | 负载过重或短路 | 测量工作电流,检查机械结构 |
| 随机误动作 | 地线干扰 | 加强电源滤波,缩短信号线 |
6. 完整工程框架示例
建议的项目文件结构:
code复制/BTS7960_DualMotor
├── Core
│ ├── Src
│ │ ├── motor.c # 驱动核心实现
│ │ ├── protection.c # 保护功能
│ │ └── smooth.c # 软启停算法
├── Drivers
└── Inc
├── motor.h # 对外接口
└── motor_cfg.h # 引脚配置
关键头文件示例(motor_cfg.h):
c复制// 电机1配置
#define M1_IN1_GPIO GPIOA
#define M1_IN1_PIN GPIO_PIN_8
#define M1_IN2_GPIO GPIOA
#define M1_IN2_PIN GPIO_PIN_9
#define M1_PWM_TIM &htim1
#define M1_PWM_CH TIM_CHANNEL_1
// 电机2配置
#define M2_IN1_GPIO GPIOB
#define M2_IN1_PIN GPIO_PIN_6
#define M2_IN2_GPIO GPIOB
#define M2_IN2_PIN GPIO_PIN_7
#define M2_PWM_TIM &htim4
#define M2_PWM_CH TIM_CHANNEL_2
在实际项目中,我会额外添加运动轨迹规划功能。比如通过加速度曲线生成PWM变化序列,这对搬运机械臂这类需要精确定位的场景特别有用。一个经验是:当电机负载惯性较大时,软停止时间应该比软启动长20%-30%,能有效避免机械振动。