
别再纠结了用ULN2003驱动数码管共阴共阳到底怎么接附实测电路图第一次用ULN2003驱动数码管是在一个周末的项目里折腾到凌晨两点。照着网上搜来的电路图焊好板子上电数码管纹丝不动。排查了一个多小时最后发现罪魁祸首根本不是代码而是我手里的数码管是共阴网上的图用的是共阳。就这一个“阴”和“阳”的区别让无数新手在ULN2003面前栽了跟头。这篇文章就把这件事彻底讲明白ULN2003为什么能驱动数码管、共阴共阳分别该怎么接、限流电阻怎么选、动态扫描有哪些坑以及我在实测中踩过的各种问题。不说废话直接上干货最后附上可复现的实测电路说明和排查表希望能帮你少走几小时弯路。1. ULN2003和数码管先搞懂这俩的“脾气”1.1 ULN2003的实质7路达林顿管阵列输出是“灌”进去的很多朋友把ULN2003当成一个“万能驱动芯片”拿来就接亮了就算不亮就懵。要搞明白它能不能驱动数码管得先弄清楚它内部到底是什么。ULN2003是典型的达林顿晶体管阵列内部集成了7路NPN达林顿对。每一路的逻辑很简单输入端给高电平输出端就导通相当于一根开关把输出接到地输入端给低电平输出端就断开。注意输出端断开的时候它并不是输出一个高电平而是处于悬空状态。这是因为ULN2003的输出极是集电极开路OC门结构内部没有任何上拉电阻。这个特性决定了ULN2003天生适合做“灌电流”驱动。什么叫灌电流可以想象它像一排放到地面的接地开关负载的一端接正电源另一端接ULN2003的输出端。当某一路开关合上时电流从正电源流过负载被“灌”进ULN2003再流到地负载工作。驱动继电器、步进电机、LED灯珠用的都是这个原理。所以记住一句话ULN2003是低压侧驱动器件它把负载的另一端拉到地让电流通过负载。它不是推挽输出不会主动往外面“推”电压。这个本质决定了它在共阳和共阴数码管面前的表现完全不同。1.2 共阴和共阳区别就在公共端数码管是由多段发光二极管组成的共阴和共阳描述的是这些二极管的连接方式。共阳数码管所有段的发光二极管阳极连接在一起引出一个公共端COM工作时COM接电源正极。点亮某一段只需要把该段的阴极拉低让电流从COM流入经该段LED从段脚流出到地。共阴数码管所有段的发光二极管阴极连在一起公共端COM接GND。点亮某一段需要从段脚流入电流经过LED到COM然后到地所以要靠段脚输出高电平来点亮。两种数码管点亮条件完全相反共阳要“低电平点亮段”共阴要“高电平点亮段”。ULN2003输出端能做什么它只能把段脚拉低或者让段脚悬空。拉低正好满足共阳数码管的点亮条件而悬空在共阴数码管面前毫无意义。这就是为什么ULN2003驱动共阳数码管顺理成章而驱动共阴数码管大多数人一接就翻车。1.3 数码管“静态显示”和“动态扫描”对驱动的要求数码管的显示方式大致分两种。静态显示每个数码管的段脚由独立的信号持续控制显示内容稳定不依赖扫描。优点是程序逻辑简单、不闪烁缺点是占IO口太多3位数码管就要占用21个IO3个位选再加8个段选具体看电路MCU一般扛不住。实际中常用锁存器、移位寄存器扩展或者用ULN2003等驱动芯片减少MCU直接驱动的压力。动态扫描所有数码管的段选共用一组IO位选单独控制。程序轮流让每一位导通几百微秒到几毫秒利用人眼视觉暂留看起来所有位都在同时亮。这种方式大大减少IO占用3位数码管只需要3个位选8个段选11个IO再配合ULN2003这类驱动芯片MCU的IO压力小很多。ULN2003在两种模式下的角色通常是负责段选信号的大电流驱动把MCU的IO逻辑电平转换成能点亮LED段的大电流灌入能力。如果只是静态显示一位或两位数码管IO口直接串电阻也能点亮但亮度有限且容易让MCU过热接到ULN2003上输入只需很小电流输出能承受更大电流稳定可靠得多。2. 共阳数码管实测按这个接基本一次成功2.1 元器件清单和接线逻辑我这次实测用的是最普通的红色共阳数码管型号类似3611BS加上一块ULN2003模块这几样东西几乎每个电子爱好者手边都有。清单如下共阳数码管1个管脚排列是上四下四那种具体看引脚图最好用万用表确认ULN2003芯片或模块7路用6路就够a、b、c、d、e、f、g如果要小数点就占7路220Ω或330Ω限流电阻8个5V电源或开发板我用的STM32电源从板子取5V面包板和杜邦线若干接线逻辑的一句话版本MCU的IO口接ULN2003输入端ULN2003输出端串限流电阻接数码管段脚数码管公共端COM接VCC所有GND共地。下面是实测用的接线示意图我尽量画清楚5V ─────────────────────────────┐ │ 共阳数码管COM公共端 │ ┌── a ── R(220Ω) ── OUT1(ULN2003) ├── b ── R(220Ω) ── OUT2 ├── c ── R(220Ω) ── OUT3 ├── d ── R(220Ω) ── OUT4 ├── e ── R(220Ω) ── OUT5 ├── f ── R(220Ω) ── OUT6 ├── g ── R(220Ω) ── OUT7 └── dp── R(220Ω) ── OUT8(ULN2003第8路若有) │ MCU IO1 ───── IN1(ULN2003) │ MCU IO2 ───── IN2 │ MCU IO3 ───── IN3 │ MCU IO4 ───── IN4 │ MCU IO5 ───── IN5 │ MCU IO6 ───── IN6 │ MCU IO7 ───── IN7 │ │ GND ───────── GND(ULN2003) ───────┘这里有个细节ULN2003的输出端是集电极开路外部负载接在哪端呢正确接法是负载数码管段LED一端接限流电阻限流电阻另一端接ULN2003输出端数码管段LED另一端其实是在数码管内部汇到COM而COM接VCC。这样当ULN2003导通时电流路径是VCC→COM→段LED→段脚→限流电阻→ULN2003输出→地LED点亮。2.2 限流电阻怎么选算一次你就记住了关于限流电阻网上说法很乱有人用100Ω有人用1kΩ。其实可以用欧姆定律一次算清楚。5V供电下红色LED的正向压降通常在1.8V~2.2V取1.9V计算。ULN2003在输出导通时饱和压降约为1V左右。于是整个回路上除限流电阻外的压降是1.9VLED1VULN2003饱和压降2.9V限流电阻需要承受的电压是5V-2.9V2.1V如果想让数码管工作在10mA左右普通红色数码管这个电流已经比较亮R2.1V/0.01A210Ω所以实测中220Ω就很合适。如果想让亮度更高一点例如15mA可以选150Ω如果只是近距离显示330Ω也能亮只是稍暗而且更省电。我实测的结论是5V供电、红色共阳数码管用220Ω限流电阻显示效果和寿命都比较好。绿色或蓝色数码管LED压降更高约3.0V~3.4V同样的电阻下电流会小一些可能显得暗可以适当减小电阻到100Ω~150Ω。另外多位数码管动态扫描时每一位只有1/位数的占空比在工作平均亮度会下降可以把限流电阻适当调小一点比如10mA占空比下用150Ω甚至100Ω具体根据实测亮度来。但切勿去掉限流电阻直接短接LED会瞬间烧掉。2.3 实测案例点亮一个“8.”和一个倒计时我用STM32F103的PA0~PA6分别接ULN2003的1~7路输入PA7接第8路控制小数点。数码管用共阳COM接5V。测试程序很简单先把a~g全置高数码管显示“8.”#include stm32f1xx_hal.h void GPIO_Init(void) { __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitTypeDef GPIO_InitStruct {0}; GPIO_InitStruct.Pin GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7; GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull GPIO_NOPULL; GPIO_InitStruct.Speed GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOA, GPIO_InitStruct); } void Display_8_Dot(void) { HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET); // a HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET); // b HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET); // c HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET); // d HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET); // e HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET); // f HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET); // g HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_SET); // dp }注意STM32的IO输出3.3V高电平ULN2003输入高电平门槛不高实测驱动没有任何问题。如果一个IO口推不动可以并两个IO口但通常没必要。51单片机5V系统就更稳了直接接就行。如果要用51做倒计时秒表思路也差不多用定时器产生1秒中断秒值减到0时停止显示部分用动态扫描3位数码管位选分别接到另外的IO口注意动态扫描的位选需要额外电路下面会说。ULN2003照旧接段选代码部分无非是多一个位选轮询函数和段码表。段码表我直接给你参考共阳数码管、段脚按a-b-c-d-e-f-g-dp排列低电平点亮时用取反值// 共阳数码管段码表1表示段灭0表示段亮 const unsigned char code SEG_CODE[] { 0xC0, // 0 0xF9, // 1 0xA4, // 2 0xB0, // 3 0x99, // 4 0x92, // 5 0x82, // 6 0xF8, // 7 0x80, // 8 0x90, // 9 };如果用ULN2003做低电平驱动输入高电平让输出拉低点亮段所以MCU输出的段码要和“低电平点亮”匹配。上面这份是共阳数码管常用取反码喂给ULN2003输入端前要确认逻辑方向一致需要点亮的段给高电平熄灭的段给低电平。所以实际用这份表时把表里的1/0反过来理解更方便或者在代码里做一次按位取反。2.4 用ULN2003做动态扫描的注意点动态扫描最经典的做法是段选由ULN2003驱动、位选由PNP三极管或锁存器控制。因为共阳数码管的公共端接VCC选通某一位时需要让该位的COM保持高电平不选通时COM需要断开或者拉低。ULN2003是低位导通不擅长直接控制高侧位选所以位选我用的是PNP三极管比如S8550反相控制IO输出低时三极管导通COM接VCCIO输出高时三极管截止该位灭。如果你手里的ULN2003模块上带了“COM”引脚9脚这个引脚是内部续流二极管的公共端用来接感性负载电源用的。驱动数码管这种纯阻性负载COM引脚可以悬空千万别把它和数码管COM搞混。动态扫描时有一个坑ULN2003输出的关断有延迟。实测扫描频率超过2kHz后容易出现“拖影”或亮度不均。建议扫描周期控制在1kHz到2kHz每位点亮时间1ms左右并且在切换位选时先关闭段选消隐再切换位选最后打开下一段的段选。否则切换瞬间容易看到上一段余晖。3. 共阴数码管怎么办别硬接换条路走3.1 直接用ULN2003驱动共阴为什么不行我见过不少新手把共阴数码管的段脚接到ULN2003输出端以为输入高电平点亮段。结果上电后整个数码管要么全灭要么亮度极低要么部分段伴随微弱发光。原因不复杂。共阴数码管的COM接GND段脚需要正电压才能点亮。ULN2003的输出端只有两个状态导通接近0V和截止悬空。导通时段脚被拉到0VLED两端电压几乎为0不会亮截止时段脚悬空电压由漏电流决定电流极小基本也点不亮。更麻烦的是某些“特殊接法”号称能用ULN2003驱动共阴实际上是把ULN2003放在位驱动位置将公共端拉低来选通。比如某一位共阴数码管的COM接ULN2003输出输入高电平时COM被拉低同时段脚由IO或其它驱动芯片输出高电平才能点亮。这种方案绕了一圈段驱动实际靠的不是ULN2003。所以想用ULN2003直接驱动共阴数码管的段本质上就是接反了方向逻辑完全错误。别在这个方向上死磕。3.2 共阴数码管的3种可行驱动方案如果手里已经有共阴数码管且一定想用我有三种方案供你选按省事程度排序。方案一换共阳数码管。这是最省事的办法成本几毛钱拆下来换个型号电路照前面第2章接立刻搞定。别觉得换管子“丢人”我后来做项目都是先确认共阴共阳再画板绝不在这上面浪费时间。方案二段驱动用MCU IO口或74HC573/74HC245这类高电平输出缓冲器ULN2003只做位驱动。这个方案适合动态扫描的共阴多位数码管。位选部分让ULN2003拉低COM段选部分用IO口直接推高电平点亮段。要注意的是共阴管的段电流全部汇到COM再由ULN2003流向地COM要承担所有段的电流总和ULN2003每路最大500mA3~5位数码管完全够。但IO直推段的驱动能力有限一个IO口一般只能稳定输出几mA到20mA多位同时亮可能出现亮度不够。这时可以在段驱动加74HC573或74HC245缓冲。方案三用CD4511、74HC164这类专用译码/移位芯片。CD4511是BCD七段译码器输入4位BCD码输出七段码输出为高电平有效正好适配共阴数码管。缺点是它只支持0~9数字不支持小数点需要小数点得另外加IO控制。74HC164是8位串入并出移位寄存器串行数据从IO口进来并行输出给共阴数码管的段脚优点是可以多片级联驱动多位缺点是显示数据要自己算好段码。我实测过CD4511配共阴数码管的方案显示数字很清晰但亮度一般因为CD4511输出驱动能力有限几mA级别用在小尺寸高亮数码管上还能接受。如果希望字更亮最好在CD4511输出后面加缓冲或换方案。3.3 带小数点、多位数码管的特殊接法共阴数码管的小数点dp段和普通段一样段脚需要高电平才能点亮。用方案二时dp脚直接接IO或缓冲输出即可。多位共阴数码管动态扫描时位选COM分别接ULN2003的不同输出段选共同接IO缓冲。程序上先送段码再选通该位。举个例子2位共阴数码管动态扫描段选共用B0~B7位选COM1接ULN2003 OUT1COM2接OUT2。显示第一位数时先让OUT1输入为高电平COM1被拉低同时段脚送高电平点亮需要的段显示第二位数时把OUT1关闭OUT2打开循环扫描。这里要特别注意共阴动态扫描和共阳动态扫描的位选逻辑是相反的共阴位选是“拉低选通”共阳位选是“拉高选通”。如果套用网上共阳的位选程序去驱动共阴结果一定是显示错乱、亮度不均甚至不亮。4. 实测踩坑记录不亮、乱码、亮度不均4.1 常见故障现象与排查顺序我在各种现场调试中总结出一个排查顺序电源→公共端→段脚→IO逻辑→代码。每次出问题按这个顺序查能少走很多弯路。先说电源。ULN2003需要共地单片机、数码管、ULN2003三者的GND必须连在一起。电源电压不足也会导致数码管亮度低或者闪烁尤其动态扫描时电流大劣质电源压降明显。我用过一个5V/500mA的充电头带4位数码管一上电电压掉到4.3V字非常暗换个1A电源立刻正常。再查公共端。共阳数码管的COM没接VCC或者共阴的COM没接GND就是最常见的“不亮”原因。很多人以为COM就像芯片电源一样必须接没错但经常在接很多根线时漏接COM或者用面包板时COM和旁边脚短路。段脚排查。常见问题是用错引脚顺序把a段接到OUT2上显示8的其中一笔由另一段驱动数字越看越怪。最靠谱的做法是用万用表二极管档先确认数码管公共端和每个段脚的对应关系再根据引脚图核对板子走线。推荐买数码管时先找数据手册找不到就用万用表从头测一遍别靠猜。IO逻辑和代码基本是最后查的。ULN2003输入端高电平有效输入端悬空也可能导致输出导通所以MCU不驱动的IO口要设为低电平或下拉。动态扫描代码里尤其要检查位选和段选的切换顺序消隐没做好容易有鬼影。4.2 用万用表判断共阴共阳不用猜不知道手里数码管是共阴还是共阳不需要猜万用表二极管档20秒搞定。做法万用表拨到二极管档红表笔接数码管的某个引脚先假设是公共端黑表笔依次碰其余引脚。如果数字显示某个正向压降值约1.5~2.5V说明红表笔接的是公共端而且该数码管是共阳因为阳极接红表笔电流经LED到黑表笔的阴极段脚正向导通。如果红表笔接公共端时没有读数反过来黑表笔接该引脚红表笔碰其他引脚有读数则说明黑表笔接的是公共端数码管是共阴。确定公共端后把公共端固定用红表笔或黑表笔扫描其他引脚就能画出每个引脚对应哪一段。这个办法我每次拿到没资料的数码管都用比看丝印可靠得多。4.3 Proteus仿真里的几个易错点很多人在Proteus里仿真不亮或者乱码经常不是逻辑问题而是元件选错。Proteus库里的数码管常用模型名称共阳是7SEG-COM-ANODE共阴是7SEG-COM-CATHODE。别小看这一字之差选错模型仿真电路和实物完全对不上。还有一种“MPX”系列是多位数码管例如7SEG-MPX8-CC-BLUE表示8位共阴蓝色数码管。注意“COM-ANODE”是共阳“COM-CATHODE”是共阴顺序别记反。另外一个常见仿真问题是ULN2003在Proteus里的引脚。部分库版本中ULN2003的引脚和实物不完全一致或需要给COM引脚接电源才能正确显示续流二极管特性。驱动数码管时COM悬空就行但如果仿真结果异常可以把COM接VCC试试对纯电阻负载不影响。仿真不能代替实测尤其在动态扫描时仿真里看不出刷新率不足、鬼影、驱动能力不够这些硬件问题。我习惯先用Proteus验证代码逻辑再上真实板子测硬件两头都要。4.4 常见接线错误速查表这里按我踩坑概率从高到低整理了一个速查表建议收藏。现象可能原因解决方法数码管完全不亮共阳COM没接VCC / 共阴COM没接GND万用表确认公共端并正确连接数码管完全不亮ULN2003 GND和MCU GND没共地所有GND连在一起数码管完全不亮IO口全部输出低电平ULN2003不导通按段码表给对应IO设高电平数字乱码某几段总是反着亮段脚接错位置用万用表测段位映射重新接线某一段不亮该段限流电阻开路或虚焊检查该段回路电阻和焊点整体亮度偏低限流电阻太大/电源电压不足换小电阻换大功率电源显示闪烁亮度不均动态扫描频率太低或位选延时太长提高扫描频率到1kHz以上均匀分配位时间切换数字时有拖影ULN2003关断延迟扫描切换未消隐位选切换前先关闭全部段选数字全亮但有一两位多亮共阳共阴搞反或代码位选逻辑反了确认数码管极性调整位选逻辑这个表不能解决所有问题但覆盖了绝大多数翻车现场。第8条“切换数字时有拖影”很多人一开始不会注意等做时钟、秒表这类动态刷新显示时就会遇到。解决方法是段选置全0或全1做消隐然后改位选再开新段。稍微加几行代码的事别偷懒。还有一个容易忽略的点ULN2003输入不能悬空。如果MCU还没初始化或者某个IO处于高阻态ULN2003输入端相当于浮空可能会随机导通数码管就出现“乱跳”的段。解决方法是在MCU初始化时把所有控制IO先设为推挽输出低电平或者硬件上加下拉电阻10kΩ到GND即可。这次实测下来我的体会是ULN2003驱动数码管这件事弄懂原理比抄电路重要得多。弄清了“灌电流”和“拉电流”的区别共阴共阳不会再是玄学动态扫描的时序也能理清楚。如果你正要搭板子我的建议是提前花两分钟用万用表确认一下数码管极性电阻按220Ω起步电源选大一点余量先把一位静态显示调亮再去做多位动态扫描扩大规模。最后再分享一个小经验手边备两种数码管共阳、共阴各一调试时遇到反过来接的板子也能立刻交叉验证不会卡在原地。