CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Multiplexing LEDs
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
test153



Joined: 09 Feb 2009
Posts: 28

View user's profile Send private message

Multiplexing LEDs
PostPosted: Thu Mar 05, 2009 2:41 pm     Reply with quote

How do I multiplex LEDs? I have been trying to find a solution on my own for quite some time, since I haven't come up with a good one i turn to you.

From what I understand one would have to use some kind of timer and update every LED 50 times a second to avoid flickering. Below is the circuit I'm using. The PIC I'm using is 12f629.

Sydney



Joined: 13 Feb 2009
Posts: 71

View user's profile Send private message

PostPosted: Thu Mar 05, 2009 2:57 pm     Reply with quote

It looks like that would have to be done in 4 cycles, with 3 leds controllable in each cycle.

GP0 HIGH
GP1 FLOAT //D2 D6 D10 controllable

GP0 LOW
GP1 FLOAT //D1 D5 D9 controllable

GP0 FLOAT
GP1 HIGH //D4 D8 D12 controllable

GP0 FLOAT
GP1 LOW //D3 D7 D11 controllable
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Mar 05, 2009 3:04 pm     Reply with quote

Appnote on multiplexing LEDs:
http://ww1.microchip.com/downloads/en/AppNotes/00234a.pdf

Found with this search string at Google:
Quote:
site:microchip.com multiplexing LEDs
test153



Joined: 09 Feb 2009
Posts: 28

View user's profile Send private message

PostPosted: Thu Mar 05, 2009 3:31 pm     Reply with quote

Floating outputs is a nice approach I haven't tried, will indeed simplify the code. Thanks.

PCM programmer wrote:
Appnote on multiplexing LEDs:
http://ww1.microchip.com/downloads/en/AppNotes/00234a.pdf

Found with this search string at Google:
Quote:
site:microchip.com multiplexing LEDs


This appnote is a good one but it doesn't provide a programing example, appnote TB029 is a good one too. I have read everything I could find on that topic unfortunately I hit a dead end mostly due to my programing skills in PIC C.

Correct me if I'm wrong but I think I need a timer. So I need to use "setup_timer_0( )" right? and if so how do I set it up?
Sydney



Joined: 13 Feb 2009
Posts: 71

View user's profile Send private message

PostPosted: Thu Mar 05, 2009 3:48 pm     Reply with quote

Start simple, just get it working with a delay_ms(5); between each cycle.

You could use an int16, with bits 0-11 representing your leds, then use bit_test() to see if the led should be on or off.

Here I have started you off:

Code:
int16 leds = 0b000000000000; // all leds off
while(1){
   output_float(PIN_A5);
   output_float(PIN_A4);
   output_float(PIN_A2); // clear leds
   
   output_high(PIN_A0);
   output_float(PIN_A1); // cycle 1
   
   if(bit_test(leds, 1)) // D2
      output_low(PIN_A5);
   if(bit_test(leds, 5)) // D6
      output_low(PIN_A4);
   if(bit_test(leds, 9)) // D10
      output_low(PIN_A2); // test leds and switch on
     
   delay_ms(5);
}
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Mar 05, 2009 3:50 pm     Reply with quote

There are a lot of project examples to be found with Google
and they have source code:

Here's one:
http://www.micro-examples.com/public/microex-navig/doc/091-dymoclock
He has a function called dymoLight(), in which he writes to TRISB
and PortB to turn on the specified LED.

I don't know what the purpose of your project is. I don't know if this
example is completely applicable.
test153



Joined: 09 Feb 2009
Posts: 28

View user's profile Send private message

PostPosted: Fri Mar 06, 2009 2:41 am     Reply with quote

Thanks for the code. I have one question. Wouldn't it be bad to return so much current through one pin, unless there is a special reason we use " output_float" instead of setting it as an input. Aslo if we drive three LEDs at once will they not light less bright?

My initial thought was to controll every LED one by one (lightining only on at a time), with approach is the best. As far as I know a single pin can only handle 25mA.
Sydney



