3

schematic

simulate this circuit – Schematic created using CircuitLab

Its a simple project. I am trying to drive 3 RGB LEDs using Arduino Nano. Since Arduino Nano does not have 9 PWM pins, the only solution I can think of by multiplexing them. I have try multiplexing 12 7-segments driven by atmega16, the results was satisfying. Is it possible to do PWM multiplexing on Arduino Nano?
So far, here is what I have done:

const int R=9, G=10, B=11, M1=5, M2=6, M3=7;

//I use pin 5,6,7 as selector since they are on same PORT (PORTD)

void setup()
{
    pinMode (R,OUTPUT);
    pinMode (G,OUTPUT);
    pinMode (B,OUTPUT);

    pinMode (M1,OUTPUT);
    pinMode (M2,OUTPUT);
    pinMode (M3,OUTPUT);
}

void led(int r, int g, int b)
{
    analogWrite(R,255-r);
    analogWrite(G,255-g);
    analogWrite(B,255-b);
}

void loop()
{
    for(int i=0; i<256; i++)
    {
        led(0,0,i);
        __asm__("nop\n\t");     //one clock cycle delay
        PORTD = B10000000;      //select LED-1

        led(0,i,0);
        __asm__("nop\n\t");     //one clock cycle delay
        PORTD = B01000000;      //select LED-2

        led(i,0,0);
        __asm__("nop\n\t");     //one clock cycle delay
        PORTD = B00100000;      //select LED-3
    }

    for(int i=256; i>0; i--)
    {
        led(0,0,i);
        __asm__("nop\n\t");     //one clock cycle delay
        PORTD = B10000000;      //select LED-1

        led(0,i,0);
        __asm__("nop\n\t");     //one clock cycle delay
        PORTD = B01000000;      //select LED-2

        led(i,0,0);
        __asm__("nop\n\t");     //one clock cycle delay
        PORTD = B00100000;      //select LED-3
    }

}    

But still, this does not work. The result is all the led turned on, with 'a little bit' different color, mainly white with a little addition of another color (while it supposed to be contrast, R, G and B for each LED), and its blinking. The blink is very short, but still, its annoying. One possibility I can think of my code still not optimum.
Someone had an idea?

EDIT
I fixed the diagram, I hope the diagram does not make any misunderstandings. As the suggestion from @jwpat7, I forget to inform that the led still error even if there is just one for-loop.
I am using __asm__("nop\n\t") as delay substitution because "theoretically", 1 clock cycle from 16mHz clock is shorter than 1 microseconds. (correct me if I am wrong, but I think its about 62.5 ns)

Thanks in advance

2

I've copied and slightly modified your diagram, as below. Note the added connections of R1, R3 cathodes to that of R2, and similarly for green and blue LEDs.

schematic

simulate this circuit – Schematic created using CircuitLab

I'm supposing that unlike the original diagram, this one represents what you actually wired up.

A basic problem with your program is that it spends most of its time changing PWM settings, without letting PWM cycles actually occur. To see this, do some timing analysis on the code.

The code repeatedly executes sections of code like the following:

    led(0,i,0);
    __asm__("nop\n\t");     //one clock cycle delay
    PORTD = B01000000;      //select LED-2

The call to led() results in three calls to analogWrite(). As seen by perusing at garretlab the source code for analogWrite(), digitalWrite(), and pinMode(), each of those analogWrite() calls takes a few handfuls of cycles – let's say 50 at most – so the three lines of code shown above take less than a dozen microseconds to execute. Thus each of the two for loops takes less than 10 milliseconds to complete, causing the loop() routine to run more than 50 times per second. Persistence of vision will result in observers just seeing the average level of light, rather than any ramping up or down.

To fix the ramps-not-visible problem, determine how long you want each ramp up or down to take, and add corresponding delays in the for loops. For example, suppose you want to go up in one second and down in two. As 1000000 μs /256 passes ≈ 3906 μs per pass, you could add delayMicroseconds(3906-36) at the end of the first for loop, and delayMicroseconds(2*3906-36) at the end of the other, to achieve the specified rates. (The -36 term accounts for time used by other code in each loop. It's probably an overestimate and perhaps should be left out.)

However, the previous paragraph doesn't take multiplexing effects into account. You may, of course, want a different PWM level for each of the nine different LED chips. It probably is practical to just directly use as many PWM outputs as you have available, and emulate PWM in software for any remaining LEDs.

For more information about software PWM, see some articles that google turns up, including:
Arduino PWM pin vs digital pin PWM simulation on electronics.stackexchange, which presents basic ideas and some pros and cons of software-based PWM
AnyPWM Revisited, a blog article by Nick Borko about PWMing 12 LEDs using software PWM
PWMAllPins, an arduino.cc article apparently by Paul Badger or Seth Wolf about PWMing 11 LEDs using software PWM

Generally, software PWM hogs computing cycles and can be difficult to coordinate with other calculations. But if PWM control is the only significant task a processor is handling, software PWM can be an economical way to produce extra PWM pins.

  • Thanks jwpat, I did not notice the mistake on diagram before. I edited my original question. "emulate PWM in software", sounds interesting, can you explain more? – dhimaspw Nov 11 '16 at 6:10
  • @dpw, I added some links that help with the software PWM concept. – James Waldby - jwpat7 Nov 11 '16 at 8:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.