Best way to drive common anode 7 segments

Hi
I have 3 7 segment leds which are common anode and I just spent some time wiring them to 74HC595's and learning all about shifting out etc but I just read somewhere that I may not be able to use common anode digits with this chip.
What is the best way with the least components to drive them?

I currently have a current resistor on every cathode pin going to the 595's and was trying to read how to wire the vdd to an external power supply when I came across the info stating perhaps I couldn't use 595's with the common anode.

Yes, you can use '595 with common anode.
LED will turn on when the '595 output goes low.
Wire the common anodes to 5v.
'595 is only good for 6-8 mA tho, part like 74AC299 can sink 20mA, for a brighter display.
What value resistors did you use?

I used 330 ohm cause I was planning on going 12v

The other way to drive them is multiplexed, with the cathodes driven direct from the Arduino through a single set of 7 or 8 series resistors (chosen to limit the current per segment to 10 or at most 20mA), and the anodes driven by 3 more Arduino pins via PNP transistors. This is quite economical on hardware but has two disadvantages: it needs 7 Arduino pins (8 if you include the decimal point) + 1 pin per 7-seg display; and your sketch needs to keep refreshing the displays, so you can't make calls to delay() to delay more than a short time. It's a good solution for simple sketches if you can spare the pins, but not for more complex systems.

For 12V, you need different parts. 12V will damage the 74HC595 outputs.
TPIC6B595 are shift registers with high voltage capable open collector outputs.
Or put open collector drivers like ULN2003/2803 after the shift register.
330 will be fairly high current.
If the LED Vforward is 2V, and the open collector drive has 0.7V across it, then the current flow will be
V/R = i
(12V- 2V - .7)/330 = 28mA. Most LEDs are spec'ed at 20, running higher shortens their life.
If Vforward is lower, like 1.7V, then the current is even higher.

I will use a 5v breadboard power supply then instead in the meantime and change my resistor value to perhaps 220 ohm which would be about 15ma per led I think.

It is a fairly simple sketch so I will also have a look at multiplexing them. I had 2 multiplexed so 3 will be no problem.

Thanks for the replies.

Sounds like a good plan.
How are you switching the anodes off & on between parts?

Thats the bit that I am not understanding.
When I multiplexed the 2 7 segment leds and was outputting a simple countdown to them, I was just switching the anodes with an output.Is there any reason I would need to use transistors on the anodes now with 3 digits?
When I originally multiplexed them I wired them like in the following tutorial.

All I did because I had common anode was to replace the B0's with B1's in the code and vice versa. It worked well.

EDIT
As I typed this I realised why. You use the exact same hookup method but connect the new higher current power supply positive to one side of the transistor and the arduino output to the other side to switch the transistor on and off is that correct?
So do I connect the arduino output to the base and the emitter to positive and the collector to ground?

If you use an output as the anode drive and you have 7 segments on at one time, you should limit the current for any one segment to ~25/7 mA, so maybe 4 mA tops so you don't smoke the arduino output eventually. If you're allowing 13-20ma/segment, that's 91-140mA and will damage your ATMega for sure.

I should probably look into getting something like the ULN2803 to drive these right?
Or will I get away with adding 3 high side switches with PNP transistors to the anodes?

Multiple ways to get there.
3 high side PNPs, for the anodes, ULN2803 driving the cathodes of the displays straight from arduino pins,
or a 74HC595 shift register with ULN2803, or a TPIC6B595 that combines the HC595 & ULN2803 in one package - either way the mux'ing is coming from the anode driver.

No1Daemon:
I should probably look into getting something like the ULN2803 to drive these right?
Or will I get away with adding 3 high side switches with PNP transistors to the anodes?

3 high side switches with PNP transistors to drive the anodes, and connect the cathodes through the resistors direct to Arduino outputs. Use a single set of 7 or 8 resistors (not a separate set for each 7-seg display) so that if you accidentally turn on more than one anode at the same time, the current sunk by the pins driving the cathodes is still limited to 20mA. You only need drivers for the cathodes if you want more than about 20mA per segment.

No1Daemon mentioned working from 12V earlier, so ULN2803 is needed there. Will work from 5V also.
Will need a 'driver' in front of the PNP to allow 12V switching into its base also. An open collector NPN would do it.
Or an Allegro2981, PNP version of ULN2803, can drive with 5V logic levels. Has the equivalent of NPN driving a PNP internally.