Joined: 13 Feb 2009
Posts: 71

View user's profile Send private message

PostPosted: Fri Mar 06, 2009 3:52 am     Reply with quote

test153 wrote:
Wouldn't it be bad to return so much current through one pin, unless there is a special reason we use " output_float" instead of setting it as an input.


output_float(PIN_A0); // set PIN_A0 as input ;)

test153 wrote:
Aslo if we drive three LEDs at once will they not light less bright?

My initial thought was to controll every LED one by one (lightining only on at a time), with approach is the best. As far as I know a single pin can only handle 25mA.


No they will appear brighter, because each led will be on 4x longer, since there are only 4 cycles vs. 12 if you turn each led on in turn.

Depends what leds you use, most will be way under 25ma, so gp5, 4, and 2 will be fine but gp0, and 1 may need transistors. You could use a resistor in gp5, 4, and 2 to limit the current(putting a resistor in gp0 or 1 will affect the brightness depending on how many of the 3 leds are on in each cycle).

You could also adjust the duty cycle to limit the current, ie change the delay_ms(5) to say 1ms, then put the rest of the delay after my clear leds section. Then the leds are ony on for 1ms every 20ms instead of 5ms.

Code:
int16 leds = 0b000000000000; // all leds off
while(1){
   output_float(PIN_A5);
   output_float(PIN_A4);
   output_float(PIN_A2); // clear leds
   delay_ms(4);

   output_high(PIN_A0);
   output_float(PIN_A1); // cycle 1
   
   if(bit_test(leds, 1)) // D2
      output_low(PIN_A5);
   if(bit_test(leds, 5)) // D6
      output_low(PIN_A4);
   if(bit_test(leds, 9)) // D10
      output_low(PIN_A2); // test leds and switch on
     
   delay_ms(1);
}
Sydney



Joined: 13 Feb 2009
Posts: 71

View user's profile Send private message

PostPosted: Fri Mar 06, 2009 4:09 am     Reply with quote

Here is a test program that should(might) work

Code:
int16 leds = 0b000000000001; // D1 on
while(1){
   output_float(PIN_A5);
   output_float(PIN_A4);
   output_float(PIN_A2); // clear leds
   
   output_high(PIN_A0);
   output_float(PIN_A1); // cycle 1
   
   if(bit_test(leds, 1)) // D2
      output_low(PIN_A5);
   if(bit_test(leds, 5)) // D6
      output_low(PIN_A4);
   if(bit_test(leds, 9)) // D10
      output_low(PIN_A2); // test leds and switch on
     
   delay_ms(5);
   
   output_float(PIN_A5);
   output_float(PIN_A4);
   output_float(PIN_A2); // clear leds
   
   output_low(PIN_A0);
   output_float(PIN_A1); // cycle 2
   
   if(bit_test(leds, 0)) // D1
      output_high(PIN_A5);
   if(bit_test(leds, 4)) // D5
      output_high(PIN_A4);
   if(bit_test(leds, 8)) // D9
      output_high(PIN_A2); // test leds and switch on
     
   delay_ms(5);
   
   output_float(PIN_A5);
   output_float(PIN_A4);
   output_float(PIN_A2); // clear leds
   
   output_float(PIN_A0);
   output_high(PIN_A1); // cycle 3
   
   if(bit_test(leds, 3)) // D4
      output_low(PIN_A5);
   if(bit_test(leds, 7)) // D8
      output_low(PIN_A4);
   if(bit_test(leds, 11)) // D12
      output_low(PIN_A2); // test leds and switch on
     
   delay_ms(5);
   
   output_float(PIN_A5);
   output_float(PIN_A4);
   output_float(PIN_A2); // clear leds
   
   output_float(PIN_A0);
   output_low(PIN_A1); // cycle 4
   
   if(bit_test(leds, 2)) // D3
      output_high(PIN_A5);
   if(bit_test(leds, 6)) // D7
      output_high(PIN_A4);
   if(bit_test(leds, 10)) // D11
      output_high(PIN_A2); // test leds and switch on
     
   delay_ms(5);
   
   if(leds << 1 == 4096)
      leds = 1; // D12 is on, go back to D1
   else
      leds <<= 1; // turn current led off, and next one on
}
test153



