直流有刷电机大概是每个搞嵌入式或者硬件的人绕不开的一个东西。不管你是做小车、做云台、做电动推杆,还是拆个玩具想让它转得听话一点,最后都会落到同一个问题上:怎么用单片机控制它的正反转和转速。我这些年做过的电机驱动项目少说也有几十个,从几块钱的L298N模块到分立MOS搭的H桥,再到集成驱动芯片,踩过的坑基本能写一本小册子。这篇就围绕“直流有刷电机H桥控制”这件事,把原理图怎么画、PWM怎么调、DR70x这类驱动芯片怎么用,从头到尾捋一遍。不管你是刚接触电机驱动的新手,还是想从模块党进阶到自己画板子的老哥,应该都能从里面找到点有用的东西。
1. 为什么非得用H桥,而不是一个三极管搞定
1.1 直流有刷电机的正反转本质
先把这个事说透。直流有刷电机就两根线,你把正负极接对了它正转,接反了它反转。听起来简单到不行,但问题在于:你不可能每次都手动去调换两根线。用单片机控制的时候,需要的是“电子开关”来动态改变电流方向。
一个三极管或者一个MOS管,只能做单向导通,电流只能朝一个方向流。你用它控制电机,电机就只能朝一个方向转,想反转?没门。这时候就需要四个开关管组成一个“H”形的电路——中间横着的是电机,四条竖边是四个开关,这就是H桥名字的由来。
H桥的核心逻辑其实就一句话:对角导通。左上和右下同时开,电流从左往右流过电机,正转;右上和左下同时开,电流从右往左,反转。同侧上下两个管子绝对不能同时开,否则电源直接短路,管子当场冒烟。这个“绝对不能”我后面还会反复强调,因为它是烧板子最常见的原因,没有之一。
1.2 H桥的四种工作状态拆解
把H桥的状态列清楚,后面画图、写代码都靠这个。
| 状态 | 左上 | 左下 | 右上 | 右下 | 电机两端 | 效果 |
|---|---|---|---|---|---|---|
| 正转 | 通 | 断 | 断 | 通 | 左正右负 | 全速正转 |
| 反转 | 断 | 通 | 通 | 断 | 左负右正 | 全速反转 |
| 刹车 | 断 | 通 | 断 | 通 | 两端接地 | 快速停转 |
| 滑行 | 断 | 断 | 断 | 断 | 悬空 | 惯性滑行 |
这里有个容易被忽略的点:刹车和滑行是两回事。刹车状态下电机两端被短接,反电动势会让电机迅速停下来,适合需要急停的场景;滑行状态下电机两端悬空,靠惯性慢慢停,适合节能或者需要平滑减速的场景。很多新手写代码只会正转反转,忽略了这两个状态,结果做出来的东西要么停不下来,要么停得太猛。
1.3 分立方案和集成方案的取舍
H桥可以用四个分立MOS管搭,也可以用集成驱动芯片。我两种都用过,说下各自的适用场景。
分立MOS方案的好处是灵活、便宜、电流可以做得很大。你想驱动10A、20A的电机,用分立MOS基本是唯一选择,因为集成芯片很少有这么大电流的。但代价是外围电路复杂:要加上拉电阻、栅极驱动电阻、自举电容(如果用N沟道做上管)、续流二极管,PCB布局还得讲究,不然容易震荡或者发热。
集成芯片方案就省心多了,像DR70x这类芯片,内部已经把逻辑控制、死区时间、保护电路都做好了,你只要给方向信号和PWM信号就行。缺点是电流能力有限,一般几个安培以内,而且芯片本身有压降,会发热。
我的经验是:小功率、快速验证用集成芯片;大功率、成本敏感、要量产用分立MOS。这篇两种都会讲到,但重点放在集成芯片的实操上,因为大部分人第一次做H桥,用集成芯片成功率最高。
2. DR70x驱动芯片到底怎么用
2.1 DR70x的引脚和内部结构
DR70x这个系列(不同厂家后缀可能不一样,但功能大同小异)是一颗典型的单通道有刷电机驱动芯片,内部集成了一个完整的H桥。它的引脚一般是这样分布的:
- VCC:逻辑电源,通常3.3V或5V,给内部逻辑电路供电
- VM:电机电源,接电池或者电源正极,范围一般在2V到10V左右
- GND:地
- IN1 / IN2:方向控制输入,两个引脚的电平组合决定正转、反转、刹车、滑行
- PWM:有些型号单独有一个PWM引脚,有些型号直接把PWM打到IN1或IN2上
- OUT1 / OUT2:接电机的两个端子
内部结构上,DR70x把四个功率MOS管、栅极驱动、死区控制、过流保护、过热保护都集成在里面了。所谓“死区控制”,就是芯片内部保证同侧上下管不会同时导通的那段安全时间,这个时间通常是几百纳秒。你自己搭分立电路的话,死区时间得靠单片机或者专用驱动芯片来保证,很容易出错,集成芯片帮你把这个坑填了。
2.2 真值表和PWM调速的两种打法
DR70x的控制逻辑,用真值表表示最清楚:
| IN1 | IN2 | PWM | 输出状态 |
|---|---|---|---|
| 0 | 0 | X | 滑行(悬空) |
| 0 | 1 | 1 | 反转 |
| 1 | 0 | 1 | 正转 |
| 1 | 1 | X | 刹车 |
注意这里的PWM列,不同型号处理方式不一样。有的芯片PWM是独立引脚,IN1和IN2只管方向,PWM管调速;有的芯片没有独立PWM脚,你需要把PWM信号打到其中一个IN脚上。
打法一:独立PWM脚。IN1=1、IN2=0定方向,PWM脚给方波调速。这种最干净,方向和速度完全解耦,代码也好写。
打法二:PWM打到IN脚。比如要正转调速,IN1给PWM、IN2给0;要反转调速,IN1给0、IN2给PWM。这种打法要注意:当PWM为低电平时,IN1=0、IN2=0,电机进入滑行状态,而不是刹车。如果你想要“慢速正转”但又不希望电机在PWM低电平期间滑行,这种打法就不太合适。
我一般优先选带独立PWM脚的型号,省心。如果手头只有不带独立PWM脚的,那就用打法二,但心里要清楚低电平期间电机是在滑行的。
2.3 外围电路怎么配
DR70x的外围电路其实很简单,但有几个地方不能省。
电源去耦电容。VM和GND之间一定要并一个大电容,通常100uF到470uF的电解电容,再加一个0.1uF的陶瓷电容。大电容吸收电机启停时的电流冲击,小电容滤高频噪声。我见过太多人省掉这个电容,结果电机一启动单片机就复位,查半天查不出来。
续流路径。虽然DR70x内部有续流二极管,但如果你驱动的电机电感比较大,或者PWM频率比较高,建议在OUT1和OUT2之间再并一个肖特基二极管或者RC吸收电路,把反电动势的能量泄放掉。这个不是必须的,但能显著降低芯片发热。
逻辑电源和电机电源的隔离。如果电机电源电压比较高(比如12V),而逻辑电源是5V,建议在VCC引脚前面串一个几十欧姆的电阻,再并一个稳压二极管,防止电机电源的波动串到逻辑电路里。
注意:VM和VCC的上下电顺序有讲究。理想情况下先上VCC再上VM,下电时先下VM再下VCC。如果做不到,至少保证VM不会在VCC没上电的时候倒灌电流进芯片。有些型号内部有保护,有些没有,保险起见加个二极管。
3. 从原理图到PCB的实操细节
3.1 原理图绘制要点
画H桥原理图的时候,有几个地方我每次都会检查。
第一,电机两端一定要有续流路径。不管是芯片内部集成的还是外部加的,原理图上要能看出来。如果用的是分立MOS,每个MOS管旁边都要并一个快恢复二极管,方向是源极到漏极(对于N沟道)。
第二,栅极电阻不能省。分立方案里,MOS管的栅极要串一个10欧姆到100欧姆的电阻,作用是限制栅极充电电流,防止震荡。电阻太大会导致开关变慢、发热增加;太小又起不到抑制作用。我一般用22欧姆,实测比较平衡。
第三,自举电容。如果用N沟道MOS做上管,需要自举电容来把栅极电压抬到比源极高。自举电容一般用0.1uF到1uF,配合一个快恢复二极管。这个电容的容值要算:假设MOS管栅极电荷是Qg,自举电容Cboot要满足Cboot > Qg / ΔV,ΔV一般取1V左右。比如Qg=20nC,那Cboot至少20nF,实际取100nF留余量。
第四,电流采样。如果想做电流闭环或者过流保护,可以在H桥的下管源极和地之间串一个采样电阻。采样电阻的阻值要小,一般几十毫欧,功率要够。比如峰值电流2A,采样电阻0.1欧姆,那峰值功率就是0.4W,得用1W的电阻。
3.2 PCB布局的坑
PCB布局这块,我踩过的坑比原理图多得多。
大电流路径要短而粗。VM到芯片、芯片到电机、电机到地的路径,走线要尽量宽。1A电流至少走40mil,2A走80mil,以此类推。如果走线不够宽,压降大、发热严重,还会引入寄生电感,导致开关瞬间电压尖峰。
功率地和信号地分开。电机电流在地线上产生的压降会干扰逻辑电路。正确做法是功率地和信号地单点连接,通常在芯片的GND引脚附近。我一般会在PCB上留一个0欧姆电阻或者磁珠作为单点连接的位置,调试的时候可以灵活处理。
散热焊盘要处理好。DR70x这类芯片底部通常有一个散热焊盘,必须焊到PCB的铜皮上,铜皮面积越大越好,最好打过孔到背面的大面积铜。如果散热焊盘虚焊,芯片跑几分钟就过热保护了。
去耦电容紧贴芯片。0.1uF的陶瓷电容要放在VCC引脚旁边,走线越短越好。大电解电容可以稍微远一点,但也不能太远。
3.3 一个完整的原理图框架
把上面这些串起来,一个典型的DR70x驱动电路大概是这样:
- 电源部分:VM接电池正极,并100uF电解+0.1uF陶瓷到地;VCC接5V,并0.1uF到地
- 控制部分:IN1、IN2、PWM接单片机IO口,每个IO口可以串一个100欧姆电阻限流
- 输出部分:OUT1、OUT2接电机,电机两端并一个0.1uF电容(可选,抑制EMI)
- 保护部分:VM和VCC之间加一个二极管防止倒灌;电机两端加TVS管吸收尖峰(大功率场合)
这个框架我用了很多次,基本没出过问题。当然具体参数要根据电机和电源调整,但结构是通用的。
4. PWM调速的核心参数怎么定
4.1 PWM频率的选择
PWM频率这个事,选高了选低了都有问题。
频率太低(比如几百Hz),电机会听到明显的啸叫,因为人耳能听到20Hz到20kHz的声音。而且低频PWM会导致电流纹波大,电机转动不平稳。
频率太高(比如几十kHz以上),MOS管的开关损耗会增加,芯片发热严重。而且高频下PCB的寄生电感和电容影响变大,容易出现震荡。
我的经验值:有刷电机PWM频率选15kHz到25kHz。这个范围刚好在人耳听觉上限附近,啸叫不明显,开关损耗也可以接受。如果对噪声特别敏感,可以选20kHz以上;如果芯片发热严重,可以降到10kHz试试。
有个特殊情况:如果电机电感很小(比如空心杯电机),电流纹波会很大,这时候需要更高的PWM频率来平滑电流,可能要到30kHz以上。但空心杯电机一般功率小,芯片发热不是大问题。
4.2 占空比和转速的关系
理论上,电机的转速和PWM占空比成正比。占空比50%,转速就是全速的一半。但实际上不是完全线性的,因为:
第一,电机有启动死区。占空比太低的时候(比如5%以下),电机可能根本转不起来,因为平均电压不足以克服静摩擦。这个死区大小取决于电机本身,一般3%到10%。
第二,反电动势的影响。电机转起来之后会产生反电动势,抵消一部分电源电压。所以同样的占空比,空载和带载的转速不一样。
第三,电源电压波动。电池电压会随着放电下降,同样的占空比,电池满电和快没电的时候转速差很多。
如果要精确控制转速,最好加一个编码器做闭环。但大部分应用(比如小车、风扇)开环就够了,知道有这些非线性因素就行。
4.3 死区时间对调速的影响
前面说过,DR70x内部有死区控制。死区时间是指同侧上下管都关断的那段时间,目的是防止直通短路。但死区时间也会影响调速性能。
死区时间太长,输出电压会有损失,尤其是在低占空比的时候。比如死区时间500ns,PWM周期50us(20kHz),那死区占周期的1%,影响不大。但如果PWM频率很高,比如100kHz,周期10us,死区就占了5%,低占空比时输出会明显偏低。
DR70x这类芯片的死区时间一般是固定的,几百纳秒级别,对常规应用足够了。如果你自己搭分立H桥,死区时间要自己控制,一般设200ns到1us。太短了有直通风险,太长了输出失真。
5. 代码实现:从GPIO到PWM的完整流程
5.1 初始化配置
以常见的单片机为例,控制DR70x需要配置三个引脚:IN1、IN2、PWM。IN1和IN2是普通GPIO,PWM是定时器输出。
初始化的时候,先把IN1和IN2都设成低电平,让电机处于滑行状态,避免上电瞬间电机乱转。PWM引脚配置成定时器PWM输出模式,频率设20kHz,初始占空比0。
// 伪代码,具体寄存器名根据芯片手册改 void motor_init(void) { // IN1, IN2 配置为推挽输出 GPIO_Init(IN1_PIN, OUTPUT_PP); GPIO_Init(IN2_PIN, OUTPUT_PP); // 初始状态:滑行 GPIO_Write(IN1_PIN, 0); GPIO_Write(IN2_PIN, 0); // PWM定时器配置,20kHz TIM_Config(TIM_PWM, 20000); TIM_PWM_Init(TIM_PWM, DUTY_0); }5.2 正反转和调速函数
把方向控制和调速封装成函数,用起来方便。
void motor_set(int direction, int duty) { // duty范围0-1000,对应0%-100% if (duty < 0) duty = 0; if (duty > 1000) duty = 1000; if (direction > 0) { // 正转 GPIO_Write(IN1_PIN, 1); GPIO_Write(IN2_PIN, 0); TIM_PWM_SetDuty(TIM_PWM, duty); } else if (direction < 0) { // 反转 GPIO_Write(IN1_PIN, 0); GPIO_Write(IN2_PIN, 1); TIM_PWM_SetDuty(TIM_PWM, duty); } else { // 停止:刹车 GPIO_Write(IN1_PIN, 1); GPIO_Write(IN2_PIN, 1); TIM_PWM_SetDuty(TIM_PWM, 0); } }这里有个细节:停止的时候我用的是刹车状态(IN1=1、IN2=1),而不是滑行。刹车停得快,适合需要快速响应的场景。如果想让电机自然滑行停转,把IN1和IN2都设成0就行。
5.3 软启动和斜坡控制
直接给100%占空比,电机会猛地窜出去,电流冲击也大。加一个软启动,让占空比在几百毫秒内从0慢慢升到目标值,体验会好很多,对电机和驱动芯片也更友好。
void motor_ramp(int direction, int target_duty, int step_ms) { int current = 0; int step = 10; // 每次增加10,对应1% while (current < target_duty) { current += step; if (current > target_duty) current = target_duty; motor_set(direction, current); delay_ms(step_ms); } }step_ms设5到10毫秒比较合适,太快了起不到软启动效果,太慢了响应迟钝。这个斜坡控制在做小车的时候特别有用,能明显减少轮子打滑和电流冲击。
5.4 电流检测和保护逻辑
如果硬件上有电流采样,代码里可以加过流保护。思路是:定时器触发ADC采样采样电阻上的电压,换算成电流,超过阈值就立刻关断输出。
void motor_current_check(void) { int adc_val = ADC_Read(CURRENT_CH); float voltage = adc_val * 3.3 / 4096.0; float current = voltage / SAMPLE_RESISTOR; // SAMPLE_RESISTOR单位欧姆 if (current > OVER_CURRENT_THRESHOLD) { // 过流,立即刹车 GPIO_Write(IN1_PIN, 1); GPIO_Write(IN2_PIN, 1); TIM_PWM_SetDuty(TIM_PWM, 0); fault_flag = 1; } }这个保护逻辑要放在中断或者高频任务里,响应越快越好。DR70x内部也有过流保护,但那是最后一道防线,软件保护能更快响应,减少芯片压力。
6. 常见问题排查和避坑经验
6.1 电机不转或者只往一个方向转
这是最常见的问题,排查顺序如下:
先量电压。用万用表量OUT1和OUT2之间的电压,正转时应该是正的,反转时应该是负的。如果电压正常但电机不转,那是电机的问题;如果电压不对,那是驱动或者控制的问题。
再查控制信号。用示波器或者逻辑分析仪看IN1、IN2、PWM的波形。如果IN1和IN2的电平组合不对,检查代码里的GPIO配置;如果PWM没有输出,检查定时器配置。
最后查电源。VM电压够不够?VCC有没有上电?如果VM电压太低,芯片可能不工作。DR70x的最低工作电压一般在2V左右,但电机启动瞬间电流大,电源内阻大的话电压会被拉低,导致芯片复位。
6.2 芯片发热严重
芯片发热一般有三个原因:电流太大、PWM频率太高、散热不好。
先算一下电机的堵转电流。堵转电流 = VM / 电机内阻。如果这个电流超过了芯片的额定电流,那发热是必然的,得换更大电流的芯片或者用分立MOS。
如果电流在额定范围内还发热,检查PWM频率。频率越高开关损耗越大,试着降到10kHz看看。另外检查散热焊盘有没有焊好,PCB铜皮面积够不够。
还有一个容易被忽略的点:续流损耗。电机电感在PWM关断期间会产生反电动势,电流通过续流二极管流回电源。这个电流在二极管上产生的损耗也会让芯片发热。如果电机电感大,可以考虑在电机两端并一个RC吸收电路,把部分能量消耗在电阻上。
6.3 电机启动时单片机复位
这个问题我遇到过好几次,基本都是电源问题。
电机启动瞬间电流可能是额定电流的5到10倍,如果电源功率不够或者去耦电容太小,VM电压会瞬间跌落,通过芯片内部电路影响到VCC,导致单片机复位。
解决办法:加大VM的去耦电容,至少470uF,最好1000uF以上;在VCC和VM之间加隔离,比如用二极管或者磁珠;单片机和电机驱动用独立的稳压器供电。
6.4 PWM调速时电机有异响
异响一般来自PWM频率落在人耳听觉范围内,或者电流纹波太大导致电机振动。
先把PWM频率调到20kHz以上试试。如果还有异响,可能是电机本身的机械问题,比如轴承磨损或者转子不平衡。另外检查PWM占空比是不是太低,太低的占空比会导致电机间歇性转动,发出“咔咔”声。
6.5 常见问题速查表
| 现象 | 可能原因 | 排查方法 | 解决措施 |
|---|---|---|---|
| 电机不转 | 电源未上电 | 量VM和VCC电压 | 检查电源连接 |
| 只往一个方向转 | IN1/IN2信号不对 | 示波器看波形 | 检查代码GPIO配置 |
| 芯片发热严重 | 电流超额定 | 算堵转电流 | 换大电流芯片或分立MOS |
| 单片机复位 | 电源跌落 | 示波器看VM波形 | 加大去耦电容,隔离供电 |
| 电机异响 | PWM频率低 | 调整频率 | 调到20kHz以上 |
| 调速不线性 | 启动死区 | 测最低启动占空比 | 加软启动,避开死区 |
| 刹车太猛 | 刹车状态 | 确认IN1/IN2 | 改用滑行状态 |
7. 进阶:从开环到闭环,以及仿真验证
7.1 编码器闭环调速
开环调速的精度受电源电压、温度、负载影响很大。如果要精确控制转速,需要加编码器做闭环。
编码器输出脉冲,单片机用定时器的编码器模式或者外部中断计数。每隔固定时间(比如10ms)读一次计数值,算出实际转速,和设定值比较,用PID调整PWM占空比。
PID参数整定是个经验活。我的习惯是先用纯比例控制,P从0.1开始慢慢加,直到转速开始震荡,然后退回一点。再加积分项消除稳态误差,积分时间从大到小调。微分项一般用不上,除非负载变化特别快。
7.2 用仿真工具验证H桥逻辑
在画板子之前,可以用仿真工具验证H桥的逻辑和PWM调速效果。比如用电路仿真软件搭一个H桥模型,加上电机模型和PWM源,看电流波形和转速响应。
仿真的好处是快,改参数不用焊板子。但要注意仿真模型和实际器件的差异,尤其是MOS管的开关特性和电机的非线性。仿真结果只能作为参考,最终还是要实测。
7.3 从DR70x到分立MOS的升级路径
如果DR70x的电流不够用了,升级到分立MOS是必然的。升级的时候注意几点:
上管用P沟道还是N沟道?P沟道简单,不需要自举,但导通电阻大、价格贵、选择少。N沟道导通电阻小、便宜,但需要自举或者专用栅极驱动芯片。大电流场合基本都用N沟道加自举。
栅极驱动芯片怎么选?看驱动电流和耐压。驱动电流要足够大,保证MOS管快速开关;耐压要高于VM电压。常见的有半桥驱动芯片,一片驱动一个桥臂,两片组成H桥。
死区时间怎么设?分立方案的死区时间由单片机或者驱动芯片控制。单片机控制的话,在换向的时候先关断所有管子,延时几百纳秒,再开通新的管子。这个延时可以用定时器实现,也可以用驱动芯片自带的死区控制。
8. 一些零散但重要的经验
8.1 电机两端并电容的讲究
电机两端并一个0.1uF的陶瓷电容,能有效抑制电刷火花产生的EMI。但电容不能太大,太大了会增加开关损耗,还会和电机电感形成LC振荡。0.1uF是个比较安全的取值。
如果EMI要求严格,还可以在电机两端各串一个磁珠,再并电容,组成π型滤波。磁珠选高频阻抗大的,比如100MHz时阻抗100欧姆以上。
8.2 电源反接保护
电池反接是新手最容易犯的错误之一。轻则芯片烧毁,重则电池爆炸。最简单的保护是在VM回路串一个二极管,但二极管有压降,大电流时损耗大。更好的方案是用P沟道MOS做理想二极管,压降小,但电路复杂一点。
如果成本允许,建议加反接保护。我见过太多因为电池接反烧板子的案例,加一个二极管就能避免,性价比很高。
8.3 上电顺序和使能控制
有些应用需要控制电机的上电顺序,比如先让单片机初始化完成,再使能电机驱动。这时候可以在VM回路上加一个使能开关,用MOS管控制。单片机初始化完成后,拉高使能引脚,电机驱动才上电。
这个做法还能实现低功耗待机。不用电机的时候,把VM切断,芯片完全不耗电。对于电池供电的设备,这个功能很实用。
8.4 调试用的假负载
调试H桥的时候,不要一上来就接电机。先用一个功率电阻或者灯泡做假负载,确认控制逻辑和PWM输出正常,再接电机。电机是感性负载,出问题的时候电流冲击大,容易烧东西。假负载是纯阻性,安全得多。
我一般用一个12V的汽车灯泡做假负载,既能看出PWM调速的效果(灯泡亮度变化),又能限制电流。确认没问题了再换电机。
8.5 示波器看波形的技巧
调试H桥,示波器是必备的。看波形的时候注意几点:
测OUT1和OUT2的时候,用差分探头或者两个探头相减,不要直接把探头地夹在OUT上,否则可能短路。
看PWM波形的时候,触发方式选边沿触发,时间基准调到能看清一个完整周期。重点看上升沿和下降沿有没有震荡,如果有,说明栅极电阻或者布局有问题。
看电流波形的话,用电流探头或者采样电阻上的电压。电流波形能反映很多问题,比如续流是否正常、有没有直通、电机是否堵转。
9. 写在最后的一些个人体会
做电机驱动这些年,最大的感受就是:理论很简单,实操全是坑。H桥的原理十分钟就能讲明白,但真正画板子、写代码、调试的时候,电源、布局、散热、保护,每一个环节都能让你卡半天。
DR70x这类集成芯片大大降低了入门门槛,让新手不用一上来就面对分立MOS的复杂性。但集成芯片不是万能的,电流有限、散热有限,用到一定程度就得升级。升级到分立方案的时候,前面集成芯片积累的经验——比如PWM频率怎么选、死区时间怎么设、续流路径怎么走——都是有用的。
最后分享一个我自己的习惯:每次做新的电机驱动板,第一版一定留足够的测试点和跳线。测试点方便量波形,跳线方便改电路。不要想着一次做完美,留点余地,调试的时候会感谢自己。
还有,手边常备几个不同规格的电机和假负载。调试的时候换着试,能快速定位是驱动的问题还是电机的问题。这个习惯帮我省了很多时间。