ULN2003驱动继电器与步进电机:单片机驱动电路实战与避坑
开头先给一句过来人的话继电器要被单片机控制、步进电机要转起来不要上来就只盯着“用三极管搭个开关电路”先把负载电流和续流回路算清楚否则三极管烧了、继电器乱跳、电机不转这些问题会一个个找上门。我早期调STM32F103C8T6外围电路时也经历过用S8050驱动继电器、结果开关几次就击穿的尴尬后来换ULN2003一片芯片把继电器驱动、步进电机驱动、多路负载控制全包了板子一下子干净很多。这篇文章会把ULN2003、继电器、步进电机放在同一个外围电路里讲清楚包括每一步为什么这么接以及我在实测中踩过的坑适合正在学单片机外围电路、或者总在驱动部分翻车的同学。1. 为什么很多人的三极管驱动电路总在翻车1.1 三极管开关电路的能力边界搜“NPN三极管的导通截止条件”“三极管开关电路”的人非常多说明大家第一反应都是用三极管当电子开关这个思路本身没问题。但把三极管直接接到继电器线圈或电机绕组上时真正的问题往往不在导通而在关断。先用一个具体例子算账。S8050是常见的NPN三极管假设要驱动一个5V继电器线圈电阻约80Ω稳态电流就是I5V÷80Ω≈62.5mA。要让S8050进入饱和导通而不是工作在放大区基极电流IB需要满足IBIC÷hFE。S8050的hFE大概100~300按最小值算IB至少0.625mA实际工程上会取2~3倍余量。如果用3.3V单片机GPIO直推基极串1kΩ电阻IB大约是(3.3-0.7)V÷1kΩ≈2.6mA理论够用。但这里有几个隐藏问题。第一GPIO高电平只有3.3V如果基极电阻随手选了个4.7kΩIB就只有0.55mA三极管进不了饱和区VCE压降大管子自己发热非常严重摸上去烫手。第二继电器线圈是电感断电瞬间会产生很大的反向感应电动势方向与原先电源电压相反幅度可能到几十伏甚至上百伏没有续流二极管三极管只能靠自身反向击穿来泄放运气好能撑几百次运气不好一次就报废。第三单管方案只能控制一路等需要控制两路继电器接电机正反转、或者控制四相步进电机时马上要变成四五个三极管加四五个续流二极管外围电路复杂度和出错率立刻上升。这就是为什么“三极管导通截止条件”搜的人很多照着搭却总是翻车——你学会了导通和截止却没给电感负载留续流回路开关瞬间的冲击照样烧管子。三极管确实导通关断很快但快不等于安全。1.2 达林顿结构带来的连锁优势网络热词里有一句“IC三极管IB大于IC”这里其实是个容易混淆的说法。ULN2003内部不是单个三极管而是达林顿管相当于两级三极管叠在一起第一级的集电极电流当作第二级的基极电流总电流增益是两级乘积hFE能到几千甚至更大。所以真正的关系是集电极电流IC远大于基极电流IB输入只需要很小的电流输出就能驱动大负载。“IB大于IC”是把输入级和第二级的关系搞混了。这种高增益带来一个很实际的好处MCU的GPIO只需要几毫安驱动能力就能让ULN2003输出管进入饱和。而用普通三极管每路都要重算基极电阻换一个负载电压或者换一个管子电阻可能就要换掉非常麻烦。更省事的是内部的续流二极管。ULN2003每个输出通道都并联了一个钳位二极管公共端从COM脚引出实际型号一般是7路ULN2803才是8路。使用继电器绕组、步进电机绕组这类电感性负载时续流二极管必不可少如果用分立三极管方案每路都要外接一个1N4007或1N4148方向焊反还会直接出问题而ULN2003只要把COM脚接回负载电源内部二极管就能给所有通道提供泄放回路。对比项单NPN三极管方案ULN2003方案单通道输出电流能力由型号决定常见约100~500mA额定500mA电流增益几十到几百达林顿结构通常几千以上续流二极管需要外接方向容易焊错内部集成接好COM脚即可通道数量一路一个管子外围元器件多一片芯片7路可驱动多负载3.3V MCU兼容性需要重算基极电阻不同负载换电阻输入灵敏度高接IO口即可典型的例子是控制两路继电器接电机正反转。用两个继电器组成H桥每个继电器线圈需要“一个三极管开关一个续流二极管”总共就是两个三极管加两个二极管换成ULN2003选两个输入通道正转反转由程序控制两个IO交替置位就行PCB布局走线少一大截。2. 动手前先算账继电器和步进电机各自需要多大的驱动电流2.1 继电器的线圈电流与吸合电压需求驱动继电器的第一步不是接电路而是看继电器的线圈参数。继电器外壳上通常印着线圈电压常见的是5V、12V、24V线圈电流不直接标注但标了线圈电阻比如5V继电器线圈电阻约70~100Ω算下来电流就是50~70mA12V继电器线圈电阻约200~400Ω电流30~60mA。不要只看触点标称电流那是指触点能承受的负载电流和线圈驱动电流完全是两回事。选驱动方案时要以线圈电流和线圈电压一起做依据。用ULN2003驱动5V继电器500mA的通道能力余量很大驱动12V继电器也够只要ULN2003的供电环境和负载电源匹配。还要特别注意线圈电压和触点电压必须分开看线圈用12V触点两端完全可以接220V交流负载或者接直流电机两者之间只有继电器内部的机械触点联系这也是“继电器与PLC区别”里常被问到的点——继电器本质就是一个电控机械开关不是功率放大器。实际选型时我用万用表量线圈电阻再对照标称电压计算电流。有些继电器资料会直接写“吸合电压是额定电压的75%”意思是12V继电器在9V左右就可能吸合但这不代表你可以长期用9V驱动工程上要留足电压余量按额定电压供电才稳定。驱动电流则按额定电压下的最大电流算保证三极管或ULN2003在最坏情况下都不会过流。2.2 步进电机的工作电流与相位关系步进电机和继电器的负载特性不一样。以最常见的28BYJ-48为例它标称5V四相五线单相绕组电流实测约120~150mA数据手册给出的步距角是5.625°/64减速比1/64算下来一个整步对应输出轴约0.0879°。这个电流很小ULN2003单通道500mA完全带得动。但很多人一看“步进电机”这个词就以为所有步进电机都能用ULN2003这就容易出大问题。42步进电机比如42BYGH系列额定相电流常见1.5A甚至1.7A远超ULN2003单通道500mA而且它通常是两相四线内部是双极性绕组需要H桥驱动才能换向。ULN2003是单方向集电极开路输出只能用来拉电流不能主动推电流所以双极性电机的正向反向电流控制它做不了。42步进电机要用A4988、DRV8833、DRV8825或TMC2208这类专门驱动芯片。网上搜“DRV8833两相四线步进电机”的朋友多半就是明白了ULN2003不适合才换方案的。还有一个容易忽略的电气细节28BYJ-48虽然单相电流只有120~150mA但启动瞬间、堵转瞬间电流会比额定值高很多而且四相绕组轮流导通不是四个通道同时满负荷所以ULN2003带它是安全的。如果你发现电机卡住不转时间久了IC会发烫这时要赶紧断电检查机械卡阻不能只想着换更大电流的驱动管。3. ULN2003 驱动继电器外围电路逐点拆解3.1 继电器接在哪个输出脚为什么是这个极性ULN2003常见的是16脚DIP封装引脚不是随便接的。输入脚1~7接MCU控制信号输出脚16~10对应各路集电极开路输出8脚接地9脚是COM。放在实板上我用STM32F103C8T6的PB0~PB6接输入输出端16~10分别接各路继电器线圈的负极继电器线圈正极统一接负载电源正极比如5V或12V再把COM脚也接到同一个电源正极。这里要解释一个常见误区ULN2003的COM脚不是芯片供电脚芯片本身不需要VCC它内部的逻辑结构和输出级靠输入信号和负载电源来工作。COM脚真正的用途是引出内部续流二极管的公共端。你把负载电源正极接在COM上内部二极管的反向恢复电流才能回到电源否则内部二极管完全不起作用。很多人把8脚和9脚搞混或者干脆把COM悬空结果用ULN2003驱动继电器照样烧就是这个原因。输出脚为什么必须接继电器线圈的负极因为ULN2003输出级是NPN达林顿管集电极是输出端发射极统一接地。只有MCU输出高电平时输入内部基极电阻流入基极电流达林顿管导通输出脚被拉到接近GND继电器线圈两端形成压差电流从电源正极流过线圈再进输出管继电器吸合。如果接反把线圈正极接到输出脚、负极接电源达林顿管导通时线圈根本得不到正常压差还可能导致逻辑混乱。这是个高频翻车点尤其是用“两个继电器接电机正反转”时两个继电器不只要管触点还要注意线圈极性和驱动通道。控制端就按两路独立通道处理正反转逻辑放在程序里切换硬件上反而简单。3.2 续流二极管的COM脚接错了等于没接续流回路是电感负载驱动的命门。继电器线圈断电瞬间磁场消失电感两端会产生反向感应电动势极性是线圈下端接ULN2003输出脚的那端电压被抬高企图维持原电流方向。如果这个高压没有回路就会直接击穿输出管这就是为什么很多人用普通三极管驱动继电器时三极管莫名其妙损坏。ULN2003内部已经集成了续流二极管但它有个前提COM脚必须接到负载电源的正极。以5V继电器为例线圈正极接5V线圈负极接输出脚COM接5V。关断瞬间输出脚电压被抬高到略高于5V内部二极管从输出脚到COM正向导通电感电流经过COM回到电源电压尖峰被钳位在电源电压加一个PN结压降大约5.7V不会再造成击穿。我用示波器实测过COM接与不接的区别不接COM时继电器断开瞬间输出脚能看到一个明显的负向或正向尖峰幅度几十伏接好后尖峰被削平只剩下一个很窄的脉冲。所以判断你是否接对不一定要靠感觉示波器一抓就很清楚。还有一个细节如果继电器供电电源和逻辑电源不是同一个电源COM脚应该接到继电器线圈的那个电源正极而不是接到MCU的3.3V。比如线圈是12V那就接12V正极线圈是24V就接24V正极。COM脚只是续流二极管的汇流端和MCU没有直接关系。4. ULN2003 驱动步进电机接线顺序和相位控制4.1 28BYJ-48的标准接法公共线接电源而不是接地28BYJ-48是四相五线电机五根线里有一根是公共线通常是红色其余四根分别是A、B、C、D相。接ULN2003时公共线必须接电源正极四根相线分别接四个输出通道。注意一个高频错误有人把公共线当GND接到8脚结果通电后电机完全不动还可能过流。因为ULN2003输出管打开时是把相线拉低电流必须从电源正极→公共线→绕组→输出管→GND公共线接电源正极才有完整通路。GPIO和输入脚对应关系可以自己定义比如PB0接IN1→输出OUT1→橙线PB1接IN2→输出OUT2→黄线PB2接IN3→输出OUT3→粉线PB3接IN4→输出OUT4→蓝线。不同厂商的线序颜色可能有差异认准驱动板或电机标签上的A、B、C、D即可不一定非要按颜色死记。如果用的是淘宝常见的“ULN2003步进电机驱动板”板上已经画好了接线电机排线直接插上去驱动板输入端有IN1~IN4和GND、VCC跳线。这时要注意板上通常有电源指示灯和一个跳线帽选择外部电源还是板载取电。我用外部5V电源时会把跳线帽拔掉从外部电源端子直接给电机供电避免从MCU板上抽太多电流。4.2 驱动时序和为什么别把42步进接到ULN2003上单极性四相步进电机有单四拍和八拍两种驱动方式。单四拍顺序是A→B→C→D八拍顺序是A→AB→B→BC→C→CD→D→DA。八拍运行更平稳也能提升一定的位置分辨率我用28BYJ-48时一直用的是八拍。对应到四个输入脚可以把驱动序列写成二进制假定高电平表示对应相导通序列为0001、0011、0010、0110、0100、1100、1000、1001这里的1表示该相被拉低还是拉高取决于你输入脚的电平定义。实际上ULN2003是高电平输入才能导通所以软件上置高电平的那一路就是当前导通的相。每次切换相位之间要留出足够的延时一般1ms到5ms具体看电机特性和负载。延时太短电机跟不上脉冲可能出现丢步延时太长转速慢但扭矩稳定。我在轻载空转时用2ms带负载时放到3~5ms测试下来效果稳定。至于热词里提到的“步进电机ENA”一般是指驱动器上的使能信号ENA用于释放或锁住电机轴。ULN2003本身没有专门的ENA引脚但如果需要自由释放轴可以控制公共线电源的通断或者在驱动器外部加一个MOS管做电源开关。实际很小的项目里停止发脉冲并让所有输入为低电平电机仍会有定位力矩如果这个力矩影响调试再考虑断电释放。要特别强调42步进电机和28BYJ-48不是一回事。42步进通常两相四线额定电流1.5A量级ULN2003单通道500mA完全不够而且双极性绕组需要正反向电流ULN2003做不到。网上搜“42步进电机”“DRV8833两相四线步进电机”的基本都是在寻找替代方案。所以标题说“用ULN2003驱动步进电机”准确说是驱动28BYJ-48这类小电流单极性步进电机遇到42步进老老实实换A4988或DRV8825不要硬塞给ULN2003否则发热、失步、烧芯片都是早晚的事。5. 从光耦隔离到MCU引脚一整套可复制的控制链路5.1 光耦隔离到底什么时候该用很多教程喜欢在MCU和继电器之间加光耦比如PC817画出来的“光耦隔离继电器原理图”看起来很高端。但光耦隔离不是万能药加错了反而增加功耗、降低可靠性所以要先搞清楚它的用途。光耦隔离解决的是两个系统之间“不共地”的问题。比如MCU是3.3V系统继电器是24V工业系统两者如果直接共地电网侧的干扰可能通过地线串进单片机导致复位甚至烧毁用光耦把两侧的地完全分开信号通过光传递干扰就被切断了。这时不仅前级要光耦后级还需要独立的隔离电源常见做法是用B0505S这类隔离DC-DC模块给继电器侧供电不然光耦虽然隔离了信号地还是连着的隔离等于没做。反过来如果只是5V继电器、12V继电器MCU和继电器共用同一个电源共地完全没问题。这种场景下再加PC817不仅多花钱还会增加输入侧限流电阻的匹配负担。我的做法是纯低压板载项目不加光耦直接GPIO串一个1kΩ限流电阻接ULN2003输入工业现场或者电源质量差的场景才加PC817加隔离电源。这个原则比“看到继电器就加光耦”实用得多。5.2 STM32F103C8T6外围电路的实际连接方式如果用STM32F103C8T6做控制板GPIO输出高电平是3.3V直接接ULN2003输入脚完全可行。ULN2003输入侧内部有基极电阻输入匹配3.3V和5V逻辑都能认所以不需要额外电平转换。网上会搜到“三极管电平转换电路”的朋友多半是担心3.3V推不动5V负载在ULN2003这里这个担心不必要。实际接线建议这样GPIO到ULN2003输入端之间串一个1kΩ电阻。这个电阻不是功能必须但调试时很重要——万一某一路接错短路到地或有反压电阻能挡掉大部分电流板子和芯片活下来的概率大很多。继电器线圈正极接12V电源COM也接12VULN2003的8脚接电源地同时继电器侧5V或12V的地和MCU的地要连在一起否则输入信号没有参考地无法形成回路。供电顺序也要养成习惯先给MCU上电再给继电器负载上电。如果反过来继电器电源先建立、MCU还没初始化GPIO呈高阻态ULN2003输入端可能被杂散干扰拉高继电器会乱吸合。代码里初始化GPIO时先把所有控制引脚拉低再进入主循环这样即便负载电源先上电也不会误动作。电源分配上STM32F103C8T6板载稳压器最好只负责MCU本身继电器的12V和步进电机的5V单独从外部电源接入。我见过太多人用一个AMS1117同时给MCU、继电器、步进电机供电结果AMS1117过热保护整板反复重启。用外部电源适配器电机电源经过DC-DC降压到5V给逻辑供电比让单片机板硬扛强得多。6. 实测踩过的坑上电抖动、发热和电源分配6.1 上电瞬间继电器乱跳的真实原因有一次我调试一个两路继电器控制电机正反转的板子只要一上电继电器就“哒哒哒”乱跳几下然后才稳定。用示波器抓MCU引脚和ULN2003输入引脚发现MCU复位的几百毫秒里GPIO状态是不确定的有的是高阻态有的会短暂被拉高ULN2003输入端只要有一个高电平对应的继电器就会吸合。解决方法是双管齐下硬件上在每个ULN2003输入端到地并联一个10kΩ下拉电阻让输入信号在MCU未初始化时不飘软件上初始化代码一进来就把控制引脚全部配置为推挽输出并输出低电平再初始化其他外设。实测加了下拉电阻和初始化顺序之后上电抖动完全消失。注意下拉电阻不要太小1kΩ会额外消耗GPIO驱动电流10kΩ是比较稳的取值。还有一种情况是继电器自身触点抖动造成的“乱跳”假象尤其是继电器触点接的是电机时触点吸合瞬间会产生火花和电磁干扰可能反向干扰控制电路。这种情况应在继电器触点两端并RC吸收电路或者在电机端加续流二极管/压敏电阻而不是把锅全甩给ULN2003。6.2 ULN2003发热和系统供电分配的教训ULN2003带继电器基本不热因为继电器线圈电流只有几十毫安但带28BYJ-48步进电机时电机连续运行十几分钟后ULN2003微微发烫是正常的。达林顿管饱和导通时CE间仍有约1V压降5V×0.15A的绕组电流单路功耗大约0.15W四路轮流导通平均下来总功耗不小芯片表面温热正常但烫到不敢摸就不正常。烫到不敢摸通常有三个原因。第一输入占空比过高电机一直满电流运行没有加减速曲线这种情况可以降低PWM占空比或者用八拍而不是全步进第二堵转电机卡住时绕组电流持续冲击需要加堵转检测或者限流第三电源电压过高28BYJ-48标称5V有人图方便用12V直接驱动电机和IC都会发热异常这时候应该用降压模块先降到5V。还要检查一下COM脚是否按规范接了电源正极COM不接或者接错内部续流二极管不工作关断瞬间的尖峰也会让芯片发热加剧。供电分配上我吃过一次亏。当时把4路继电器和1个28BYJ-48电机全部挂在一个5V 1A的USB电源上4路继电器同时吸合大约280mA电机启动瞬间大约150mA再加上MCU板功耗总电流轻松超过500mAUSB电源电压被拖垮MCU反复复位。后来改成继电器用12V电源单独供电28BYJ-48用另一个5V电源逻辑板用一个独立5V DC-DC三个地最后在一点汇合系统再也没出现复位问题。多说一句与电源相关的经验继电器吸合瞬间电流比稳态高步进电机换相瞬间也有电流尖峰所以电源不能只看稳态电流要留至少1.5倍余量在靠近ULN2003的电源脚附近放一个100μF电解电容和一个104陶瓷电容可以吸收大部分尖峰原理图上看不起眼的两个电容在实测中能解决很多莫名其妙的复位和掉电问题。最后再分享一个调试习惯新板子第一次通电先不要插MCU用可调电源设置一个安全电流上限直接给ULN2003输入脚加手动高电平逐通道测试输出是否正常再接入MCU。这个习惯看起来多花几分钟但能帮你区分“电路问题”和“程序问题”比焊完就上电、烧了再查要省事得多。