手把手教你用STM32驱动L298N控制直流电机(基于STM32F103C8T6)
你是不是也曾在做智能小车、机器人或者自动化装置时,被“怎么让电机转起来”这个问题卡住?别急,今天我们就来彻底搞定一个经典又实用的组合:L298N电机驱动模块 + STM32F103C8T6。
这套方案成本低、资料全、上手快,是无数嵌入式初学者踏入电机控制世界的第一步。更重要的是——它真的能用!本文将从硬件原理讲到代码实现,不跳步骤、不甩术语,带你一步步把电机稳稳地转起来。
为什么选L298N和STM32F103C8T6?
在开始接线和写代码之前,先搞清楚我们为什么要用这两个东西。
L298N:让MCU“推得动”电机
STM32再强,它的GPIO也只能输出3.3V、几十毫安电流,而一个普通直流电机可能需要6~12V电压、几百毫安甚至几安培电流才能转动。直接连?轻则不转,重则烧芯片。
这时候就需要L298N这种“力气大”的驱动芯片了。你可以把它理解成一个“电子开关组”,STM32只负责发指令(比如“正转!”、“停!”),真正的电力搬运工是L298N。
它最大的特点就是:
- 双H桥设计 → 能同时控制两个直流电机
- 支持最高46V电源输入 → 适配多种电机
- 内置保护二极管 → 防止电机断电时反向电动势击穿电路
- 控制端兼容TTL电平 → 和STM32的3.3V逻辑完美对接
虽然它效率不高、发热明显,但胜在便宜、稳定、资料多,非常适合学习和原型开发。
STM32F103C8T6:“蓝丸”虽小,五脏俱全
这块被称为“蓝丸”的开发板核心是一颗ARM Cortex-M3内核的MCU,主频72MHz,自带PWM、定时器、串口等丰富外设。最关键的是——价格只要十几块钱!
相比Arduino Uno这类8位单片机,STM32的优势在于:
- 更高的处理能力,适合未来扩展PID调速、编码反馈等功能;
- 定时器精度高,PWM波形更稳定;
- 多通道PWM输出,轻松实现双电机独立调速。
两者结合,就是一个性价比极高的入门级电机控制系统。
L298N是怎么控制电机的?一文看懂H桥原理
很多人知道L298N可以控制电机正反转,但不清楚背后是怎么实现的。关键就在于H桥电路。
想象一下,电机有两根线,A端和B端。如果A接正极、B接地,电机正转;反过来,A接地、B接正极,电机就反转。那能不能自动切换呢?
答案就是用四个开关组成一个“H”形结构:
+Vcc │ ┌─▼─┐ │ Q1├─── OUT1 ────► Motor A+ └─┬─┘ │ │ ▼ ├───────────────┤ │ ▲ ┌─▼─┐ │ │ Q2├─── OUT2 ────► Motor A- └─┬─┘ │ GND通过控制Q1~Q4这四个开关的状态,就能改变电流方向:
| Q1 | Q2 | Q3 | Q4 | 结果 |
|---|---|---|---|---|
| ON | OFF | OFF | ON | 正转 |
| OFF | ON | ON | OFF | 反转 |
| ON | OFF | ON | OFF | 刹车(短路) |
| OFF | OFF | OFF | OFF | 悬空停止 |
L298N内部集成了两个这样的H桥,所以能驱动两个电机。
对外接口简化为几个关键引脚:
| 引脚名 | 功能说明 |
|---|---|
| IN1, IN2 | 控制第一个电机的方向(高低电平组合) |
| ENA | 使能端,接PWM信号用于调速 |
| OUT1, OUT2 | 接电机两端 |
| VCC, GND | 逻辑电源(通常5V或取自板载5V) |
| +12V, GND | 电机电源输入(可接外部电池) |
⚠️ 注意:逻辑电源和电机电源最好分开供电!否则电机启动瞬间的大电流会拉低系统电压,导致STM32复位。
硬件连接:STM32如何与L298N通信?
现在我们来动手连线。假设你要控制一台直流电机。
所需材料清单
- STM32F103C8T6最小系统板(“蓝丸”)
- L298N模块(常见红色PCB)
- 直流电机 ×1
- 外部电源(如12V适配器或电池组)
- 杜邦线若干
- 万用表(调试用)
接线图(以TIM2_CH1为例)
| STM32引脚 | → | L298N引脚 | 功能说明 |
|---|---|---|---|
| PA0 | → | IN1 | 方向控制1 |
| PA1 | → | IN2 | 方向控制2 |
| PA2 | → | ENA | PWM调速输入 |
| 3.3V | → | +5V (使能) | 给L298N逻辑部分供电(若使用板载稳压) |
| GND | ↔ | GND | 共地必须连接! |
🔌 关于电源:
- 如果你的L298N模块上有跳帽(Enable 5V Regulator),并且你希望用电机电源给逻辑部分供电,则保留跳帽。
- 否则建议断开跳帽,单独给STM32和L298N逻辑端提供干净的3.3V/5V电源,避免干扰。
📌 特别提醒:PA2要接到EN_A,并且这个引脚必须支持PWM输出。查手册可知,PA2是TIM2_CH1的复用功能,完全符合要求。
软件实现:用HAL库生成PWM并控制方向
接下来进入编程环节。我们将使用STM32CubeIDE + HAL库进行开发,这也是目前最主流的配置方式。
第一步:配置时钟与GPIO
打开STM32CubeMX,选择STM32F103C8Tx,设置如下:
- RCC → Crystal/Ceramic Resonator(外部晶振8MHz)
- Clock Configuration → 系统时钟72MHz
- GPIO:
- PA0, PA1: 输出模式,推挽,高速
- PA2: 复用功能 → TIM2_CH1(PWM输出)
第二步:配置定时器TIM2为PWM模式
在Timers → TIM2中设置:
- Mode: PWM Generation CH1
- Channel 1 Pulse (%): 设为50(初始占空比)
- Counter Period (Auto-reload): 100 → 即PWM周期为100个计数单位
- Clock Division: 不分频
- 得到PWM频率 ≈ 72MHz / (PSC+1) / (ARR+1)
若PSC=71,则每tick为1μs,ARR=99 → 周期100μs → 频率10kHz(理想值)
✅ 推荐PWM频率设在1kHz~20kHz之间,避开人耳敏感区(减少嗡嗡声),又能保证调速平滑。
第三步:编写核心控制函数
#include "main.h" #include "stm32f1xx_hal.h" // 定义控制引脚 #define IN1_PIN GPIO_PIN_0 #define IN2_PIN GPIO_PIN_1 #define IN1_PORT GPIOA #define IN2_PORT GPIOA TIM_HandleTypeDef htim2; // 设置电机正转 void Motor_Forward(uint8_t duty) { HAL_GPIO_WritePin(IN1_PORT, IN1_PIN, GPIO_PIN_SET); // IN1 = 1 HAL_GPIO_WritePin(IN2_PORT, IN2_PIN, GPIO_PIN_RESET); // IN2 = 0 __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, duty); // 设置PWM占空比(0~100) } // 设置电机反转 void Motor_Reverse(uint8_t duty) { HAL_GPIO_WritePin(IN1_PORT, IN1_PIN, GPIO_PIN_RESET); // IN1 = 0 HAL_GPIO_WritePin(IN2_PORT, IN2_PIN, GPIO_PIN_SET); // IN2 = 1 __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, duty); } // 停止电机(快速刹车) void Motor_Brake(void) { HAL_GPIO_WritePin(IN1_PORT, IN1_PIN, GPIO_PIN_SET); HAL_GPIO_WritePin(IN2_PORT, IN2_PIN, GPIO_PIN_SET); __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, 0); } // 自由停止(悬空) void Motor_Stop(void) { HAL_GPIO_WritePin(IN1_PORT, IN1_PIN, GPIO_PIN_RESET); HAL_GPIO_WritePin(IN2_PORT, IN2_PIN, GPIO_PIN_RESET); __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, 0); }主循环测试逻辑
int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_TIM2_Init(); // 启动PWM输出 HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); while (1) { Motor_Forward(80); // 正转,80%速度 HAL_Delay(2000); Motor_Brake(); // 刹车 HAL_Delay(1000); Motor_Reverse(50); // 反转,50%速度 HAL_Delay(2000); Motor_Stop(); // 停止 HAL_Delay(1000); } }💡 小贴士:
-__HAL_TIM_SET_COMPARE()是动态修改PWM占空比的关键API;
- 使用HAL_Delay()简单延时即可完成动作序列验证;
- 实际项目中应加入按键、遥控或传感器输入来触发不同行为。
常见问题排查与调试技巧
刚上电发现电机不动?别慌,以下是新手最容易踩的坑:
❌ 问题1:电机完全不转
- ✅ 检查共地是否连接(STM32和L298N的GND有没有接在一起?)
- ✅ 查看电机电源是否有电压输出(用万用表测+12V和GND之间)
- ✅ 确认L298N的使能跳帽是否正确设置
- ✅ 测IN1/IN2是否有电平变化(可用LED模拟测试)
❌ 问题2:只能单向转,不能换向
- ✅ 检查IN1和IN2是否接反?
- ✅ 是否软件中写错了电平逻辑?(比如该清零的没清零)
❌ 问题3:有声音但不转,或转得很慢
- ✅ PWM频率太低会导致力矩不足,建议提高至5kHz以上
- ✅ 占空比太小 → 加大duty试试(比如从20调到60)
- ✅ 电源带载能力不足 → 换更大容量电池或适配器
❌ 问题4:STM32频繁重启
- ✅ 最可能是电源干扰!务必做到:
- 电机电源与逻辑电源分离
- 在L298N电源输入端加滤波电容(100μF电解 + 0.1μF陶瓷并联)
- 尽量缩短大电流走线
进阶思路:不只是“让它转”
掌握了基本控制之后,下一步可以尝试这些提升:
🧩 添加编码器实现闭环控制
加上霍尔编码器后,就可以读取实际转速,配合PID算法实现恒速运行,即使负载变化也不怕。
🎮 引入遥控或蓝牙控制
通过HC-05蓝牙模块接收手机指令,实现无线调速、远程启停。
📊 加电流检测做保护
在电源线上串联一个小电阻(如0.1Ω),用ADC采集压降,计算实时电流,一旦过流立即停机。
⚙️ 移植FreeRTOS实现多任务
把电机控制、传感器采集、通信处理拆分成独立任务,系统更健壮、响应更快。
写在最后:从“点亮电机”到“掌控运动”
当你第一次看到电机按照程序指令精准地正反转、加速减速时,那种成就感丝毫不亚于“点亮LED”。
而这只是开始。L298N + STM32这个组合就像一把钥匙,打开了通往机器人、自动化、运动控制的大门。虽然它不是最先进的方案(如今更多人用MOSFET驱动芯片如DRV8876),但它足够简单、透明、可控,让你看清每一层技术背后的本质。
所以,别再停留在理论了——拿起你的蓝丸板和L298N模块,焊好线、下好程序,让电机真正为你所控。
如果你在实践中遇到任何问题,欢迎留言交流。我们一起把每一个“理论上可行”的项目,变成“实际上能跑”的现实。