Multiplexing 6, 7 segment digits with ULN2803 and 2N2222

Hi,

I am working on a project, where i want to control six 7 segment displays, I want to power them using 12V power supply and i want to separate that power rail from arduino. So i decided to use:

Arduino uno
74HC595
ULN2803 (for connecting led display to gnd)
6 x 2N222 (to connect LED display to 12V
six 7 segment displays of 1 number

here's the circuit:

My display is just 6 separate 7 segments numbers, I have connected all wires A-G together and each number positive wire i want to switch on when i need that specific number.

For some reason my 2N2222 transistors gets really hot and to LEDs i get only around 5-6V, instead of 12V. Looks like transistors does not open fully and getting really hot.

Any ideas what's wrong here? Should i replace 2N2222 with a logic level mosfets instead? Or regular PNP transistor?

Looks like you are using the the transistors as a high side switch.
The output of the Arduino outputs 0-5 volts, that's why the LEDs only see ~5V at the emitter.
The 22s are not saturating therefore, they are getting hot.

Also you need a base resistor for the 2N2222s however, you will need to drive PNPs with the 2N2222s (emitter to ground, collector though a resistor ~2.2K to +12V to the base of the new PNPs).

Looks like your schematic isn't complete.

The other part of shematic are some push buttons to control display..

Looks pretty complicated...

Arduino > resistor > base (2N222) / emiter - gnd / cathode > resistor > PNP base > emiter load > cathode to 12V? I saw on some other forums that people are using just PNP transistor for high side switching. Is this what you've meant? http://jeelabs.org/2012/11/12/high-side-switching/

would a mosfet work for this?

edvardas:
Looks pretty complicated...

Arduino > resistor > base (2N222) / emiter - gnd / cathode > resistor > PNP base > emiter load > cathode to 12V? I saw on some other forums that people are using just PNP transistor for high side switching. Is this what you've meant? http://jeelabs.org/2012/11/12/high-side-switching/

Yes, that page explains the problem. You will also need 10K pull-ups (to 12V) on the pnp bases, otherwise they will never switch off.

edvardas:
would a mosfet work for this?

No, same problem!

There are other ways to run your displays or simplify your circuit.

You can replace your 74xx595 + ULN2803 with a single chip, a tpic6x595.

You can use a MIC5981, which is like ULN2803 but for high-side switching.

You could abandon multiplexing and have a tpic chip per digit, all 4 chips daisy-chained to the same Arduino pins.

You could use 2 saa1064 chips. These use i2c bus, so both chips connected to the same 2 Arduino pins (SDA & SCL).

Paul

Do you mean something like this for each digit:

What size of pull up should I use? 10kOhm on all ?

R16 is it not needed.
The gain of the transistors are necessary.
Start with 4.7K for R17 2.2K for R15.

LarryD:
R16 is it not needed.

So then when the NPN turns on (its collector goes to Gnd), PNP IB will be _____A ?

At any rate, "R16" isn't placed properly.
ET Issues and Answers: High-side Switching

You are correct.

So what resistor values should I use? for R16 and R17? I have now 4.7K for R17

The easiest way will be to use two TPIC6B595s, chained together so both are driven by the same 3 pins.

One directly drives the segments via the resistors. The other drives your high-side PNPs via their base resistors. You most likely will not really need emitter-base resistors on them as such leakage as there is will not result in any visible indication on the LEDs.

ULN2x03s are pretty much obsoleted by FET devices such as the TPIC6B595.

edvardas:
So what resistor values should I use? for R16 and R17? I have now 4.7K for R17

How about the values that I called out in the schematic at my blog (link)?
Don't place the resistors as in your schematic, but as I show in mine.

Everything works now as expected. Thank you guys for your help!

I'm having another problem. I have 6 digits connected and I use 12V power supply. After ULN2803 i have 1 kOhm resistors for each segment.

For some reason not all segments on near digits come off, some stay on but very dim.. For example if i have number 0 0 0 0 1 3, so on number 1 i still can see leds for number 3 on. Or if i light on a dot, that dot is replicated to the second digit, but much less dim.. But other digits do not replicate that, it's visible only on near digits, e.g. number 1 ir replicating number 2, 3 is replicating 4 and so on..

Should i increase resistor size to like 10 kOhm? But then everything would be more dim...

Here is my code for segments:

void skaicius (int skcius){ 
  #define seg_on  LOW
  #define seg_off HIGH
    switch (skcius){
  case 0:
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, MSBFIRST, B00111111);   
    digitalWrite(latchPin, HIGH);
    break;
  case 1:
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, MSBFIRST, B00000110);  
    digitalWrite(latchPin, HIGH);
    break;
  case 2:
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, MSBFIRST, B01011011);   
    digitalWrite(latchPin, HIGH);
    break;
  case 3:
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, MSBFIRST, B01001111);  
    digitalWrite(latchPin, HIGH);
    break;
  case 4:
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, MSBFIRST, B01100110);   
    digitalWrite(latchPin, HIGH);
    break;
  case 5:
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, MSBFIRST, B01101101);   
    digitalWrite(latchPin, HIGH);
    break;
  case 6:
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, MSBFIRST, B01111101);   // pakeista i 6 su pagaliuku virsuj
    digitalWrite(latchPin, HIGH);
    break;
  case 7:
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, MSBFIRST, B00000111);   
    digitalWrite(latchPin, HIGH);
    break;
  case 8:
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, MSBFIRST, B01111111);   
    digitalWrite(latchPin, HIGH);
    break;
  case 9:
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, MSBFIRST, B01101111);   // pakeista i 9 su pagaliuku apacioj
    digitalWrite(latchPin, HIGH);
    break;
  case 10:
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, MSBFIRST, B00000000);
    digitalWrite(latchPin, HIGH);
    break;
    case 11:
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, MSBFIRST, B01000000);
    digitalWrite(latchPin, HIGH);
    break;  
  }} 

