Arduino’s and LEDs
An LED is a Light-Emitting Diode, which I’ve covered separately on my LEDs for Modelers page. But using LEDs with an Arduino adds come complexity.
Voltage and Resistance
Arduino’s come in versions with two different base voltages: 3.3V and 5.0V (I’ll ignore the LillyPad models, which operate over a range of voltages, since they’re mostly for clothing). Most are 5V, and I’ll assume those for this page, but the Pro and Pro Mini are also available in 3.3V versions, and so you’d need to modify this advice a bit if you use one of those.
Because LEDs typically have an operating voltage between 1.6 and 3 volts, a resistor in series with the LED is required to discard the excess voltage. For a typical LED of 20-30 mA, to be safe a 180 ohm 1/8 W resistor should be used. This will be rather oversized for green and white LEDs, and a trifle high for yellow ones (and even some red ones) and make them dimmer than necessary. If you know the specific “Forward Voltage” of your LED, calculate the actual size required. To do that, divide five minus the forward voltage by the current in amps and round up to the next standard resistor size (see the LEDs for Modelers page for a list of those): for a green LED with 2.1Vf and 20 mA current, that’s (5-2.1)/0.020=145, rounding up to 150 ohms.
If you want to allow more current you can use smaller resistors, or if you are using LEDs with less current (like SMD LEDs, which often use 10 mA or less) you would need larger resistors (e.g., a 300 ohm one for that example green LED I mentioned above). But 20 mA is often a useful current, so 180 ohms is a good default (double that for SMD LEDs) if you don’t know your LED’s rating.
Now that’s the required resistance for a simple circuit, where a digital pin is configured as an output and connected to the anode (positive side of the LED) and the other end of the circuit connects to the Arduino ground. That’s well enough if you only need a couple of LEDs, but doesn’t work if you need a lot. I’ll get to some more complex configurations below that need different resistances because of the way the circuit is designed.
The most significant limit is going to be current. LEDs typically use 20 – 30 mA, although some can use over 50 mA. Surface-mount LEDs (SMD packaging) often use 10 mA or less. Which doesn’t sound like a lot if you have a 600 mA power supply connected to the Arduino, perhaps you could drive 60 lit SMD LEDs?
But the actual limits are much more stringent. Each output pin is limited to a maximum of 40 mA, meaning the Arduino can’t even drive some large white LEDs safely. Then the total power consumption of the Arduino is limited to 200 mA, and some of that is used to run the processor itself (typical maximum CPU current is 9 mA). Finally, pins on an Arduiono are related to groups of I/O ports on the chip, and these groups are typically limited to 100 mA per group (see the electrical characteristics section of the appropriate data sheet for specific details, and the schematic for the association of pin to I/O port; both are usually linked from the Arduino product page for the specific model of Arduino), in general this limits groups of pins to under 15 mA each if all are in use.
Don’t expect to light even 10 standard LEDs simultaneously off one normal Arduino. You can do more with higher resistance (current limiting). However an even better method is to use pulsed power to light different LEDs at different times and make it appear that more are “lit” simultaneously. This requires more complex programming, and a program error that causes too many LEDs to light and remain lit could even damage the Arduino, so work cautiously if you do this.
With pulsed power and sequential lighting of LEDs, you can probably light around 40 LEDs without getting in trouble (and more if you’re really careful or use low-current LEDs).
More LEDs – Multiplexing
The basic solution to doing more with less on the Arduino is “multiplexing”, and LEDs are no exception. This can get rather complicated through, and there are a number of issues to deal with to make this work.
Now if you want to control something really large, like a dot-matrix display, you may be better off using some external circuitry. Arduino has an example page describing use of a LED Driver chip if you want to go this route. One thing I don’t like about this is it takes time to signal the chip, and you have to use delays to ensure precise timing of that signal, so you lose something more than 560 microseconds each time you want to change which LEDs are lit. That may not seem like much, and in many cases it won’t be, but if you need to change them a lot or you’re doing other things that need time, it adds up. This solution I’ll describe below uses 12 microseconds of processing time once every 1,000 microseconds to drive twenty LEDs. My method could still use more time overall since you’re unlikely to change the state of the LEDs too often, but it’s time that’s evenly distributed, and that’s an important characteristic when you want the program to be off doing other things most of the time.
Persistence of Vision, or Not
Things like movies and television work by exploiting the fact that the brain remembers what it’s recently seen if there’s a short gap. This is called persistence of vision or “flicker fusion”. And if you look around the web, you’ll find references that say that as long as the gap between events is less than about 11 milliseconds, you can’t perceive it. In fact, it’s a rare person who can notice gaps even that long under intense scrutiny. As you’ll see in a bit, it’s not quite that simple, but the principle is correct. Film projectors use this to display a frame for a short period before blocking the light to advance the film; the brain fills in the gaps when the screen is dark, as long as there’s a new frame at least 16 times a second (i.e., every 62.5 milliseconds). At that rate, some flicker is noticeable (think about old silent movies and how they appear), and modern film uses 24 frames per second (41.7 milliseconds).
But a LED isn’t quite the same as a motion picture screen. For one thing, a movie has lots of dots on the screen, and they’re constantly changing color and intensity. A LED is a single dot of one brightness. It only makes sense that it would be easier to notice changes, and it is. You can trick the eye into seeing continuous light instead of flickering, but the numbers are different.
I modified the standard Arduino example program Blink to turn an external 1.5mm red LED on for a specific number of milliseconds (or microseconds) then off for a different number of milliseconds each time around the loop. I discovered several interesting things from this. First, the LED doesn’t need to be on for long. It gets dimmer at shorter durations, but even if it was lit for just 5 microseconds (not milliseconds) out of every 20 milliseconds I saw it as continuously lit. That’s just one part in 4,000 (I suspect it was lit longer, as the transistor probably can’t switch that fast and the diode probably glows for a short time after power is removed, but still it didn’t take much to appear lit).
The second thing is that it’s easier to see short gaps than short pulses of light. If I lit the LED for 100 milliseconds, and turned it off for just 4 milliseconds (not microseconds), I could see it flicker.
So what this means is that when structuring a program to deal with multiple LEDs, I need to make sure they’re on for much shorter times than they’re off, so that the viewer sees a continuous but dim light, rather than a bright but flickering one.
The other part of this is that if the delay between lit phases was much longer than 20 milliseconds, I could see flicker anyway (25 milliseconds was somewhat visible, 30 milliseconds was obvious). That agrees with some of what I read, which is that rates above about 50 – 60 Hz (17 msec to 20 msec maximum between pulses) were needed. That is not the whole story, however.
So what I need to do is ensure that roughly every 20 milliseconds each LED that’s lit is lit for as long as possible (to get maximum brightness), but that “as long as possible” can be quite short if I was willing to accept a relatively dim light. In theory I could light 4,000 LEDs this way, and use the power needed to drive just one. In truth it’s not that simple, as power is lost turning them on and off (switching power in the transistors). But still, this means that it is possible to drive lots of LEDs with the limited power available from an Arduino and structure things in such a way that different ones are on at different times (i.e., with multiplexing).
One way to drive LEDs like this, incidentally, would be to use PWM. But typically only 6 of the 14 digital pins on an Arduino are capable of PWM, and they’re tied to a small number of unique timers, one of which has to run at a specific standard rate in order for millis(), micros(), delay() and delayMicroseconds() to work properly. So instead I’ll use the time functions to do it myself, which gives me more pins and more flexibility.
But is ~20 milliseconds really the right interval to use? This should work fine for the human eye, but what if you’re filming your layout in operation?
A typical film camera operates at 24 frames per second (which for arcane technical reasons is actually 23.976 frames per second). This works out to 41.7 milliseconds. So each frame of video is taken ~42 milliseconds apart. But it doesn’t stay open the whole time. And if the LED doesn’t light up while its open, then it will be dark. Worse, because the LEDs and shutter cycles at different rates, over the long term (large fractions of a second) different ones will be caught by the shutter, causing the LEDs to look like they’re flickering, or even turning on and off slowly over time.
So clearly, the cycle time needs to fit within the speed of a typical camera shutter if you want the LEDs to look stable on video. But what is that? Well, for technical reasons this has historically been twice the speed of the frame rate. So for film, this works out to 20.8 milliseconds, and we would have just over 20 milliseconds to cycle through all of the LEDs. But video is more typically shot at 30 fps, and has frames lasting just 33 msec. And a lot of modern cameras will work at 60 fps, which is often rounded to a 1/125-second shutter. So to really be safe, I need to keep my cycle time under 8 milliseconds (for more on this, see my Musing on video and LEDs. That’s tighter than I thought it was going to be.
Even faster shutter speeds may be desirable to deal with motion blur. Someone really serious about video, using a high-end camcorder or DSLR that can shoot video with adjustable shutter speeds, might want to have LEDs cycling even more quickly so they could shoot video at a higher shutter speed (my new DSLR will do this). There’s a practical limit to this, as there’s only so much light available and faster shutters mean less light on the sensor. Still, a shutter speed of 1/250-second would leave just four milliseconds to cycle through the LEDs, and such a shutter speed would easily be possible. I don’t think I can allow for that; there’s just not enough time to get through “loop()” quickly enough. So I’ll aim for a hair under 8 msec, but I may revisit that decision if I can make things run quickly enough. And if I were designing an Arduino program to perform more specialized control (e.g., a simple signal driver), where I had less work to do overall, then I’d probably try to cycle the LEDs at a higher rate.
In any event, if you want to be sure your LEDs will look good on video, get through them in under 8 milliseconds. Depending on your video camera, 16 milliseconds may produce acceptable results, but don’t take longer than that. The eye won’t see a problem at 20 milliseconds, but a video camera will.
Multiplexing and Charlieplexing
Multiplexing in its simplest form arranges things in rows and columns, such that each object (LED) is active when both its row and column are selected, and not otherwise. This allows, for example, 8 control lines arranged as a 4×4 grid to control 16 LEDs, a two-fold multiplier. But there’s another technique, named Charlieplexing (after its inventor, Charlie Allen) that’s more complex, and allows N control lines to drive N collections of N-1 LEDs. With this, 8 lines could drive 56 LEDs (assuming sufficient power was available to light them all, which becomes an issue).
Charlieplexing depends on the fact that microcontroller output pins don’t have just two states, high and low, but actually three: output high, output low, and input, which in effect is neither on nor off. And it’s easily structured around clusters of LEDs that have a common anode or cathode wiring arrangement. This turns out to be quite handy for model railroad signals, as these are usually wired with all lights in a signal having a common wire on one side (typically anode for LEDs, although it could vary).
Also, while a signal might have two LEDs sharing an anode (for example), that doesn’t mean you’re limited to clusters of that size. Two signals could be wired together into one cluster of four LEDs. The limiting factor is going to be power: how many of those LEDs need to be lit, how many milliamps are they using, and what are the limits of the power supply (per pin or total). There are some issues to be aware of with this technique. They’re summarized quite well on this page, so I won’t bother to restate them here. But the circuit design given below, and the program to use with it, take these into account.
Charlieplexing LEDs with Arduino
First, I’m going to use two different colors of LED in this example, since I’m planning to use the circuit for controlling a set of red/green signals. Second, I need to be able to have more than one LED lit at a time, which the circuit can’t do, so I’ll use persistence of vision and blink the LEDs so that more than one appears on even though current is only flowing through a single LED at any given moment. Here’s my circuit plan for controlling twenty LEDs (five sets of four) with five Arduino pins. Using two-color signals, this is going to prove for up to ten signals (e.g., the LEDs associated with Rc11 and Rc12 in the diagram are one signal mast with a two-light head). This can easily be generalized to three-light signals, or more sets, or both, using more pins. The next step up would need seven pins to drive three two-color signals or two three-color signals per set, and seven sets (for 21 two-color signals or 14 three-color signal masts).
Notice that there are resistors on both sides of the LEDs. The RsN resistors are on the anode (positive) side, and serve to block current from the cathode (negative side) of one LED from recirculating into the anode of another set. This is necessary because an Arduino pin in LOW state isn’t quite at ground due to internal resistance, keeping the LED cathodes above ground. Without these, I had unintended LEDs that lit faintly (or sometimes not so faintly). I found 100 Ohms to be a good size for these, although this was probably underdriving the LEDs (with two LEDs lit, I could have had 40 mA flowing, which means I’d be dropping 4 V of the 5 V present; realistically much less current would flow and thus the effect would be less). I need to experiment with other size resistors and see if I can reduce these to 50 Ohms or less (while possibly increasing the ones on the cathode side).
Note: one significant difference in this diagram from normal charlieplexing diagrams is that it uses separate resistors on the high and low sides of the LEDs, rather than putting one resistor on each pin and sharing them. There is a reason for this. It has to do with variations in how many LEDs in a bank are lit, which we’ll cover further down the page. But for now, just take it as being worth the few extra cents that a few more resistors cost.
The resistors on the cathode side are there to provide each LED with its own resistance, as two dissimilar LEDs sharing an anode resistor that are both lit may light at different intensities if there’s nothing to prevent all or most of the current from using one of them. For my experiments, which were carried out with red and green LEDs with Vf of 3V and currents of 15 and 20 mA respectively, I found 68 Ohms to be a good size for these (but see the comments below). When I used the same circuit with a NJI International signal with SMD LEDs, it worked but was fairly dim, so I’ll need to experiment more to find good values for typical signals.
Note: I used Radio Shack 276-0026 (3mm low-intensity RED, 3 V, 15 mA) and 276-0022 (5mm green, 3V, 20 mA LEDs) for my testing if you want to exactly replicate the circuit. All resistors were 1/8 Watt (well, some were 1/4 W because I couldn’t find enough 1/8 W ones, but they only needed to be 1/8 W).
Still, it works. The software to drive them is a bit complex although conceptually quite simple, and in any case it meets my goal of running a large number of LEDs from a small number of pins without spending a long time communicating with an outboard controller. As noted above, my code used just 12 microseconds every 1,000 microseconds, so I can add it to other programs without having to be concerned with adding unexpected delays in time-sensitive processing. That’s important for the kinds of programs I’m likely to use this in.
It’s easier to show how this works than to explain the program, so I’ve constructed a sample sketch to drive the LEDs in the diagram above, which I used to test the behavior of the charlieplexed LEDs and my planned use of them, and that’s available (download it here) if you want to see it (as with all of my code, it’s public domain so you can use it to make your own programs).
My initial purpose in doing this is to drive signals, so let’s take a look and what that means for the circuit.
First, with the signals I’m using, I can safely assume that either red or green will be lit, but not both. That’s handy, as I can tighten up my loop to drive one signal per cycle instead of one LED per cycle, making my cycles twice as fast with still limiting current to that of one LED. There are some signals that light two or more LEDs on a signal head (Japanese signals) or even three (position signals, used in both Japan and the U.S.), so as a general solution that won’t always be possible. In those cases, you may need to settle for driving multiple LEDs simultaneously, which will work as long as you keep the total current under the 40 mA limit of an Arduino pin.
Second, I’m going to be using some specific signals, either New Jersey International #2002 or #2004, or Tomar N-857. The NJI signals are marginally less expensive, so let’s use these for this example. Because the signals aren’t documented as to the LEDs forward voltage or maximum current, we first need to determine that. I can estimate that these are likely around 10 mA because they’re SMD LEDs (there are high-current SMD LEDs that draw up to 30 mA though) and because they’re supplied with a 1,000 Ohm resistor for 12V use (which implies a LED with 10 mA current and Vf of 2 volts).
If we assume the LED will have Vf=1.6 volts, and a current of 10 mA, then to run it safely on 5V I need to use a (5 – 1.6) / 0.01 = 340 Ohm resistor or larger. So the first thing I do is stick a signal on a breadboard with a 390 Ohm resistor (what I had handy) and connect one of its LEDs to the +5 and ground pins on my Arduino with that resistor in line. The LED lights (good sign), and I connect my multimeter across the two legs of the LED I’ve wired up, measuring the DC voltage across it as 2.00 Volts. Now Vf will vary slightly with current, but it generally stays close to one voltage, so I can estimate my LEDs at Vf=2.0 V. Next I modify the circuit slightly to measure current through the LED with my meter (keeping the same resistor), and see a current of 7.4 mA. This is a good first approximation, but let’s firm it up a bit.
Recalculating (still assuming 10 mA, my required resistance is probably (5 – 2) / 0.01 = 300 Ohms. I wire up a pair of 150 Ohm resistors in series and check again, the reading now is 9.6 mA. That pretty much confirms that I guessed correctly. Why isn’t it 10 mA? Well, first the Arduino doesn’t put out 5.0 volts. According to my meter, it’s 4.92 today (it can vary slightly with the supply voltage, which can vary with the line voltage). Second, my resistors aren’t exact (although they are 5% ones), and actually total 296.5 volts, and (4.92 – 2.0) / 296.5 = 9.85 mA.
But since we don’t need to be exact, this says the my signal LEDs (I tested both red and green and they were identical) have Vf=2.0 V and I=0.01 A. And that means that on a nominally 5 Volt Arduino output, I need about (5 – 2.0) / 0.01 = 300 Ohms as previously calculated.
Now going back to my driver circuit, how do I divide that between the RsN and RcNN resistors? It’s not as simple as half each, because while the current through RcNN is 10 mA, the current through RsN depends on how many LEDs in the bank are simultaneously lit. If on one was, both would have 10 mA. But if, as planned, I light one LED per signal, that means my bank of two signals will have two LEDs lit, and current through RsN will be 20 mA.
I saw in my earlier experiments that 100 Ohms was a good size for RsN. I haven’t actually tried smaller ones, but what happens if I use that size with a current of 20 mA? It drops 100 x 0.02 = 2 Volts, dispersing 2 x 0.02 = 40 mW, so I can safely use a 1/8 W (125 mW) resistor if I want. That still leaves me with 1.0 volt to drop to take 5V down to 2.0 V. With a current of 10 mA through RcNN that means I need 1.0 / 0.01 = 100 ohms on the output side as well (also a 1/8 W resistor). That’s nicely symmetric.
But is symmetric good? Perhaps I’d be better off making the one between the high pin and the LED larger, just to make the path to ground even more preferable (in truth, it shouldn’t matter, and symmetric ought to work too). A bit of calculation shows that 120 ohms will work on the high side, with 91 on the low side. Total voltage drop is 3.31 volts, slightly more than the 3 I want to drop, but that’s good, as it provides a safety margin for variation in the actual resistance and most of the time it makes the current through the LED lower than maximum, which is good for the lifespan of the LED. It also would protect them if for some reason the Arduino decides to put out 5.1 instead of 4.9 volts.
Note: 91 ohms is a 5% size, and might be harder to find than 100, so 100 + 100 will work if you can’t do 120 + 91.
But wait, what happens if I’m using an odd number of signals (I’m not for my Tram project, but what if I was)? That means that one bank will have one signal in it, rather than two. And for that bank, two 100 Ohm resistors aren’t enough. One of them (either) needs to be raised to at least 200 Ohms (or 220 Ohms, which is the more easily-found size, and I think a better choice). That would also be what I’d need to use if I didn’t make the code take advantage of the wiring; if I only light one LED in a set at any given instant, I need the larger resistors (220 Ohms), but if two are simultaneously lit, then I can use the smaller ones (120 Ohms).
If I raise the high side resistor to 220 ohms and drop the low side to 91 ohms, I get a voltage drop with one LED of 3.1 volts. With two I’d appear to get a drop of 5.3 volts, which can’t happen with a 5-volt supply, so what really happens is that the current drops (perhaps enough that the LED won’t light, or perhaps just lighting it dimly).
So this is what I’d use with the NJ signals, which as noted draw 10 mA with a Vf of 2.0 volts, meaning that I have to lose 3V from the Arduino’s 5V supply in the resistors. If I used different LEDs (e.g., for HO I might have 20 mA non-SMD LEDs with Vf around 1.8 Volts, meaning I’d need to drop more volts, but would use smaller resistors due to the higher current). Or I might have the LEDs I found in my local Radio Shack, which have Vf of 3 volts and currents of 15 and 20 mA (which makes things a bit more complex; I used 100 ohms on the high side and 67 on the low side with those, but that was actually larger than it needed to be.