Introduction: Software Driver to Control 2-pin Bi-Color LEDs

I had a project platform with 8 LEDs and wanted some different colors based on the game/functionality that was implemented. There is the possibility of using 3-pin R-G or 4-pin RGB LEDS, but I wanted to use only one DIO (Digital Input/Output) pin per LED not 2 or 3 (requiring 16 or 24 DIO pins).

With some carefully selected design elements I was able to achieve the color qualities as well as a range of brightness levels I desired, on an individual LED basis. This was accomplished with just one DIO per LED plus one common R-G driver line. The implementation presented here is in the form of an Arduino sketch.

Step 1: How It's Done

I decided to implement the color (Red-Green balance) via time slices within a millisecond being divided up between red and green illuminations. To do this I created an Interrupt Service Routine which runs 10 times per millisecond. In which the common "LED_VCC" is toggled between HIGH and LOW. Each LED can be assigned a color which then determines how many of the 5 time slices for Red are energized and how many for Green (see the 'RG_lvls' array).

For brightness implementation standard Pulse-Width-Modulation seems obvious, but due to color implementation the assigned DIO for an LED has a complex behavior not compatible with the built in PWM functionality. I accomplish various brightness levels in the greater than one millisecond time domain, with an appropriately driven activation duty cycle which can go from 0 to 16 msecs out of each 16 msec period. This results in a brightness refresh rate of > 60Hz, such that no flicker should be detected.

The LED's color is controlled by the value 1-8 in the global array:  LED_Color[ ]

The LED's brightness is controlled by the value 1-16 in the global array:  LED_Lvl[ ]

Step 2: The Software Driver Implementation

A straight forward coding of this worked, yet there were a couple of issues.

1. There is a race condition when trying to switch the state of both pins of an LED at the same time. This caused color leakage skewing the colors and prevented a pure Red or Green.

To resolve this I had to set the LED DIO pins to INPUT to effectively have a high impedance during the transition. Below shows the related code from the biColor Driver software in bi_Color.h.

  for (int led=1; led<=nleds; led++) {
    pinMode(lites[led-1], INPUT);  // set LED pins to high-Z during transition
  }

...

ledPin = lites[led-1];
    if (rgOn) {    // pin for this LED is an OUTPUT only when it needs to conduct current
      pinMode(ledPin, OUTPUT);
      digitalWrite(ledPin, !RedTime);  // LED leads must be opposite polarity to energize
    }

2. The Green diode was too powerful compared to the Red.

This makes realizing other colors (eg: Orange, Yellow, yel-Green) too hard, as there is only one resistor in line with the LED and only one control DIO, you can't balance their outputs. I found some LEDs with R:G illumination strength ratios being 1:4 and some about 1:2.

To resolve this I used those with ~1:2 ratio and doubled the Red time slices to effectively balance their brilliance. So with these LEDs I use 15 time slices per millisecond allocating 10 of them to Red illumination (see diagram above). BTW: I used 220 Ohm resistors to get the light output I desired. Use frosted or milky LEDs!

Step 3: User Requirements

In the development hardware platform used here to showcase the utilization of 2-pin bi-color LEDs I used a Waveshare RP-2040-Zero MCU. The only code that is specific for it is the interrupt routine setup. If you are using a different MCU that code would need to change appropriately. 

Further, you could be using any number of buttons and LEDs (two buttons are needed for this demo code).

All you need for your project is the bi_Color.h file.

Simply change the pin value assignments in the "LED Hardware Configuration" section per your configuration.

In your project code file you'll need to include the .h and from your setup code call "init_usTimer_ISR".

#include "bi_Color.h"  // uSecs_ISR and biColor LED Driver support

...

void setup() {

  ...

  init_usTimer_ISR();

  ...


Naturally your application code would differ according to your needs. Use the "biColor_Parade()" function in the bi_Color.ino file as an example.


Related hardware:

  • One or more 2-pin biColor LEDs. Strongly recommended 3mm "Red Green520nm Milky LEDs". I have not tested any 5mm ones.
  • One current limiting resistor per LED. (perhaps 220 Ohm)

Step 4: Bi-Color LED Operational Demo

Step 5: Follow Up

In the not too distant future I will make a version of the STEM GAME Platform utilizing these 2-pin bi color LEDs, along with an Instructable to go with it.