void show_digit(int minutesds, int minutesd, int minutesv, int sekundesd,int sekundesv){ 
unsigned long pradzia;
int ded = 2500;


digitalWrite(digit6, HIGH);
skaicius(sekundesv);
delayMicroseconds(ded);
digitalWrite(digit6, LOW);

if (sekundesd > 0 || minutesv > 0 || minutesd > 0 || minutesds > 0){
digitalWrite(digit5, HIGH);
}
skaicius(sekundesd);
delayMicroseconds(ded);
digitalWrite(digit5, LOW);


if (minutesv > 0 || minutesd >0 || minutesds >0){ 
digitalWrite(digit4, HIGH);
}
skaicius_su_tasku(minutesv);
delayMicroseconds(ded);
digitalWrite(digit4, LOW);

if (minutesd > 0 || minutesds > 0){
digitalWrite(digit3, HIGH);
}
skaicius(minutesd);
delayMicroseconds(ded);
digitalWrite(digit3, LOW);

if (minutesds > 0)
{
digitalWrite(digit2, HIGH);
}
skaicius(minutesds);
delayMicroseconds(ded);
digitalWrite(digit2, LOW);

if (ipliusa == true) {
digitalWrite(digit1, HIGH);
skaicius(11);
delayMicroseconds(ded/2);
digitalWrite(digit1, LOW); }

}

I'm having problems understanding your sketch, maybe because it is not complete, partly because the variable name and comments are not English (sorry!).

But I have a concern about this:

  if (sekundesd > 0 || minutesv > 0 || minutesd > 0 || minutesds > 0) {
    digitalWrite(digit5, HIGH);
  }
  skaicius(sekundesd);
  delayMicroseconds(ded);
  digitalWrite(digit5, LOW);

Making digit5 HIGH is conditional, which means that sometimes new data will be shifted out before the previous digit has been switched off? This could lead to the "bleeding" or "ghosting" effect you describe. This is not the only such conditional I found in your code.

I have a timer here, minutes up to 999 and seconds up to 60, 6th digit is just for displaying "-" sign. So what i do i divide my time into separate digits and then I display them:

hundreds of minutes
tens of minutes
minutes
tens of seconds
seconds

And with this statement i dont turn on digit, if all digits ahead of it are zero. So for example if i have 000:59, so only 59 will be shown on display. Or 011:01, at this case 11:01 will be shown.

digitalWrite(digit6, HIGH);
skaicius(sekundesv); //skaicius function, which lights up segments for a digit (sekundesv)
delayMicroseconds(ded); //this sets brightness
digitalWrite(digit6, LOW);

This effect that I have described happends independently if I have this condition on or not. Here's how this effect looks like:

Try shifting out the data before you make each digit HIGH, like this:

skaicius(sekundesv); //skaicius function, which lights up segments for a digit (sekundesv)
digitalWrite(digit6, HIGH);
delayMicroseconds(ded); //this sets brightness
digitalWrite(digit6, LOW);

PaulRB:
Try shifting out the data before you make each digit HIGH, like this:

skaicius(sekundesv); //skaicius function, which lights up segments for a digit (sekundesv)

digitalWrite(digit6, HIGH);
delayMicroseconds(ded); //this sets brightness
digitalWrite(digit6, LOW);

Fixed problem like a charm. Thank you!