ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

ULN2003驱动继电器与步进电机:从三极管到达林顿阵列实战指南

ULN2003驱动继电器与步进电机:从三极管到达林顿阵列实战指南 搞单片机外围电路最常遇到的三件事不外乎驱动继电器、带小步进电机、做电平匹配。很多老教程上来就教你先用三极管搭开关电路我自己也是从S8050一路焊过来的但当你手里有5个继电器要同时控制或者想快速带起一颗28BYJ-48步进电机时一颗ULN2003能把外围电路简化到让人上瘾的程度。它本质上就是7颗三极管加上反相缓冲和续流保护省掉了限流电阻、续流二极管等一大堆元件。这篇就手把手讲清ULN2003怎么选、怎么接线、怎么写代码以及继电器和步进电机驱动里那些必须注意的细节和坑。1. 别急着堆三极管先认清ULN2003的优势和边界1.1 单颗三极管驱动继电器的老问题用三极管驱动继电器最经典的方案是NPN低边开关继电器线圈一端接电源正极另一端接三极管集电极发射极接地基极通过一只限流电阻接到单片机的IO口。这个电路能用但每次都要重做一遍“计算防护”的流程比如继电器型号不一样线圈电流就要重新算限流电阻要重新选续流二极管也不能漏。一个5V继电器线圈电阻大约是70Ω工作电流约71mA用S8050这类小功率三极管时Ib至少需要Ic/hFE算出来约0.7mA实际取2到3倍余量再加上Vbe约0.7V5V驱动时基极电阻大概取1kΩ到1.5kΩ。这些计算本身不难但几路继电器下来板子上全是电阻和二极管布局难看不说排查故障也更麻烦。还有一个常见误区网上流传“三极管饱和时IB大于IC”这个说法不严谨。饱和的本质是Ib大于Ic/hFE也就是基极电流比临界饱和值更大并不是说基极电流一定要大于集电极电流。实际设计开关电路按Ic/hFE的2到3倍取Ib就足够饱和了别盲目加大基极电流否则白白增加功耗还容易让三极管发热。至于“三极管导通截止放大条件”一句话概括Ube大于0.7V是导通前提Ib足够大进饱和区当开关用Ib不够就落在放大区这时继电器会吸合不稳、吱吱响。再往上走PNP三极管开关电路也有坑。PNP通常是低电平导通单片机上电复位瞬间IO口如果处在高阻或高电平状态晶体管可能误导通继电器“啪”地吸合一下这在很多项目里是不能接受的。所以说三极管开关是基本功但不代表它是唯一选择。1.2 ULN2003内部到底是什么7路达林顿反相器的构成ULN2003是达林顿晶体管阵列内部集成了7路NPN达林顿对。每一路的结构可以理解成“两个三极管串成一个复合管”输入信号经过一个2.7kΩ电阻进第一级基极第一级发射极又接到第二级基极两级集电极一起接到输出引脚。这样做的直接好处是电流放大倍数极高单片机IO口只需要提供很小的驱动电流就能让输出端灌入比较大的负载电流。这个器件的关键参数我记得很清楚输出端耐压50V单通道最大输出电流500mA输入高电平兼容TTL和CMOS输出是集电极开路结构。也就是说输入为高电平时输出管导通电流从负载流向ULN2003输出脚再到地输入为低电平时输出管截止输出端相当于开路。所以ULN2003本质上是一个“反相驱动器”输入高输出低输入低输出高阻。更重要的是ULN2003内部每个通道都集成了一个续流二极管二极管的阴极统一接在COM引脚16脚。这个设计专门为感性负载准备。继电器线圈、步进电机绕组关断的瞬间由于电流不能突变线圈两端会产生反向电动势如果没有泄放回路很容易击穿驱动管。用了ULN2003后反电动势会通过内部二极管引到COM端再接回电源正极直接温和泄放掉。1.3 什么场景必须用ULN2003什么场景还得回到三极管ULN2003最适合的负载是5V或12V继电器、28BYJ-48这类小功率步进电机、小型电磁阀、LED点阵的段驱动、信号指示灯等。这些负载的工作电流基本在几十毫安到两三百毫安单路500mA的限值非常够用。但我也得把话说清楚ULN2003不是万能的。它只能做低边开关也就是负责把负载一端拉低到地没办法主动输出高电平去驱动负载想搭H桥控制直流电机正反转单靠它是做不到完整高边驱动的。其次单通道500mA的电流在真正的大功率负载面前不够看42步进电机相电流轻轻松松1.5A硬上ULN2003只会烫到怀疑人生。另外ULN2003没有隔离功能如果单片机和继电器之间需要电气隔离那还是得回到“光耦三极管/驱动芯片”的方案。三极管依旧有自己的位置比如单路低成本开关、大电流MOS管驱动、线性放大电路甚至那种用三极管搭建的电平转换电路都还会用到。只是说当你面对多路继电器和小步进电机的组合时ULN2003绝对是更高效的选择。2. ULN2003驱动继电器最小电路、取电方式和接线示范2.1 经典的线圈COM接法为什么这样接ULN2003驱动继电器的典型接线其实很简单。单片机任意一个GPIO口接到ULN2003的输入引脚IN1对应的输出引脚OUT1接到继电器线圈的一端继电器线圈的另一端接到外部的电源正极同时ULN2003的COM脚也接到同一个电源正极最后把电源负极和单片机的GND共地。这样当GPIO输出高电平时ULN2003内部导通电流从继电器线圈流进OUT1再到地继电器吸合GPIO输出低电平时线圈断电继电器释放。这里有两个关键点一定要理解。第一继电器线圈为什么接电源正极而不是接地因为ULN2003输出是低边开关只有把线圈一端接正电源、另一端接到输出脚输出管导通时才能形成完整回路。如果把线圈一端接GND另一端接输出脚输出管导通后就相当于把线圈两端都接到了地永远不会有电流流过。第二COM脚为什么必须接电源正极因为COM脚内部连接着所有续流二极管的阴极只有把它接到电源正极关断瞬间线圈产生的反向电动势才能通过内部二极管泄放到电源上。不接COM脚内部二极管形同虚设继电器关断瞬间产生的反压完全可能打坏ULN2003。输入引脚不需要外加限流电阻因为ULN2003内部已经有2.7kΩ电阻这是它比三极管方案省心的地方。驱动5V继电器时整个电路只需要四个连接点信号线、电源正极、COM、GND非常干净。2.2 和STM32F103C8T6最小系统联动电源、共地、GPIO配置很多新手做STM32F103C8T6外围电路时继电器部分其实只占很小一块但电源和共地处理不当会导致各种灵异现象。STM32F103C8T6是3.3V供电ULN2003输入兼容TTLGPIO推挽输出3.3V的高电平直接就能把输入级推起来不需要额外做5V电平转换。我在实测里直接用PA0、PA1、PA2接ULN2003的IN1、IN2、IN3驱动5V继电器非常稳定。共地这个事得啰嗦一遍。如果继电器用的是独立5V电源你必须把5V电源的负极和STM32的GND接在一起否则GPIO输出高电平时ULN2003输入的参考地和5V电源不统一继电器要么不动作要么乱动作。最好在继电器电源端加上一个100uF电解电容和一个100nF陶瓷电容用来吸收继电器吸合瞬间的电流冲击免得干扰到单片机的复位电路。STM32F103C8T6最小系统的外围电路也要检查到位NRST复位引脚接10kΩ上拉到3.3VBOOT0接10kΩ下拉到GND8MHz晶振两端各接一个20pF电容到地VDDA和VSSA不要悬空。很多时候继电器一动作MCU就重启问题不在继电器代码而在最小系统复位脚悬空或者电源滤波不足。GPIO配置上要把对应的引脚设置成推挽输出速度不用太高默认50MHz也行。代码里要注意上电时序单片机复位后GPIO默认是浮空输入状态这时ULN2003输入引脚悬空虽然达林顿管不一定导通但为了避免外部噪声干扰导致继电器误动作我习惯在初始化函数最开头就把GPIO拉低再切到推挽输出模式。如果你实在不放心可以在IN1到IN7对地各加一个4.7kΩ下拉电阻这样上电全过程继电器都稳稳处在释放状态。2.3 用两路继电器做电机正反转互锁和时序两路继电器接电机正反转这个词条我经常在搜“继电器驱动电路”的人那里看到这里分享一个我认为最不容易出错的接法。需要两个带常闭触点的SPDT继电器也就是每个继电器至少要有COM、NO、NC三个引脚。把电机两个端子分别接K1和K2的公共端COMK1的常闭端NC接GND常开端NO接VCCK2反过来NC接VCCNO接GND。当两路继电器同时释放时电机一端通过K1的NC到GND另一端通过K2的NC到VCC电机正转当两路同时吸合时电机两端对调反转。如果出现一个吸合、一个释放的状态电机两端同电位不会转也不会短路。这个接法比“一路控制高、一路控制低”的经典H桥式接法安全因为任何情况下都不会出现电源正负极直接短路的路径。但要注意电机是感性负载直接切换继电器触点会产生火花长期使用会烧蚀触点。我的做法是方向切换前先把两路继电器全部释放延时10ms到20ms再让两路同时吸合换向这样能明显减少触点电弧。如果继电器没有引出NC引脚只能用单刀单掷触点搭H桥那程序里必须严格互锁先全部断开延时再接通目标方向绝不能出现两路同时导通的情况。我见过不少板子在这个环节直接冒烟多半就是两个继电器同时吸合把电源直接短路了。用ULN2003来驱动这两路继电器时两个输入引脚分别接单片机两个GPIO即可。一个5V继电器线圈按70mA算两路同时导通也就是140mAULN2003单通道500mA的余量非常充足发热很小。3. ULN2003驱动步进电机从28BYJ-48到42步进的电流账3.1 28BYJ-48五线四相步进电机标准接法ULN2003驱动步进电机最经典的搭配是28BYJ-48这颗小电机在网上有大量配套的ULN2003驱动板五根线一起被接好排针直接引出来。28BYJ-48是5V四相五线制步进电机内部有减速齿轮减速比约1比64适合做云台、摇头风扇、自动窗帘这类对精度和扭矩要求不高、但对成本敏感的场合。五根线的颜色通常是红、橙、黄、粉、蓝其中红色线是中心抽头接外部5V电源正极橙色、黄色、粉色、蓝色分别对应四相绕组。驱动板上一般已经把这五根线对应到了IN1到IN4和电源正极你只需要把驱动板的IN1到IN4接到单片机任意四个GPIO把驱动板电源接到5VGND和单片机共地即可。默认顺序是橙色接IN1、黄色接IN2、粉色接IN3、蓝色接IN4如果发现电机转起来方向不对或者抖动不转把橙色和黄、粉和蓝的顺序对调一下再试大概率就能正常。需要特别强调28BYJ-48的额定电压虽然是5V但它的相电流大约在200mA级别ULN2003单通道500mA是可以从容带动的。我见过有人把它接到12V电源上结果电机发烫、驱动器冒烟就是因为超过额定电压太多电流飙升。电源电压这个东西只能按电机的铭牌来不能想当然往上加。3.2 八拍工作方式和STM32代码示例步进电机的工作原理就是给四相绕组按顺序通电每改变一次通电组合定子磁场就转过一个角度转子跟着转一个固定步距角。28BYJ-48这种四相电机常用八拍方式驱动通电顺序是A、AB、B、BC、C、CD、D、DA。相比单四拍八拍的步距角更小运行也更平稳。如果把这八拍对应的引脚电平整理成一个表格就是下面这个样子拍号橙(IN1)黄(IN2)粉(IN3)蓝(IN4)十六进制110000x01211000x03301000x02401100x06500100x04600110x0C700010x08810010x09在STM32F103C8T6上用HAL库写驱动代码可以直接把表格放进一个数组里循环查表输出代码非常简短#define MOTOR_GPIO GPIOB #define IN1_PIN GPIO_PIN_8 #define IN2_PIN GPIO_PIN_9 #define IN3_PIN GPIO_PIN_10 #define IN4_PIN GPIO_PIN_11 const uint8_t step_table[8] { 0x01, 0x03, 0x02, 0x06, 0x04, 0x0C, 0x08, 0x09 }; void set_motor(uint8_t phase) { HAL_GPIO_WritePin(MOTOR_GPIO, IN1_PIN, (phase 0x01) ? GPIO_PIN_SET : GPIO_PIN_RESET); HAL_GPIO_WritePin(MOTOR_GPIO, IN2_PIN, (phase 0x02) ? GPIO_PIN_SET : GPIO_PIN_RESET); HAL_GPIO_WritePin(MOTOR_GPIO, IN3_PIN, (phase 0x04) ? GPIO_PIN_SET : GPIO_PIN_RESET); HAL_GPIO_WritePin(MOTOR_GPIO, IN4_PIN, (phase 0x08) ? GPIO_PIN_SET : GPIO_PIN_RESET); } void motor_step(uint16_t steps, uint16_t delay_us, uint8_t reverse) { for (uint16_t i 0; i steps; i) { uint8_t idx reverse ? (7 - (i % 8)) : (i % 8); set_motor(step_table[idx]); delay_us(delay_us); } }这里的delay_us是微秒级延时实际工程里可以用SysTick或者DWT来实现。速度调节主要靠这个延时参数八拍模式下延时在500us到2000us之间比较合适太短了电机跟不上会丢步太长了会有明显的顿挫感。28BYJ-48因为内部有1比64的减速齿轮输出轴转一圈大约需要4096个八拍脉冲所以想让电机精准转90度就把steps设成1024。停止电机的时候要注意最好把四个GPIO全部输出低电平也就是set_motor(0)让所有绕组断电。如果让电机停在某个保持相线圈会一直通电长时间下来电机和ULN2003都会发热。3.3 ULN2003带不动42步进电流计算和A4988/DRV8823的ENA接线很多人看到标题是“ULN2003驱动步进电机”就想当然把42步进电机也往ULN2003上接结果电机不转、芯片烫手。这里算一笔账就清楚了常见42步进电机如42BYGH相电流在1A到1.7A之间而ULN2003单通道最大输出只有500mA差了至少3倍。哪怕是四路并联总电流也只有2A左右但并联后每路均流不一致达林顿管的饱和压降又高芯片功耗会大得离谱根本不适合长期工作。42步进电机应该用专用步进电机驱动器比如A4988、DRV8825、TB6600。A4988性价比较高但建议实际工作电流控制在1A以下DRV8825的峰值能力更强适合相电流1.5A到2A左右的应用。这类驱动板的接线一般是VMOT接电机电源VDD接逻辑电源STEP和DIR分别接单片机两个GPIOEN也就是使能引脚用来控制驱动器是否输出电流。这里有个经常出现的词条叫“步进电机ENA”其实就是驱动器上的使能信号。大部分驱动板是低电平有效也就是ENA接逻辑电源正极ENA-接单片机GPIOGPIO输出低电平时驱动器使能输出高电平时电机释放。如果你希望电机一直处于锁定保持状态可以把ENA-直接接地但那样电机会持续发热调试时通常是先让ENA处于释放状态方便手拧电机轴。还要注意这些专用驱动板的逻辑输入兼容3.3VSTM32F103C8T6可以直接接STEP、DIR、ENA但最好查一下具体板子的手册。有些板子需要限流电阻有些则内置了我遇到过便宜板子不标清楚导致电流灌进单片机引脚的情况后来统一在信号线上串了1kΩ电阻稳妥很多。4. 外围电路细节电平匹配、光耦隔离和PCB布局4.1 3.3V逻辑直接驱动ULN2003的可行性很多刚接触嵌入式的人一看到ULN2003输入兼容TTL/CMOS就担心3.3V单片机能不能直接驱动。我实测下来STM32F103C8T6的3.3V推挽输出直接接ULN2003输入引脚完全没问题。原因在于ULN2003每一路输入内部串联了2.7kΩ电阻输入高电平阈值大约在2V左右而STM32推挽输出高电平在3.3V足够让达林顿管进入饱和。不过有两点要注意。第一如果单片机GPIO口配置成开漏输出那必须外部加上拉电阻一般是4.7kΩ到10kΩ上拉到3.3V或5V否则输出无法主动拉高。第二1.8V电平的单片机就别指望直接驱动ULN2003了最好加一个三极管电平转换电路或者用低压版本的驱动芯片。至于网上常见的“三极管电平转换电路”它解决的是3.3V和5V之间双向或单向逻辑通信的问题ULN2003并不是电平转换芯片它只是单向反相驱动器不能替代1.8V转3.3V这种场景。还有一个很多人会混淆的点ULN2003的输出是集电极开路输入高输出低它和“三极管取反电路”的逻辑很像。输入高电平输出导通到地输入低电平输出断开。所以如果你要控制的负载必须由“高电平”驱动比如某些逻辑高电平触发的固态继电器模块那直接用ULN2003的输出去接就不行你得把负载的另一端接到电源正极让ULN2003把这一端拉低这才是正确的用法。4.2 光耦隔离、三极管开关和ULN2003的配合边界光耦隔离继电器原理图是另一个高频搜索词。很多要求较高的项目单片机和继电器不共地或者继电器附近有大功率感性负载为了不让干扰通过地线回流到单片机会在驱动链路上加光耦。PC817是很常用的光耦连接方式是单片机GPIO接一个限流电阻到光耦输入侧LED正极LED负极接GND电阻取330Ω3.3V到470Ω5V比较合适光耦输出侧的三极管集电极接继电器线圈的一端线圈另一端接电源正极发射极接GND同时线圈两端要反向并联一个续流二极管。这样单片机和继电器之间只有光信号耦合没有电气连接干扰很难传过去。ULN2003本身不具备隔离功能它只是把多路驱动集成到一起。你要隔离正确的做法是“光耦在前、ULN2003在后”也就是光耦输出再接到ULN2003输入ULN2003输出再接继电器。但说实话如果项目对隔离没有那么高要求直接用带光耦隔离的成品继电器模块更省事模块内部已经完成了光耦和驱动晶体管的配合。有一点必须提醒光耦输出侧的电流能力有限PC817最大约50mA直接驱动5V继电器线圈问题不大但驱动12V、24V大功率继电器时电流不够这时要在光耦输出后再加一个三极管或MOS管扩流。也有人直接用光耦驱动ULN2003利用ULN2003的高达林顿增益来放大电流这个方案在需要同时隔离和多路驱动时很实用我做过一次效果稳定。4.3 PCB布局、电源滤波和散热建议如果你把ULN2003、继电器、步进电机接口这些都画到STM32F103C8T6的底板上PCB布局上要刻意把“小信号”和“功率”分开。单片机最小系统、晶振、去耦电容放在板子一侧ULN2003和继电器、电机接线端子放在另一侧中间尽量用地线或敷铜隔离。ULN2003输出脚是低边开关电流最后会从GND回流所以ULN2003的GND引脚到电源负极这一段的走线尽量短和粗。继电器和电机的电源线按通过电流选宽度1A电流大概需要1mm宽的铜箔如果只跑几十毫安的继电器线圈0.5mm也可以但我习惯留足余量统一走1mm以上。ULN2003如果长期工作在300mA以上DIP封装最好加一个散热焊盘或直接铺铜辅助散热我见过有人用ULN2003驱动1A负载连续跑最后芯片外壳烫到变色这种情况就该换驱动方案了。电源滤波也顺便说一句。整个板子建议在总电源输入端放一个100uF电解电容和100nF陶瓷电容继电器和步进电机电源再接一个220uF电解电容。STM32F103C8T6的VDDA和VDD引脚附近也要各放100nF电容这样继电器吸合瞬间的大电流不会把MCU供电拉出毛刺。5. 常见故障排查与实测避坑5.1 故障速查表从继电器不吸合到步进电机丢步调试外围电路时遇到问题先别急着改代码对照现象查硬件往往更快。我把这些年实际遇到过的问题整理成一张速查表可以直接照单排查。现象常见原因排查与解决继电器完全不吸合COM脚没接电源正极检查COM脚是否接到继电器线圈电源正极继电器吸合无力、抖动电源电流不足或电压偏低换更大功率电源加100uF电容单片机上电瞬间继电器误动作GPIO初始化前电平不定外部接4.7kΩ下拉电阻初始化先拉低电机不转或只抖不转28BYJ-48线序不对按橙黄粉蓝顺序重接或调换相位顺序电机转到某个位置后发热严重停止时绕组仍通电停止后调用set_motor(0)让输出全低ULN2003烫手负载电流超过500mA或长时间接近上限换专用驱动或并联通道但要注意散热步进电机通电后锁死但无法转动ENA使能逻辑颠倒检查驱动板ENA和ENA-接法测试反接继电器动作时MCU重启电源共地不良、复位脚悬空确保共地复位脚接10k上拉加滤电容两路继电器正反转冒烟两个继电器同时吸合导致短路换用“同吸同放”接法或程序严格互锁信号灯组驱动时逻辑反了输入高输出低负载接法不对确认负载一端接电源正、另一端接ULN2003输出这条表看起来简单但每一条背后都可能是几个小时的排查时间尤其是COM脚和共地这两个点我敢说新手遇到问题一大半都出在这。5.2 我踩过的几个典型坑和最终方案第一个坑是COM脚接GND。那时候刚接触ULN2003照着网图把负载、COM、GND一股脑全接到地结果继电器一点反应都没有。后来翻了手册才明白COM脚内部是续流二极管的公共阴极必须接负载电源正极接GND等于把续流二极管废掉。这个坑印象太深了后来每次画原理图都会在ULN2003的COM脚旁边写一行注释“注意接VCC”。第二个坑是28BYJ-48的线序。第一次驱动时电机抖动不转我看网上说“把顺序反过来就行”改来改去还是抖。后来发现是供电功率不足电机和单片机共用一个USB供电USB电流不够电机启动瞬间把电压拉低到3V左右导致逻辑混乱。解决办法是电机和单片机分开两个电源但一定要共地。从那以后凡是涉及继电器或电机我都默认用独立电源共地单独接一根粗线。第三个坑是继电器干扰MCU。有一次做电磁锁控制继电器一吸合STM32就复位程序完全没法跑。查了一圈复位脚悬空继电器电源没有滤波地线也走得细。我把复位脚补上10kΩ上拉继电器电源端加220uF电容问题直接消失。很多所谓的“单片机死机”问题其实都是外围电路细节不到位。第四个坑是用ULN2003硬驱42步进电机。当时手头没有驱动器想着并联几个通道试试结果电机脚步无力芯片发热严重。后来老老实实买了一块DRV8825接上ENA、DIR、STEP两三行代码就转得飞起。从那以后我给自己定了个规矩负载电流超过300mA先查数据手册别靠“并联凑电流”这种野路子。最后分享一点自己的习惯我现在手边常年备着一块ULN2003模块和几个5V继电器调试任何板子都能快速搭出驱动部分。经验这东西都是在踩坑里攒出来的三极管开关电路当然要会但一旦确认负载属于“多路、低电压、开关型”ULN2003这种集成方案真的能省下大量时间。真正需要上大功率电机、做电气隔离或者追求极致成本时再回到三极管、光耦、MOS管重新搭配也不迟。希望这篇文章能让你少走几段弯路下次画板子或接线时多一个更稳妥的选择。
返回列表