3. GPIO基础与电机驱动:GPIO配置、H桥电路原理、L298N驱动直流电机
各位同学,今天我们来聊聊电机控制里最基础、也最绕不开的一环——GPIO和H桥。
说实话,很多新手一上来就盯着PID算法、FOC控制这些高大上的东西。但我见过太多项目,最后卡在最简单的电机转不转、转反了、或者烧了驱动芯片这种问题上。嗯,咱们先把地基打牢。
3.1 GPIO配置——别小看这玩意儿
GPIO,全称General Purpose Input Output,通用输入输出口。说白了,就是芯片的“手脚”。
在STM32里,每个GPIO引脚可以配置成多种模式。驱动电机时,我们最常用的是推挽输出模式。
推挽输出 vs 开漏输出
推挽输出:既能输出高电平,也能输出低电平。驱动能力强,适合直接控制逻辑电平。
开漏输出:只能输出低电平,高电平要靠外部上拉电阻。一般用于I2C总线。
驱动电机驱动芯片(比如L298N),请用推挽输出。
我个人习惯,在初始化GPIO时,会顺带把时钟使能、模式、速度、上下拉全部配好。别偷懒,少配一个都可能出问题。
// 以STM32F103为例,配置PA0和PA1为推挽输出
void Motor_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOA时钟
GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出
GPIO_InitStruct.Pull = GPIO_NOPULL; // 无上下拉
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; // 低速即可
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
小技巧:电机控制用的GPIO,速度不用设太高。设成LOW就够了。设高了反而容易引入噪声干扰。我在一个项目中吃过这个亏,GPIO速度设成HIGH,结果电机一启动,旁边的传感器数据就乱跳。
3.2 H桥电路原理——电机正反转的秘密
直流电机怎么让它正转、反转?答案就是H桥。
H桥这个名字,来源于它的电路形状像字母“H”。四个开关管(通常是MOS管或三极管)组成桥臂,电机接在中间。
你想想看:
- 左上和右下导通:电流从左往右流过电机 → 正转
- 右上和左下导通:电流从右往左流过电机 → 反转
- 同一侧两个同时导通:短路!烧管子!
致命禁忌:绝对不能让同一侧的上下两个开关同时导通!这叫“直通”,瞬间电流会大到烧毁MOS管。我曾经亲眼见过一个实习生,代码里延时写错了,H桥直通,MOS管直接冒烟。嗯,那味道很难忘。
下面我用一张SVG图,把H桥的核心逻辑画出来。你看一眼就明白了。
正转时,Q1和Q4导通,电流从VCC→Q1→电机→Q4→GND。反转时,Q2和Q3导通,电流反向流过电机。
3.3 L298N驱动直流电机——实战来了
自己搭H桥?可以,但没必要。市面上有现成的驱动芯片,L298N就是最经典的一款。
L298N内部集成了两个H桥,可以同时驱动两个直流电机。它需要:
- 一个逻辑电源(5V),给芯片内部逻辑供电
- 一个电机电源(6V-12V),给电机供电
- 四个控制引脚(IN1、IN2、IN3、IN4),控制两个电机的正反转
- 两个使能引脚(ENA、ENB),用PWM控制电机速度
| IN1 | IN2 | 电机A状态 |
|---|---|---|
| 0 | 0 | 刹车(停止) |
| 0 | 1 | 反转 |
| 1 | 0 | 正转 |
| 1 | 1 | 刹车(停止) |
你看,控制逻辑其实很简单。两个引脚的电平组合,决定了电机的转向。
核心要点:使能引脚ENA/ENB接PWM,可以调速。占空比越大,电机转得越快。我一般用定时器的PWM输出,频率设在1kHz左右。太低了电机会嗡嗡响,太高了驱动芯片反应不过来。
下面是一个完整的驱动代码示例。我习惯把电机控制封装成一个结构体,这样代码清晰,也方便移植。
// 电机控制结构体
typedef struct {
GPIO_TypeDef* IN1_Port;
uint16_t IN1_Pin;
GPIO_TypeDef* IN2_Port;
uint16_t IN2_Pin;
TIM_HandleTypeDef* htim;
uint32_t Channel;
} Motor_HandleTypeDef;
// 初始化电机
void Motor_Init(Motor_HandleTypeDef* hmotor)
{
// GPIO初始化(略,参考前面代码)
// PWM初始化(略)
// 初始状态:停止
HAL_GPIO_WritePin(hmotor->IN1_Port, hmotor->IN1_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(hmotor->IN2_Port, hmotor->IN2_Pin, GPIO_PIN_RESET);
}
// 设置电机方向和速度
void Motor_Set(Motor_HandleTypeDef* hmotor, int8_t direction, uint16_t speed)
{
if(direction > 0) // 正转
{
HAL_GPIO_WritePin(hmotor->IN1_Port, hmotor->IN1_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(hmotor->IN2_Port, hmotor->IN2_Pin, GPIO_PIN_RESET);
}
else if(direction < 0) // 反转
{
HAL_GPIO_WritePin(hmotor->IN1_Port, hmotor->IN1_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(hmotor->IN2_Port, hmotor->IN2_Pin, GPIO_PIN_SET);
}
else // 停止
{
HAL_GPIO_WritePin(hmotor->IN1_Port, hmotor->IN1_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(hmotor->IN2_Port, hmotor->IN2_Pin, GPIO_PIN_RESET);
}
// 设置PWM占空比
__HAL_TIM_SET_COMPARE(hmotor->htim, hmotor->Channel, speed);
}
避坑指南:我曾经在调试一个AGV小车时,电机怎么都不转。查了半天,发现是L298N的5V逻辑电源没接。记住,L298N需要两路电源:一路给电机(VMS),一路给逻辑(VSS)。逻辑电源不接,芯片不工作。
还有一个常见问题:电机启动瞬间电流很大。L298N的峰值电流是2A,但持续电流只有1A左右。如果你的电机堵转或者启动电流超过这个值,芯片会过热保护,甚至烧毁。
我的建议:在电机电源线上并联一个大电容(470μF以上),可以吸收启动瞬间的尖峰电流。另外,L298N背面一定要加散热片。别问我怎么知道的——我烧过三块L298N才长记性。
好了,这一章的内容就到这里。GPIO配置、H桥原理、L298N驱动,这三块是电机控制的入门砖。你把这些吃透了,后面学PWM调速、编码器反馈、PID控制,都会轻松很多。
公众号:蓝海资料掘金营,微信deep3321