前言
在嵌入式开发中,电机驱动是机器人、智能小车等项目的核心技术。STM32 的 GPIO 引脚通常只能输出 3.3V / 20mA 的信号,而普通的直流电机往往需要 5~12V 及数百毫安的驱动电流。因此需要电机驱动模块来作为单片机与电机之间的"桥梁",将低功率的控制信号转换为驱动电机所需的大电流和高电压。
L298N 是市面上最经典、应用最广泛的电机驱动模块之一。它价格便宜、接口简单、资料齐全,非常适合初学者进行直流电机的方向控制和 PWM 调速学习。本文将详细介绍 L298N 的工作原理,并基于 STM32F103C8T6 最小系统,采用标准外设库 编程,实现电机的正反转、停止/制动、PWM 无级调速等完整功能,代码可直接整合到你的工程中运行。
一、L298N 模块介绍
1.1 模块外观与组成

典型的 L298N 电机驱动模块通常包含以下几个主要部分:
- L298N 主芯片:意法半导体(STMicroelectronics)出品,模块的核心,负责功率驱动。
- 电源输入接口:包含 +12V(电机电源 VS)、+5V(逻辑电源 VSS)和 GND。
- 电机输出接口 :
OUT1 / OUT2对应电机 A,OUT3 / OUT4对应电机 B。 - 控制信号输入接口 :
IN1 ~ IN4方向控制信号;ENA / ENB使能及 PWM 信号。 - 板载 5V 稳压:部分模块集成 78M05 降压芯片,可将 7~12V 的电机电源降压到 5V 供逻辑电路使用(受跳线帽控制)。
- 散热片:大电流工作时有较大发热量,散热片用于保证芯片稳定工作。
1.2 引脚功能速查表
| 引脚 | 类型 | 功能说明 |
|---|---|---|
| +12V(VS) | 电源输入 | 电机驱动电源,范围 5V~35V,常用 7~12V |
| GND | 电源地 | 必须与单片机 GND 共地 |
| +5V(VSS) | 电源输出/输入 | 板载 5V 稳压输出或外部逻辑电源输入 |
| ENA | 控制输入 | 电机 A 的使能端,接 PWM 信号可调速 |
| IN1、IN2 | 控制输入 | 电机 A 的方向控制 |
| IN3、IN4 | 控制输入 | 电机 B 的方向控制 |
| ENB | 控制输入 | 电机 B 的使能端,接 PWM 信号可调速 |
| OUT1、OUT2 | 电机输出 | 连接电机 A 的正负极 |
| OUT3、OUT4 | 电机输出 | 连接电机 B 的正负极 |
1.3 电气参数
| 参数 | 数值 |
|---|---|
| 逻辑供电电压 | 4.5V~7V(推荐 5V) |
| 电机驱动电压 | 5V~35V |
| 单通道持续电流 | 2A(峰值 3A) |
| 最大功耗 | 25W(需配散热片) |
| 控制电平兼容 | 3.3V / 5V TTL 逻辑 |
L298N 内部集成了两个独立的 H 桥电路,可以同时驱动两个直流电机,或一个两相四线步进电机。
二、H 桥工作原理详解(重点)
2.1 什么是 H 桥
H 桥是电机驱动的核心电路结构,由四个开关(晶体管或 MOSFET)组成,排列成字母"H"的形状,电机连接在 H 的横梁上。通过控制这四个开关的通断组合,可以改变流过电机的电流方向,从而实现电机的正转、反转和制动。
+Vcc (电源)
│
S1 ──┴── S2
│
M (电机)
│
S4 ──┴── S3
│
GND
2.2 四种工作模式
| 模式 | 导通开关 | 电流路径 | 效果 |
|---|---|---|---|
| 正转 | S1 + S3 | 电流从 S1 → 电机 → S3 → GND | 电机正向旋转 |
| 反转 | S2 + S4 | 电流从 S2 → 电机 → S4 → GND | 电机反向旋转 |
| 滑行停止 | 全部断开 | 无电流 | 电机惯性自由滑行停止 |
| 快速制动 | S1 + S2 或 S3 + S4 | 电机两端短路 | 产生反向电动势制动,迅速停止 |
⚠️ 注意 :快速制动(IN1 = IN2 = 1)时,电机两端被短路到同一电位,会产生较大的制动电流,严禁长时间保持此状态,否则可能导致芯片过热甚至烧毁!
2.3 L298N 真值表
L298N 将 H 桥的开关控制封装为简单的逻辑电平接口。以电机 A 为例:
| IN1 | IN2 | ENA | 电机状态 |
|---|---|---|---|
| 1 | 0 | 1 / PWM | 正转 |
| 0 | 1 | 1 / PWM | 反转 |
| 0 | 0 | × | 滑行停止 |
| 1 | 1 | × | 快速制动 |
电机 B 的逻辑与 A 完全相同,对应 IN3 / IN4 / ENB。
2.4 PWM 调速的原理
如果只给 ENA 一个持续高电平,电机会以最快速度运转。要实现调速,就需要利用 PWM(脉冲宽度调制) 技术。
PWM 调速的本质是调节电机通电时间的比例:
占空比 = (高电平时间 / PWM周期) × 100%
- 占空比 100%(全程高电平) → 电机全速运转。
- 占空比 50%(一半高电平、一半低电平) → 电机以约一半的等效电压运转,速度减半。
- 占空比 0%(全程低电平) → 电机不转。
PWM 频率通常设置在 1kHz ~ 10kHz 之间,太低会有明显的抖动和噪音,太高则开关损耗增加。
三、硬件接线
以 STM32F103C8T6 驱动两个直流电机为例:
| L298N 引脚 | STM32 引脚 | 说明 |
|---|---|---|
| +12V | 外部电池正极(7~12V) | 电机驱动电源 |
| GND | 电池负极 + STM32 GND | 必须共地! |
| +5V | 悬空或接 STM32 5V | 使用跳线帽时为输出;不用则拔掉 |
| ENA | PA0(TIM2_CH1) | PWM 调速信号 |
| IN1 | PA1 | 电机 A 方向控制 |
| IN2 | PA2 | 电机 A 方向控制 |
| IN3 | PA3 | 电机 B 方向控制 |
| IN4 | PA4 | 电机 B 方向控制 |
| ENB | PA6(TIM3_CH1) | PWM 调速信号 |
| OUT1、OUT2 | 电机 A 两端 | 接电机正负极(顺序可互换) |
| OUT3、OUT4 | 电机 B 两端 | 接电机正负极 |
跳线帽处理
- 使用 PWM 调速 :拔掉 ENA 和 ENB 的跳线帽 ,将
ENA/ENB引脚接入 STM32 的 PWM 输出引脚。 - 不使用调速 (仅正反转):保留跳线帽,模块会自动把使能端接高电平,电机全速运转。
供电说明
- 推荐使用 7.4V 或 11.1V 锂电池作为电机驱动电源(接到 L298N 的 +12V 和 GND)。
- 如果电池电压在 7~12V 之间,可保留 5V 跳线帽,模块板载的 78M05 会输出 5V,可用于给 STM32 供电。
- 如果电池电压超过 12V,务必拔掉跳线帽,并从外部为 STM32 提供 5V 逻辑电源。
⚠️ 务必共地:L298N 的 GND 必须与 STM32 的 GND 连通,否则电机无法正常工作或出现异常抖动。
四、完整代码(标准库版,可直接使用)
4.1 工程结构
├── Core
│ ├── Inc
│ │ └── l298n.h # L298N 模块头文件
│ └── Src
│ ├── l298n.c # L298N 模块源文件
│ ├── main.c # 主函数
│ ├── timer.c # 定时器 PWM 初始化
│ └── gpio.c # GPIO 初始化
4.2 l298n.h
c
#ifndef __L298N_H
#define __L298N_H
#include "stm32f10x.h"
/* ---------- 引脚宏定义(可根据实际接线修改) ---------- */
/* 电机 A(ENA / IN1 / IN2) */
#define MOTOR_A_ENA_GPIO GPIOA
#define MOTOR_A_ENA_PIN GPIO_Pin_0
#define MOTOR_A_ENA_RCC RCC_APB2Periph_GPIOA
#define MOTOR_A_IN1_GPIO GPIOA
#define MOTOR_A_IN1_PIN GPIO_Pin_1
#define MOTOR_A_IN1_RCC RCC_APB2Periph_GPIOA
#define MOTOR_A_IN2_GPIO GPIOA
#define MOTOR_A_IN2_PIN GPIO_Pin_2
#define MOTOR_A_IN2_RCC RCC_APB2Periph_GPIOA
/* 电机 B(ENB / IN3 / IN4) */
#define MOTOR_B_ENB_GPIO GPIOA
#define MOTOR_B_ENB_PIN GPIO_Pin_6
#define MOTOR_B_ENB_RCC RCC_APB2Periph_GPIOA
#define MOTOR_B_IN3_GPIO GPIOA
#define MOTOR_B_IN3_PIN GPIO_Pin_3
#define MOTOR_B_IN3_RCC RCC_APB2Periph_GPIOA
#define MOTOR_B_IN4_GPIO GPIOA
#define MOTOR_B_IN4_PIN GPIO_Pin_4
#define MOTOR_B_IN4_RCC RCC_APB2Periph_GPIOA
/* PWM 定时器定义 */
#define MOTOR_A_TIM TIM2 // ENA 使用 TIM2_CH1 (PA0)
#define MOTOR_B_TIM TIM3 // ENB 使用 TIM3_CH1 (PA6)
#define MOTOR_A_PWM_CHANNEL TIM_OCMode_PWM1
#define MOTOR_B_PWM_CHANNEL TIM_OCMode_PWM1
#define PWM_PERIOD 999 // PWM 周期 = (PSC+1) × (PERIOD+1) / 72M
// PSC=71, PERIOD=999 → PWM频率 = 1kHz
/* ---------- 公开接口 ---------- */
void L298N_Init(void); // 初始化所有 GPIO 和定时器 PWM
/* 电机 A 控制 */
void MotorA_SetSpeed(uint16_t speed); // 设置速度(0 ~ PWM_PERIOD)
void MotorA_Forward(uint16_t speed); // 正转
void MotorA_Backward(uint16_t speed); // 反转
void MotorA_Stop(void); // 滑行停止
void MotorA_Brake(void); // 快速制动
/* 电机 B 控制 */
void MotorB_SetSpeed(uint16_t speed);
void MotorB_Forward(uint16_t speed);
void MotorB_Backward(uint16_t speed);
void MotorB_Stop(void);
void MotorB_Brake(void);
#endif /* __L298N_H */
4.3 l298n.c
c
#include "l298n.h"
/**
* @brief 初始化 L298N 的所有控制引脚和 PWM 定时器
* @note 使用 TIM2_CH1 (PA0) 控制 ENA,TIM3_CH1 (PA6) 控制 ENB
*/
void L298N_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
/* ====== 1. 使能时钟 ====== */
RCC_APB2PeriphClockCmd(MOTOR_A_ENA_RCC | MOTOR_A_IN1_RCC | MOTOR_A_IN2_RCC |
MOTOR_B_ENB_RCC | MOTOR_B_IN3_RCC | MOTOR_B_IN4_RCC |
RCC_APB2Periph_AFIO, ENABLE); // AFIO 用于引脚重映射(备用)
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 | RCC_APB1Periph_TIM3, ENABLE);
/* ====== 2. 方向控制引脚(IN1~IN4)配置为推挽输出 ====== */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
/* IN1、IN2(电机 A 方向) */
GPIO_InitStructure.GPIO_Pin = MOTOR_A_IN1_PIN | MOTOR_A_IN2_PIN;
GPIO_Init(MOTOR_A_IN1_GPIO, &GPIO_InitStructure);
/* IN3、IN4(电机 B 方向) */
GPIO_InitStructure.GPIO_Pin = MOTOR_B_IN3_PIN | MOTOR_B_IN4_PIN;
GPIO_Init(MOTOR_B_IN3_GPIO, &GPIO_InitStructure);
/* 初始状态:全部拉低(停止) */
GPIO_ResetBits(MOTOR_A_IN1_GPIO, MOTOR_A_IN1_PIN | MOTOR_A_IN2_PIN);
GPIO_ResetBits(MOTOR_B_IN3_GPIO, MOTOR_B_IN3_PIN | MOTOR_B_IN4_PIN);
/* ====== 3. PWM 输出引脚(PA0、PA6)配置为复用推挽输出 ====== */
GPIO_InitStructure.GPIO_Pin = MOTOR_A_ENA_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_Init(MOTOR_A_ENA_GPIO, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = MOTOR_B_ENB_PIN;
GPIO_Init(MOTOR_B_ENB_GPIO, &GPIO_InitStructure);
/* ====== 4. TIM2 配置(电机 A 的 ENA - PA0 对应 TIM2_CH1) ====== */
TIM_TimeBaseStructure.TIM_Period = PWM_PERIOD; // ARR = 999
TIM_TimeBaseStructure.TIM_Prescaler = 71; // PSC = 71 → 72M/(71+1) = 1MHz
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
/* PWM 模式配置 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // PWM 模式 1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0; // 初始占空比 0%
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM2, &TIM_OCInitStructure); // 通道 1
TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable); // 预装载使能
TIM_ARRPreloadConfig(TIM2, ENABLE);
TIM_Cmd(TIM2, ENABLE); // 启动 TIM2
/* ====== 5. TIM3 配置(电机 B 的 ENB - PA6 对应 TIM3_CH1) ====== */
TIM_TimeBaseStructure.TIM_Period = PWM_PERIOD;
TIM_TimeBaseStructure.TIM_Prescaler = 71;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM3, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM3, ENABLE);
TIM_Cmd(TIM3, ENABLE);
}
/* ================================================================
* 电机 A 控制函数
* ================================================================ */
/**
* @brief 设置电机 A 的 PWM 占空比
* @param speed: 0 ~ PWM_PERIOD(999),0 = 停止,999 = 全速
*/
void MotorA_SetSpeed(uint16_t speed)
{
if (speed > PWM_PERIOD)
speed = PWM_PERIOD;
TIM_SetCompare1(TIM2, speed); // 更新 TIM2 通道 1 的比较值
}
/**
* @brief 电机 A 正转
*/
void MotorA_Forward(uint16_t speed)
{
GPIO_SetBits(MOTOR_A_IN1_GPIO, MOTOR_A_IN1_PIN);
GPIO_ResetBits(MOTOR_A_IN2_GPIO, MOTOR_A_IN2_PIN);
MotorA_SetSpeed(speed);
}
/**
* @brief 电机 A 反转
*/
void MotorA_Backward(uint16_t speed)
{
GPIO_ResetBits(MOTOR_A_IN1_GPIO, MOTOR_A_IN1_PIN);
GPIO_SetBits(MOTOR_A_IN2_GPIO, MOTOR_A_IN2_PIN);
MotorA_SetSpeed(speed);
}
/**
* @brief 电机 A 滑行停止(自由停止)
*/
void MotorA_Stop(void)
{
GPIO_ResetBits(MOTOR_A_IN1_GPIO, MOTOR_A_IN1_PIN);
GPIO_ResetBits(MOTOR_A_IN2_GPIO, MOTOR_A_IN2_PIN);
MotorA_SetSpeed(0);
}
/**
* @brief 电机 A 快速制动
* @warning 不要长时间保持制动状态,会发热!
*/
void MotorA_Brake(void)
{
GPIO_SetBits(MOTOR_A_IN1_GPIO, MOTOR_A_IN1_PIN);
GPIO_SetBits(MOTOR_A_IN2_GPIO, MOTOR_A_IN2_PIN);
MotorA_SetSpeed(0);
}
/* ================================================================
* 电机 B 控制函数
* ================================================================ */
void MotorB_SetSpeed(uint16_t speed)
{
if (speed > PWM_PERIOD)
speed = PWM_PERIOD;
TIM_SetCompare1(TIM3, speed);
}
void MotorB_Forward(uint16_t speed)
{
GPIO_SetBits(MOTOR_B_IN3_GPIO, MOTOR_B_IN3_PIN);
GPIO_ResetBits(MOTOR_B_IN4_GPIO, MOTOR_B_IN4_PIN);
MotorB_SetSpeed(speed);
}
void MotorB_Backward(uint16_t speed)
{
GPIO_ResetBits(MOTOR_B_IN3_GPIO, MOTOR_B_IN3_PIN);
GPIO_SetBits(MOTOR_B_IN4_GPIO, MOTOR_B_IN4_PIN);
MotorB_SetSpeed(speed);
}
void MotorB_Stop(void)
{
GPIO_ResetBits(MOTOR_B_IN3_GPIO, MOTOR_B_IN3_PIN);
GPIO_ResetBits(MOTOR_B_IN4_GPIO, MOTOR_B_IN4_PIN);
MotorB_SetSpeed(0);
}
void MotorB_Brake(void)
{
GPIO_SetBits(MOTOR_B_IN3_GPIO, MOTOR_B_IN3_PIN);
GPIO_SetBits(MOTOR_B_IN4_GPIO, MOTOR_B_IN4_PIN);
MotorB_SetSpeed(0);
}
4.4 main.c
c
#include "stm32f10x.h"
#include "l298n.h"
#include "delay.h" // 使用 SysTick 实现的延时函数
/* 如有串口打印需求,可自行添加 usart.h */
/* #include "usart.h" */
int main(void)
{
/* 系统初始化 */
SystemInit(); // 配置系统时钟为 72MHz
delay_init(); // SysTick 延时初始化(自行实现)
/* USART1_Init(); // 串口初始化(自行实现) */
/* L298N 模块初始化 */
L298N_Init();
while (1)
{
/* ====== 演示一:电机 A 正转加速 ====== */
MotorA_Forward(0);
for (uint16_t speed = 0; speed <= PWM_PERIOD; speed += 50)
{
MotorA_SetSpeed(speed);
delay_ms(50); // 每 50ms 加速一档
}
delay_ms(1000); // 保持全速 1 秒
/* ====== 演示二:电机 A 反转减速 ====== */
MotorA_Backward(PWM_PERIOD);
delay_ms(2000); // 反转全速 2 秒
/* ====== 演示三:电机 A 滑行停止 ====== */
MotorA_Stop();
delay_ms(1000); // 等待滑行停止
/* ====== 演示四:双电机同步控制(小车前进/后退/转弯) ====== */
/* 小车前进:两电机同向正转 */
MotorA_Forward(700);
MotorB_Forward(700);
delay_ms(2000);
/* 小车后退:两电机同向反转 */
MotorA_Backward(700);
MotorB_Backward(700);
delay_ms(2000);
/* 小车左转:左轮慢、右轮快(差速转向) */
MotorA_Forward(300);
MotorB_Forward(700);
delay_ms(1500);
/* 小车右转:左轮快、右轮慢 */
MotorA_Forward(700);
MotorB_Forward(300);
delay_ms(1500);
/* 小车停止 */
MotorA_Stop();
MotorB_Stop();
delay_ms(2000);
}
}
4.5 stm32f10x_it.c 中断服务函数(本示例无特殊需求,留空即可)
由于本代码直接使用硬件 PWM,所有控制都由定时器硬件完成,不需要在中断服务函数中添加额外代码,保持默认即可。
五、代码详解
5.1 定时器 PWM 参数计算
以 72MHz 主频为例:
PWM 频率 = 72MHz / [(PSC + 1) × (ARR + 1)]
= 72MHz / [72 × 1000]
= 1kHz
- 预分频器 PSC = 71 ,则定时器计数频率 = 72MHz / (71 + 1) = 1MHz。
- 自动重装载 ARR = 999 ,则 PWM 周期 = 1000 个计数周期,频率 = 1MHz / 1000 = 1kHz。
1kHz 的 PWM 频率 对人耳来说刚好在听觉敏感范围之外,电机运转安静平滑。如果希望更高频率(如 10kHz,更安静),可将 ARR 改为 99,此时 TIM_SetCompare1 的取值范围变为 0~99。
5.2 占空比的控制
c
TIM_SetCompare1(TIM2, speed); // speed 范围 0 ~ PWM_PERIOD(999)
speed = 999→ 占空比 ≈ 100%(全速)。speed = 500→ 占空比 ≈ 50%(半速)。speed = 250→ 占空比 ≈ 25%(低速)。speed = 0→ 占空比 = 0%(停止)。
5.3 正反转实现
以电机 A 为例:
- 正转:IN1 = 1,IN2 = 0,ENA 提供 PWM。
- 反转:IN1 = 0,IN2 = 1,ENA 提供 PWM。
封装后的 MotorA_Forward(speed) 和 MotorA_Backward(speed) 直接调用即可,无需手动操作 GPIO。
5.4 差速转向
两轮小车转弯的核心原理是左右轮速度不同:
- 右转:左轮速度快,右轮速度慢(或反转)。
- 左转:左轮速度慢,右轮速度快(或反转)。
- 原地旋转:一侧正转、一侧反转。
c
/* 小车左转:左轮 30%、右轮 70% */
MotorA_Forward(300); // 左电机慢
MotorB_Forward(700); // 右电机快
5.5 停止与制动的区别
| 方法 | IN1 | IN2 | 效果 | 适用场景 |
|---|---|---|---|---|
Stop() |
0 | 0 | 电机断电,自由滑行 | 正常停车,缓慢减速 |
Brake() |
1 | 1 | 电机短路,电磁制动 | 紧急停车,快速响应 |
⚠️
Brake()会产生较大的瞬间电流,不要长时间保持制动状态,推荐仅在紧急停车或短时定位时使用。
六、典型应用场景
6.1 智能小车整车控制示例
将 L298N 与前面的 HC-SR04 超声波模块配合,可实现一个简单的避障小车:
c
/* 伪代码:超声波避障逻辑 */
while (1)
{
float distance = HC_SR04_GetDistance();
if (distance > 30.0f && distance < 400.0f)
{
/* 前方无障碍,全速前进 */
MotorA_Forward(800);
MotorB_Forward(800);
}
else if (distance > 0 && distance <= 30.0f)
{
/* 前方有障碍,刹车 → 后退 → 转向 */
MotorA_Brake();
MotorB_Brake();
delay_ms(200);
MotorA_Backward(600);
MotorB_Backward(600);
delay_ms(500);
/* 右转避障 */
MotorA_Forward(600);
MotorB_Backward(600);
delay_ms(600);
}
delay_ms(50);
}
6.2 其他常见应用
- 循迹小车:配合红外循迹模块,根据黑线位置动态调整左右轮差速。
- 机械臂/云台:将直流电机替换为步进电机,通过 IN1~IN4 的脉冲序列控制角度。
- 水泵/风扇控制:单路电机控制,只需使用一组 H 桥即可。
七、常见问题排查
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 电机完全不转 | ① 没有共地;② 供电不足;③ 跳线帽未正确处理 | 检查 GND 连接;确认电源 ≥ 7V;拔掉使能跳线帽 |
| 电机只能正转不能反转 | IN1/IN2 方向控制引脚接线错误 | 对照接线表重新检查 |
| 调速无效,电机始终全速 | 跳线帽未拔掉,ENA/ENB 被强制拉高 | 拔掉 ENA/ENB 的跳线帽 |
| 电机低速抖动明显 | PWM 频率太低 | 提高 PWM 频率(减小 ARR 值) |
| 芯片过热 | ① 长时间制动;② 电流过大;③ 未安装散热片 | 避免长时间制动;加装散热片;降低负载 |
| 电机运转方向与预期相反 | OUT1/OUT2 接线反了 | 交换 OUT1 和 OUT2 的连接 |
八、总结
本文详细介绍了 L298N 双 H 桥电机驱动模块的工作原理和 STM32 标准库驱动方法,涵盖了H 桥原理、引脚功能、电源供电方案、PWM 调速、正反转控制以及差速转向等核心内容。代码结构清晰、函数封装完善,可直接移植到你的项目中使用。
核心要点回顾:
- H 桥原理:通过四个开关的通断组合控制电流方向,实现正转、反转、制动。
- 控制三要素 :
- IN1/IN2 → 控制方向
- ENA → 接收 PWM 控制速度
- GND → 必须与单片机共地
- PWM 参数 :PSC=71, ARR=999 → 1kHz 频率,占空比通过
TIM_SetCompare1()调整。 - 差速转向:左右轮不同速度实现转弯(左轮慢 + 右轮快 = 左转)。
L298N 虽然效率不如一些新式驱动器,但其易用性、低成本和丰富的社区资源使其成为嵌入式入门和原型验证的绝佳选择。希望本文对你的学习和项目开发有所帮助,有问题欢迎在评论区交流讨论!