RGB multicolor LED controlled by Arduino sensed external voltage

Heya all! In the name of limitless creativity (hail Arduino!), I would like to upgrade my Bluetooth speaker project a little bit further. I want Arduino to control the multicolour LED like this:

Battery charging (highest voltage) - pulsating Blue LED Full battery - Green colour of LED Low battery - pulsating Red colour of LED

anywhere in between Full and Low: gradual change from green into yellow to red.

Now I think the idea is fantastic, but how to do this is beyond what my brain can pull off.

Any ideas? I am asking here more about programming side of things than anything else..

Big thanks!

I am asking here more about programming side of things than anything else..

Tell us about the hardware side of things, it sounds like you have all that figured out. Can you show us a schematic and include clickable links to details of the important components?

Hi Paul,

I’m not sure why HW side of thing is that important as you sad - I have it figured out (I think). Anyways, here’s the diagram of the idea. So you can visualize better. You can pretty much ignore all the other components except the leds, because all those other componens have nothing to do with leds. And the circuit works fine on the breadboard, so there is no need for improvement. What’s important is:

  • I am aware of missing resistors to LEDs. Will be added.
  • The voltage sensing pin for now is pin15 on Arduino - can be changed to any other pin, really.
  • What is also not important to me is what goes to which pin. I mean I am aware that perhaps pin15 is the worst idea for voltage sensing. Or perhaps LED output pins should be analog and not digital. I will figure it out and It’s easy to change that. It’s really just a quick sketch, so take it as that. Cheers.

I'm not sure why HW side of thing is that important as you sad

Because without knowing the hardware it is impossible to be able to understand the software.
Your image

I mean I am aware that perhaps pin15 is the worst idea for voltage sensing.

So why do it? That is a digital pin and you will only ever get a HIGH or LOW reading.

I don’t understand the switch, it seems like this is driving a relay but you have no coil. What is that part of the circuit doing?
Where is your Bluetooth device in all this?

Thank you for displaying the image correctly Mike. Like I said, other components are irrelevant to the LED issue and it is really just distracting from the problem. But to satisfy your curiosity: It is Arduino controlled transistor which in turn switches MOSFET which in turn keeps Arduino circuit and other peripheals (like the BT module - not on the pic) powered on. This specific setup has a nice advantage - you can power on/power off all of the peripheals with one press of the tactile button (the two buttons on the diagram are one button in fact switching between the lines) and also the power consumption of everything in the OFF state is incredibly small (around 1uA which is only a current leaking through MOSFET). But like I have said. This is irrelevant to the LED issue. So let me get to the point:

Arduino senses some external voltage value on some analog pin. when battery voltage drops below full value (known) the RGB LED start to fade from fully green (Red 0, Green 255, Blue 0) to yellow at 50% of charge (Red 255, Green 255, Blue 0) all the way down to low battery (Red 255, Green 0, Blue 0). Here the Red starts pulsating (pwm function?).

I need to come up with some mathematical function of some sorts that will arduino understand. Also, I need a routine that will switch from red solid color to pulsating solid color at low battery voltage.

I hope this is more understandable now.

A little picture:

Battery reference voltage --------->Arduino-------->RedLED | |__>GreenLED |_______>BlueLED

It's really this simple

I have found this:

myColor = new Color(2.0f * x, 2.0f * (1 - x), 0);

source: Algorithm: How do I fade from Red to Green via Yellow using RGB values?

After some fiddling to suit the above to Arduino code and to my specific setup (14.8V Li-ion Battery, where I want full red a bit above 10V - before Li-ion protection circuit cuts power off to prevent batteries from damage and full green just above 14.5V), I came with this. It works in the emulator/simulator, I’ll try tomorrow on the real thing.

2 notes:

  1. yellow color could look prettier, but it’s not ugly
  2. it’s barely noticeable, but the RGB LED in the emulator/simulator flickers. perhaps a cap would solve this?

Anyways, here’s the code and maybe this will help someone too.

void setup()
  pinMode(14, INPUT);

void loop()
int voltage = (120000 / analogRead(14));
int Red = (2 * voltage);
int Green = ((2 * (2 - voltage)));
analogWrite(6, Red );
analogWrite(3, Green );        

The blue led is not used. No need to add a resistor for that or use a Nano pin.

Fading between colours is done by using PWM (not flashing). Pin 7 does not have that capability. Pins 3 and 5 do.

From fully charged down to threshold of low battery, green led fades from 255 to 0, and red led fades from 0 to 255. You can use the map() function for those, provided you use the raw (integer) analog read values, not a voltage calculated as a float.

Below threshold of low battery, just use millis() to time flashing of the red led. digitalWrite(redLedPin, bitRead(millis(), 9)); would make that easy.

Thanks for an answer Paul.

Interesting idea with the map() function. Could make things a bit more accurate and clean. Alas, I have melted my Arduino today, when connected Vin into GND terminal and vice versa by accident on the breadboard, so I have to wait for the new one to arrive. One would wonder how much heat such a little board can produce. Plug in two of them this way, put a slice of a bread in between and you have made yourself a genuine Arduino toaster! :)

ardy23: a genuine Arduino toaster! :)

The toast would not smell very nice, I think.

To keep your code simple, you do not actually need to calculate the voltage at all. You just need to know the analogRead() values at full charge and low battery threshold. Then you can simply write:

#define BATTPIN 14
#define FULLYCHARGED 950
#define LOWBATTERY 650
#define REDLEDPIN 6

void setup()
  pinMode(BATTPIN, INPUT);

void loop()
  int reading = analogRead(BATTPIN);
  if (reading > LOWBATTERY)
    int red = map(reading, FULLYCHARGED, LOWBATTERY, 0, 255);
    int green = 255 - red;
    analogWrite(REDLEDPIN, red);
    analogWrite(GREENLEDPIN, green);
    digitalWrite(REDLEDPIN, bitRead(millis(), 9));
    digitalWrite(GREENLEDPIN, LOW);