Yes, he needs drivers if he still wants to run them from 12v. But the latest I saw was that he plans to use the 5v breadboard supply (reply #5).

Thanks. I will use 5v and 3 high side switches. I attempted to read up about how to calculate the resistors to ensure saturation and after about an hour I still don't understand it.
I read the spec sheet on the 2n3906 which is what I have handy but where it states some of the maximums it has a negative ma. Do I just work it out as if it is a positive figure?

So you are saying I can use only 8 220 ohm resistors(limit voltage to around 15ma) multiplex the 3 digits, and use the 3 pnp transistors to switch the anodes?
Thanks for the help guys. I never realised this would be such a learning curve. When I make the finished product I think I will choose common cathode as they seem easier hardware wise to use.

No1Daemon:
Thanks. I will use 5v and 3 high side switches. I attempted to read up about how to calculate the resistors to ensure saturation and after about an hour I still don't understand it.
I read the spec sheet on the 2n3906 which is what I have handy but where it states some of the maximums it has a negative ma. Do I just work it out as if it is a positive figure?

Yes, they are quoting negative mA because it is a PNP transistor. The max current per anode will be 8 * 15mA = 120mA or a bit less if you use a higher value resistor for the decimal point. The hfe of the 2n3906 at this current may only be about 25, so I would design for 8 to 10mA base current. BC327 would be a better choice for this amount of collector current.

No1Daemon:
So you are saying I can use only 8 220 ohm resistors(limit voltage to around 15ma) multiplex the 3 digits, and use the 3 pnp transistors to switch the anodes?

Yes. Although each resistor will be connected to 3 cathodes, only one of the 3 displays will be on at a time, so you can use one resistor for all 3 cathodes (and it is safer for the mcu in case you accidentally turn on 2 or 3 anodes at the same time).

No1Daemon:
Thanks for the help guys. I never realised this would be such a learning curve. When I make the finished product I think I will choose common cathode as they seem easier hardware wise to use.

Not really. With common cathode displays, you would drive the anodes direct from Arduino output pins via the resistors, and use NPN transistors to switch the common cathodes.

Okay thank you very much for all your help guys
I have set it up as you suggest dc42
I have multiplexed the digits and used 7 330ohm resistors and 3 2n3906 pnp transistors as high side switches.
I wasn't entirely sure of the resistor values but what I read on the net suggested that the resistor from the arduino output to the base wasn't critical as long as it makes the voltage to the base lower than the voltage connected to the emitter and I selected 4.7k resistors and I do not need any other resistor do I? I have connected the collector to the anodes and the emitter to the breadboard power supply +v.
EDIT: Sorry, I meant current to the base lower than the current connected to the emitter. Not voltage
Because they are switching common anodes all active outputs should be low.
Does this mean the segment code is reversed as well? or just the anode pins.
If you could have a look at this code please.
its just the setup of the segments I need confirmed and then I need to know how to write the line that will output the result of my calculation to the segments.

int Disp1 = 2;                  // setting up the pins for the displays
int Disp2 = 3;
int Disp3 = 4;
int segA = 5;
int segB = 6;
int segC = 7;
int segD = 8;
int segE = 9;
int segF = 11;
int segG = 10;


  pinMode(Disp1, OUTPUT);
  pinMode(Disp2, OUTPUT);
  pinMode(Disp3, OUTPUT);
  pinMode(segA, OUTPUT);
  pinMode(segB, OUTPUT);
  pinMode(segC, OUTPUT);
  pinMode(segD, OUTPUT);
  pinMode(segE, OUTPUT);
  pinMode(segF, OUTPUT);
  pinMode(segG, OUTPUT);  
 
    digitalWrite(Disp1, LOW);
    digitalWrite(Disp2, LOW);
    digitalWrite(Disp3, LOW);
   }
 
