Design News is part of the Informa Markets Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.

Controlling WS2812 Tricolor LEDs (aka NeoPixels), Part 3

Image courtesy of Clive "Max" Maxfield LEDs max 0028 featured image balls and leds
A look at pulse-width modulation and how it controls the brightness and color of LEDs.

Hi there, and welcome to Part 3 of this soon-to-be-heralded mega-mini-series. In Part 1, we discussed the first vacuum tube diodes, moved on to their solid-state (semiconductor) descendants, and then progressed to their light-emitting cousins. In Part 2, we introduced the concepts of forward voltage drop (VF) and maximum forward current (IF), current-limiting resistors, and different ways to control discrete (individually packaged) LEDs using switches and microcontrollers (MCUs). Now it’s time to hold onto our hats because things are about to get exciting—only thrill-seekers should proceed beyond this point!

As we discussed in my previous column, and as illustrated in the upper part of the diagram below, one very common scenario is to connect the LED’s anode terminal to one of the microcontroller’s digital outputs and to connect its cathode to ground. In this case, driving the pin HIGH (let’s assume 5V) will turn the LED on, while driving the pin LOW (0V) will turn it off because there will be no electrical potential across its terminals.

Image courtesy of Clive "Max" MaxfieldLEDs max-0028-fig-01.png

Two ways to control a LED with a microcontroller.

An alternative arrangement, as illustrated in the lower part of the diagram above, is to connect the LED’s cathode terminal to one of the microcontroller’s digital outputs and to connect its anode to the positive power supply (assume 5V). In this case, driving the pin HIGH will turn the LED off, while driving the pin LOW (i.e., 0V) will turn it on.

The reason we are revisiting this topic here is that there’s a third way in which we can use the microcontroller to drive the LED, which is to use two of its pins. Just for giggles and grins, let’s assume we have two LEDs, one red and one yellow, both having the same forward voltage drop. Let’s further assume that we wish to have only one (or none) of these LEDs on at any particular time; that is, we never wish to have them both on together. And, just to tie one of our hands behind our backs (metaphorically speaking), let’s say that (a) we have only one current-limiting resistor and (b) the boss wants to see something working PDQ (“pretty darned quick”), as my dear old mom used to say. Taking all of this into account, we might come up with something like the following:

Image courtesy of Clive "Max" MaxfieldLEDs max-0028-fig-02.png

Another way to control LEDs with a microcontroller.

Remember that a LED will conduct electricity in only one direction, and that it will emit light only when it’s conducting. Thus, driving one of the microcontroller’s pins HIGH and the other LOW will light one of the LEDs while turning the other off. If both of the microcontroller’s pins are HIGH or LOW, then both LEDs will be off. Pretty nifty, eh?

Now, suppose we decide that we want to control the brightness of a LED. It is possible to do this by varying its supply voltage and current but—in addition to being complicated—the term “linear” is not one that we would apply to the result. A better approach is to turn the LED on and off very quickly using a technique known as pulse-width modulation (PWM).

Microcontrollers almost invariably include hard PWM functions associated with a selection of their pins. (By “hard” we mean these functions are implemented in the silicon, as opposed to realizing them in software in a process known as “bit banging.”) Different microcontroller PWMs have different numbers of bits. In the case of an Arduino Uno, for example, the PWMs are each 8-bits in size, which means they can represent 2^8 = 256 different values numbered from 0 to 255.

PWM finds all sorts of applications of which controlling the brightness of LEDs is only one. The way to visualize this is as an endless string of cycles, where each cycle is divided into 256 “time slices.” In the case of an Arduino, we use the analogWrite() command, which accepts two parameters: the first is the pin to be controlled, while the second is the PWM value ranging from 0 to 255.

Image courtesy of Clive "Max" MaxfieldLEDs max-0028-fig-03.png

Using PWM to control the brightness of a LED.