Joined: 09 Feb 2009
Posts: 28

View user's profile Send private message

PostPosted: Fri Mar 06, 2009 4:25 am     Reply with quote

Thanks for the code. Will try it out when I get home.

The LEDs I'm using are blue ones with a VF of 3.8 under a 20mA load. Somehow I missread the datasheet and did indeed not a any resistors to GP0 and 1. The pins GP0 and 1 are the only ones I can add restistors to due to the PCB layout. I can't add a transitor either.

If I have three LEDs on I will fry the output... (20*3=60mA going back to GP0 or 1).

What is the difference between output_float() and input()?
Sydney



Joined: 13 Feb 2009
Posts: 71

View user's profile Send private message

PostPosted: Fri Mar 06, 2009 5:55 am     Reply with quote

output_float() makes the pin high impedance, by making it an input, all it does is set the corresponding tris bit high. input() reads the pin, and if you aren't using fast_io will also set the corresponding tris bit high.
Sydney



Joined: 13 Feb 2009
Posts: 71

View user's profile Send private message

PostPosted: Fri Mar 06, 2009 5:59 am     Reply with quote

If resistors aren't an option I would limit the duty cycle of the leds as I described, and you will prolly get away with it, either way the leds will appear as bright.
RLScott



Joined: 10 Jul 2007
Posts: 465

View user's profile Send private message

Re: Multiplexing LEDs
PostPosted: Fri Mar 06, 2009 7:15 am     Reply with quote

This is a very unusual circuit. Let's look at what it takes to turn on D1. If we understand that, we understand all the other LEDs because the diagram is symmetric.

To turn on D1, you must set GP5 HIGH and GP0 LOW. Just knowing those two facts has some important implications. Note that D1 is in parallel with the series combination of D3-D8-D5. Those three diodes point in the correct direction to conduct current whenever D1 is conducting current. The only thing that keeps D3-D8-D5 from lighting up is that it takes 3 forward diode drops of voltage to get current flowing through that series, and we only have one diode drop (the forward voltage of D1). But this does mean that the junctions of D3-D8 and D8-D5 must assume the voltages of .67Vcc and .33Vcc respectively. But that means GP1 must be .67Vcc and GP4 must be .33Vcc. In fact, by analyzing the series D3-D12-D9 in a similar way, you can see that GP2 must also be at .33Vcc.

So just starting from the minimal requirement to turn on D1, we find that all the other PIC pins (GP1, GP4, GP2) must be floating. If any of those three are forced either high or low, then some other diode besides D1 will be turned on. Therefore we can conclude that the only way to multiplex these 12 diodes in the circuit shown is to select only one row and one column (one high, one low) and make every other PIC pin floating.

As for adding resistors, yes, do so. Adding resistors in series with GP0 and GP1 is sufficient, as long as you don't try to turn on more than one LED at a time. Otherwise you have no real control over LED current, and are relying on the unspecified current-limiting properties of the PIC outputs.

Edit: I just realized that it is not strictly true that any non-participating output will turn on some other LED. In the example cited above for turning on D1, you could set GP1 high without turning on any other LEDs. That is because doing so would remove voltage from across D3 and divide the remaining voltage across the series of two diodes: D8-D5 and D12-D9. This would force GP2 and GP4 both to assume .50Vcc. So they definitely must be left floating. And the forward voltage drop of D1 is still not enough to light up a series of two diodes, so D8-D5 and D12-D9 will not light up, even though they have a forward voltage across them. The voltage is just not high enough.

But this does bring up another issue. Whenever you leave non-participating pins floating and they assume an intermediate voltage, you have to consider what the CMOS input structure does. For Schmitt trigger inputs, like GP2, it is no problem. They are made for tolerating intermediate voltages. But for all the TTL inputs (every other pin in the 12F629), putting an intermediate voltage on an input can cause the input stage to be biased into its linear region and cause excessive supply current to flow. It is not a good idea.
_________________
Robert Scott
Real-Time Specialties
Embedded Systems Consulting
Sydney