void number(int var)
{
  switch(var)
  {
    case 0:
    digitalWrite(segG, HIGH);
    digitalWrite(segA, LOW);
    digitalWrite(segB, LOW);
    digitalWrite(segC, LOW);
    digitalWrite(segD, LOW);
    digitalWrite(segE, LOW);
    digitalWrite(segF, LOW);
    break;
    
    case 1:
    digitalWrite(segA, HIGH);
    digitalWrite(segD, HIGH);
    digitalWrite(segE, HIGH);
    digitalWrite(segF, HIGH);
    digitalWrite(segG, HIGH);
    digitalWrite(segB, LOW);
    digitalWrite(segC, LOW);
    break;
    
    case 2:
    digitalWrite(segC, HIGH);
    digitalWrite(segF, HIGH);
    digitalWrite(segA, LOW);
    digitalWrite(segB, LOW);
    digitalWrite(segG, LOW);
    digitalWrite(segE, LOW);
    digitalWrite(segD, LOW);    
    break;
    
    case 3:
    digitalWrite(segF, HIGH);
    digitalWrite(segE, HIGH);
    digitalWrite(segA, LOW);
    digitalWrite(segB, LOW);
    digitalWrite(segG, LOW);
    digitalWrite(segC, LOW);
    digitalWrite(segD, LOW);
    break;

    case 4:
    digitalWrite(segA, HIGH);
    digitalWrite(segE, HIGH);
    digitalWrite(segD, HIGH);
    digitalWrite(segF, LOW);
    digitalWrite(segG, LOW);
    digitalWrite(segB, LOW);
    digitalWrite(segC, LOW);
    break;
    
    case 5:
    digitalWrite(segB, HIGH);
    digitalWrite(segE, HIGH);
    digitalWrite(segA, LOW);
    digitalWrite(segF, LOW);
    digitalWrite(segG, LOW);
    digitalWrite(segC, LOW);
    digitalWrite(segD, LOW);
    break;   
    
    case 6:   
    digitalWrite(segB, HIGH);
    digitalWrite(segA, LOW);
    digitalWrite(segF, LOW);
    digitalWrite(segE, LOW);
    digitalWrite(segD, LOW);
    digitalWrite(segC, LOW);
    digitalWrite(segG, LOW);
    break;
    
    case 7:
    digitalWrite(segF, HIGH);
    digitalWrite(segG, HIGH);
    digitalWrite(segE, HIGH);
    digitalWrite(segD, HIGH); 
    digitalWrite(segA, LOW);
    digitalWrite(segB, LOW);
    digitalWrite(segC, LOW);
    break;
    
    case 8:
    digitalWrite(segA, LOW);
    digitalWrite(segB, LOW);
    digitalWrite(segC, LOW);
    digitalWrite(segD, LOW);
    digitalWrite(segE, LOW);
    digitalWrite(segF, LOW);
    digitalWrite(segG, LOW);
    break;
    
    case 9:
    digitalWrite(segE, HIGH);
    digitalWrite(segG, LOW);
    digitalWrite(segF, LOW);
    digitalWrite(segA, LOW);
    digitalWrite(segB, LOW);
    digitalWrite(segC, LOW);
    digitalWrite(segD, LOW);
    break;
   
  }
}

Thanks

You don't need any extra resistors. 4.7K base resistors should be fine.

You should only turn one of the 3 anodes on at a time at most, so in setup() you should initialise the 3 anode driver pins to HIGH (i.e. driver off) rather than LOW.

Your code in number() looks OK, although I would have used a loop and a lookup table.

Here's the rest of a sketch to display 321 (or whatever the current values of 'digits' are) on the display [Warning: untested code!]:

const int numDisplays = 3;
int digits[numDisplays] = {3, 2, 1};
const int displayPins[numDisplays] = {Disp1, Disp2, Disp3};

void loop()
{
  for (int i = 0; i < numDisplays ; ++i) {
    number(digits[i]);
    digitalWrite(displayPins[i], LOW);
    delay(1);
    digitalWrite(displayPins[i], HIGH);
  }
}

If you are doing a lot of other work in loop(), you could use a timer interrupt to do the multiplexing instead.

What I am trying to do is that I have a calculation being returned that is calculated from a ds1307 and then put into 2 long integers.
I need to work out how to output the 1,2 or 3 digits returned to the 3 digits of the 7 segment leds.
So I have 1 integer called daysf and another called days and the output would be daysf-days
So how can I just use your code(provided it works :wink: and I am sure it will) and state that 'digits is equal to daysf-days.
Would that output the numbers in the correct order? ie 100's,10's and 1's to the correct digits?

Do you want to display leading zeros or not? If you do, then this should work (I've assumed the displays are numbered right-to-left):

unsigned int diff = daysf - days;
digits[0] = diff%10;
digits[1] = (diff/10)%10;
digits[2] = (diff/100)%10;

If you don't, then modify your function number() with a 'default' case that sets all segments high (i.e. off) and use this:

unsigned int diff = daysf - days;
digits[0] = diff%10;
digits[1] = (diff >= 10) ? (diff/10)%10 : 10;
digits[2] = (diff >= 100) ? (diff/100)%10 : 10;

I'm using a value of 10 to mean turn the digit off.

You should also consider what to do if diff is <0 or >999.