Strangeness with analogWrite and LEDs

Hi there,

I'm new to Arduino, this is my first post here. I don't know if my problem is hardware or software but I thought sanity-checking the software would be a good start.

I've got 3 LEDs, a clear 5mm red one, clear 5mm green and clear 5mm blue, connected to pins 9, 10 and 11 of an Arduino Uno, each of them with a 240 ohm resistor. I'm not great at figuring out resistors but from what I've read in the books and online tutorials I've seen (which tend to recommend 270 ohms - I don't have any of those), 240 should be fine. Anyway, as you can guess from the setup, I want to fade the LEDs in and out in order to cycle through all of the colours in the rainbow.

The problem I'm having is that although I'd expect a linear fade up and down in the LEDs, that's not what I'm seeing. The LEDs fade up quite sharply from off to something that looks full brightness with relatively small values, then stay bright for most of the fade up and the fade back down, finally ramping steeply down to off in the lower values again. Oddly, the behaviour seems to be different for each pin. Pin 9 is the least-afflicted and has the smoothest fade up and down, pin 10 fades up and down quite quickly, and pin 11 fades up quickly but fades down pretty smoothly. I've swapped the LEDs around and found that the issue seems to be with the pins rather than the LEDs.

Here's my code. Any help would be much appreciated.

// Pins
const int redPin = 9;       
const int greenPin = 10;
const int bluePin = 11;

// Brightness values
int red = 0; 
int green = 0;
int blue = 0;


int zone = 0;        // Used to work out which LEDs should be on, off, or ramping up or down
int phase = 0;      // Used to ramp brightnesses up or down (ranges between 0 - 255)
int fadeSpeed = 1;  // amount phase is incremented by each update

void UpdateLedColours()
{
   phase += fadeSpeed;
   
   if(phase > 255)
   {
     phase = 0;
     zone += 1;
     
     if(zone > 5)
     {
       zone = 0;
     }
   }
     
  switch(zone)
  {
    case 0:
      red = 255;
      green = phase;
      blue = 0;
      break;
    case 1:
      red = 255 - phase;
      green = 255;
      blue = 0;
      break;
  case 2:
      red = 0;
      green = 255;
      blue = phase;
    break;
  case 3:
      red = 0;
      green = 255 - phase;
      blue = 255;
      break;
  case 4:
      red = phase;
      green = 0;
      blue = 255;
      break;
  case 5:
      red = 255;
      green = 0;
      blue = 255 - phase;
      break; 
  }
}

void setup()
{
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(bluePin, OUTPUT);
}


void loop()
{
    UpdateLedColours();

    analogWrite(redPin, red);
    analogWrite(greenPin, green); 
    analogWrite(bluePin, blue); 
          
    delay(30);  
}

I've swapped the LEDs around and found that the issue seems to be with the pins rather than the LEDs.

I would have thought the symptom would follow the leds rather then the pins. Either way, setting current level for different color leds is not as simple as it might seem at first.

First a formula for determining resistor value for a specific current value, say 20ma.

R (in ohms) = (source voltage - led forward voltage drop) / current in amps. The first thing to know is that different color leds have pretty significant different forward voltage drop. So a red led typically has a 1.5 Vf rating so R= (5-1.5) / .02 = 175 ohms. A blue led has, I think, a 3.5v Vf rating so R = (5-3.5) / .02 = 75 ohms. So you see if you want to drive a red and blue led at the same 20ma current they require quite different values for their series limiting resistor. Another issue is that different leds have different efficiency ratings so don't all put out the same amplitude of light at the same specific current. Yet another issues is that led light output is not very linear with current. That is many leds running at 10ma will not seem very much brighter if adjusted up to 20ma, while changing from say 1 ma to 10ma will see a much wider range of brightness change.

So you can see you have challenges ahead. When you send a analogWrite value of 255 (full on) to your three different leds, you will have drastic differences due to the use of a same size resistor for leds with different values of Vf, and you have no real idea I suspect of the current to light efficiency value for the three different color led.

So you might want to experiment a little. What I would do is calculate the correct resistor for each color using their specific Vf rating and setting the current level to 10ma. Then run your sketch and see if you don't get a wider range of brightness control. After that if you find all have good control but one color is hotter then the other two then just raise the resistance some for that one color. Using 10 turn 1k ohm trim pots can make the experiment go a lot quicker and after you get the results you want just measure the pots adjusted value and you then can obtain fixed resistors of the same or closest available value.

Sound like a plan?

Lefty

The eye's brightness response is roughly logarithmic - this is probably what you are seeing and interpreting as non-linearity in the Arduino.

In other (PIC chip) projects, I've had much better luck doing pulse-width modulation (PWM) on the LED to achieve different brightnesses. Since LEDs are diodes (switches), they pretty much turn full-on or full-off, depending on the voltage applied.

For example, instead of writing analog values to the LED output pins, write only HIGH or LOW. If you wanted an LED to have full brightness, write HIGH every time loop() is called. If you want 50% brightness instead, write HIGH every other time loop() is called, and LOW on the other times loop() is called (HIGH, LOW, HIGH, LOW, etc.).

I'm an Arduino newbie, but I believe some of the output pins are PWM-capable: that is, you can program the Arduino to pulse the pin half the time, or 1/4 of the time, for example.

I'm an Arduino newbie, but I believe some of the output pins are PWM-capable: that is, you can program the Arduino to pulse the pin half the time, or 1/4 of the time, for example.

I think you may be a little confused about arduino command names. The OP's posted program uses analogWrite() statements to drive the leds.

In the Arduino world analogWrite means PWM output, yes I know that doesn't make sense and is ass backwards to the rest of the known civilized world, and even though I asked them nicely to rename it to pwmWrite() command, they said shut up and don't speak unless asked to (not really, they are nice people, just...set in their ways.) ;D

Lefty

Ah, my newbie-ness is revealed. Sorry for the confusion, and thanks for the info.