Joined: 13 Feb 2009
Posts: 71

View user's profile Send private message

Re: Multiplexing LEDs
PostPosted: Fri Mar 06, 2009 10:03 am     Reply with quote

RLScott wrote:
Therefore we can conclude that the only way to multiplex these 12 diodes in the circuit shown is to select only one row and one column (one high, one low) and make every other PIC pin floating.


That statement is not true, as I expained.
test153



Joined: 09 Feb 2009
Posts: 28

View user's profile Send private message

PostPosted: Fri Mar 06, 2009 11:24 am     Reply with quote

Would something like this work in practice? I have chosen to only light 1 LED at a time because of the risk of overloading an "output low" port. It works in the simulator and I think it will work on the hardware too. Unfortunately I can't test it right now and will have to wait until Monday.

It doesn't matter how many LEDs are lit it still takes 48ms (4*12) to cycle through all the LEDs - effectively keeping the brightness at a constant level. (at least that's how it's suppose to work).

Code:

char command;
const long delay=4; // How long each LED should be on

//===============================
void portReset() {
   output_float(PIN_A0);
   output_float(PIN_A1);
   output_float(PIN_A2);
   output_float(PIN_A4);
   output_float(PIN_A5);
}

void led1() {
   output_low(PIN_A0);
   output_high(PIN_A5);
}

void led2() {
   output_low(PIN_A5);
   output_high(PIN_A0);
}

void led3() {
   output_low(PIN_A1);
   output_high(PIN_A5);
}

void led4() {
   output_low(PIN_A5);
   output_high(PIN_A1);
}

//Next matrix line

void led5() {
   output_low(PIN_A0);
   output_high(PIN_A4);
}

void led6() {
   output_low(PIN_A4);
   output_high(PIN_A0);
}

void led7() {
   output_low(PIN_A1);
   output_high(PIN_A4);
}

void led8() {
   output_low(PIN_A4);
   output_high(PIN_A1);
}

//Next matrix line

void led9() {
   output_low(PIN_A0);
   output_high(PIN_A2);
}

void led10() {
   output_low(PIN_A2);
   output_high(PIN_A0);
}

void led11() {
   output_low(PIN_A1);
   output_high(PIN_A2);
}

void led12() {
   output_low(PIN_A2);
   output_high(PIN_A1);
}

void main() {

command = 60; // The ASCII code for 12 is 60, we use ASCII for easy connection to a UART later on.

while(1){
   
   if (command>=49) { led1(); }
   delay_ms(delay); // How long the LEDs should be on
   portReset();
   
   if (command>=50) { led2(); }
   delay_ms(delay); // How long the LEDs should be on
   portReset();
   
   if (command>=51) { led3(); }
   delay_ms(delay); // How long the LEDs should be on
   portReset();
   
   if (command>=52) { led4(); }
   delay_ms(delay); // How long the LEDs should be on
   portReset();
   
   if (command>=53) { led5(); }
   delay_ms(delay); // How long the LEDs should be on
   portReset();
   
   if (command>=54) { led6(); }
   delay_ms(delay); // How long the LEDs should be on
   portReset();
   
   if (command>=55) { led7(); }
   delay_ms(delay); // How long the LEDs should be on
   portReset();
   
   if (command>=56) { led8(); }
   delay_ms(delay); // How long the LEDs should be on
   portReset();
   
   if (command>=57) { led9(); }
   delay_ms(delay); // How long the LEDs should be on
   portReset();
   
   if (command>=58) { led10(); }
   delay_ms(delay); // How long the LEDs should be on
   portReset();
   
   if (command>=59) { led11(); }
   delay_ms(delay); // How long the LEDs should be on
   portReset();
   
   if (command>=60) { led12(); }
   delay_ms(delay); // How long the LEDs should be on
   portReset();
}

}
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group