The term “duty cycle” (aka “power cycle”) refers to the ratio of time a circuit is on compared with the time that circuit is off. This ratio is typically expressed as the percentage of on-time. In the case of our LED, a PWM value of 0 corresponds to a duty cycle of 0%, which means the LED is fully off. A PWM value of 85 corresponds to a duty cycle of 33%, which means the LED is on for 1/3 of the time. A PWM value of 170 corresponds to a duty cycle of 66%, which means the LED is on for 2/3 of the time. And a PWM value of 255 corresponds to a duty cycle of 100%, which means the LED is fully on.

It's important to realize that the cycle time is fast in the grand scheme of things. Depending on the microcontroller, the frequency of its PWM signals will be hundreds or thousands of hertz (cycles per second). This means that our biological eyes don’t perceive any flickering because the LED is turning on and off so quickly.

It’s possible to purchase a variety of bicolor (two-color) LEDs, but things really start to get fun when we move to tricolor (three-color) devices containing red, green, and blue (RGB) sub-LEDs.

Image courtesy of Clive "Max" MaxfieldLEDs max-0028-fig-04.png

A common cathode tricolor LED.

The device illustrated above employs a common cathode, but common anode versions are also available. This type of tricolor LED will require three of our microcontroller’s pins to drive the three anodes, and each anode will require its own current-limiting resistor (these may need to be different values; check the datasheet for the forward voltage drops of each of the sub-LEDs).

When you were a kid playing at painting, your teachers told you that there are three primary colors: red, yellow, and blue (RYB). They may have mentioned that the reason these three hues are called “primary” is because they cannot be made with mixtures of other pigments. They will also have demonstrated how mixing red and yellow gives orange, mixing yellow and blue gives green, and so forth.

The way to think about this is that paints and pigments are “subtractive.” If you illuminate them with white light, which is composed of all the visible frequencies, they absorb some of these frequencies (subtracting them from the white light) while reflecting others, and it’s the reflected frequencies that we see. When we mix multiple pigments, they each subtract their own frequencies, and what we see is what’s left over. If we mix all of the subtractive primary colors together, they absorb all of the frequencies, and we end up with black.

In fact, any group of three (or more) colors can be used to define a “color space.” Printers use cyan, magenta, and yellow (CMY). If we mix all of these together, we do get black, but it’s a sort of “muddy” black, so printers also use a cunningly concocted crisp black pigment, which they abbreviate as ‘K’ (we can’t use ‘B’ because that could be confused with ‘B’ for blue). This is why we talk about a “CMYK” color palette in the context of printing.

Image courtesy of Clive "Max" MaxfieldLEDs max-0028-fig-05.png

Primary colors.

By comparison, light is “additive,” which means that each new color adds something to the mix and adding all of the RGB light primaries results in white light. The way I like to visualize this is as shown above. In the case of paints and pigments, we start with a white space and subtract color components from this space. Contrariwise, in the case of light, I imagine starting in a dark room and then turning on different colored spotlights.

If you look closely at your color computer monitor—possibly with the aid of a magnifying glass—you’ll see that each pixel (“picture element”) is composed of RGB sub-pixels. Varying the brightness of the sub-pixels gives us the different colors. Without the aid of magnification, our eyes don’t have sufficient resolution to see the individual sub-pixels, so—as far as we’re concerned—all of their light mixes together. Exactly the same thing happens with our tricolor LED. Although the package itself is rather large, the sub-LEDs inside are mounted really close together, which means we perceive their light as being mixed together.

Take a look at the image below. If all we can do is turn each LED hard on or off, then this gives us 2^3 = 8 possible color combinations (including all off = black). By comparison, if we can use 8-bit PWMs to control the brightness of each sub-LED, then this gives us 2^8 x 2^8 x 2^8 = 2^24 = 16,777,216 possible color combinations, which is one of the reasons today’s computer screens and televisions look so awesome.

Image courtesy of Clive "Max" MaxfieldLEDs max-0028-fig-06.png

RGB tricolor LED color combos.

Once again, I’m afraid this is all we have time for in this column. However, we’ve now laid the foundation for what is to come. In my next column, we will finally start to wrestle with WS2812 Tricolor LEDs (aka NeoPixels). Until that frabjous day, as always, I welcome your comments, questions, and suggestions.

Hide comments


  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.