Need help with multiplexed displays

Hello,

I am attempting to make a 6 digit 7-segment counter using an Arduino micro and 3 double common anode 7-Segment displays.

I can't seem to get the timing correct when updating the display.

The display will correctly display the initial state of the counter array, counter[6] = {0, 0, 0, 0, 0, 0} but if I increment counter by 1.
the display glitches.

I am directly driving the displays from the arduino.

Here is the code I am using.

byte anodePins[] = {A0,A1,2,3,4,5};
int segmentPins[] = {6,7,8,9,10,11,12,13};

int digits[10][8] = {
                  {6,7,8,9,12,13,13,13},
                 {6,7,6,7,6,7,6,7},
                 {6,8,9,10,11,12,12,12},
                 {6,7,9,10,11,12,12,12},
                 {6,7,10,11,13,13,13,13},
                 {7,9,10,11,12,13,13,13},
                 {7,8,9,10,11,12,13,13},
                 {6,7,6,7,6,7,6,12},
                 {6,7,8,9,10,11,12,13},
                 {6,7,7,9,10,11,12,13}
                };
                
int counter[6] = {0,0,0,0,0,0};               

void setup() 
{
  int a, s;
  
 for(a = 0; a < 6; a++)
  {
    pinMode(anodePins[a], OUTPUT);
     anodesOff();
  }
  
  for(s = 0; s < 8; s++)
  {
    pinMode(segmentPins[s], OUTPUT);
    segmentsOff();
  }  
  
}

void loop() 
{
  updateLeds();
  
  incCount();
  
}

void anodesOff()
{
  for(int a = 0; a < 6; a++)
  {
     digitalWrite(anodePins[a], LOW);
  }
}

void segmentsOff()
{
  for(int s = 0; s < 8; s++)
  {
    digitalWrite(segmentPins[s], LOW);
  }
}



void updateLeds()
{
  int p, s, q, z;
  
 anodesOff();
 segmentsOff();
 
 digitalWrite(anodePins[0], HIGH);
 
 for(p = 0; p < 8; p++)
 {
   digitalWrite(digits[counter[5]][p], HIGH);
 }
 
  anodesOff();
 segmentsOff();
 
 digitalWrite(anodePins[1], HIGH);
 
 for(p = 0; p < 8; p++)
 {
   digitalWrite(digits[counter[4]][p], HIGH);
 }

anodesOff();
 segmentsOff();
 

 digitalWrite(anodePins[2], HIGH);
 
 for(p = 0; p < 8; p++)
 {
   digitalWrite(digits[counter[3]][p], HIGH);
 }

anodesOff();
 segmentsOff();
 

 digitalWrite(anodePins[3], HIGH);
 
 for(p = 0; p < 8; p++)
 {
   digitalWrite(digits[counter[2]][p], HIGH);
 }  

anodesOff();
 segmentsOff();
 

 digitalWrite(anodePins[4], HIGH);
 
 for(p = 0; p < 8; p++)
 {
   digitalWrite(digits[counter[1]][p], HIGH);
 } 

anodesOff();
 segmentsOff();
 

 digitalWrite(anodePins[5], HIGH);
 
 for(p = 0; p < 8; p++)
 {
   digitalWrite(digits[counter[0]][p], HIGH);
 }  

}

void incCount()
{
  counter[5] = counter[5] + 1;
}

Any help will be greatly appreciated.

I solved the counting problem with the following code.

byte anodePins[] = {A0,A1,2,3,4,5};
int segmentPins[] = {6,7,8,9,10,11,12,13};

int digits[10][8] = {
                  {6,7,8,9,12,13,13,13},
                 {6,7,6,7,6,7,6,7},
                 {6,8,9,10,11,12,12,12},
                 {6,7,9,10,11,12,12,12},
                 {6,7,10,11,13,13,13,13},
                 {7,9,10,11,12,13,13,13},
                 {7,8,9,10,11,12,13,13},
                 {6,7,6,7,6,7,6,12},
                 {6,7,8,9,10,11,12,13},
                 {6,7,7,9,10,11,12,13}
                };
                
int counter[6] = {0,0,0,0,0,0};               

int count = 0;

void setup() 
{
  int a, s;
  
 for(a = 0; a < 6; a++)
  {
    pinMode(anodePins[a], OUTPUT);
     anodesOff();
  }
  
  for(s = 0; s < 8; s++)
  {
    pinMode(segmentPins[s], OUTPUT);
    segmentsOff();
  }  
  
}

void loop() 
{
  updateLeds();
  
  //counter[0] = counter[0] + 1;
  
  incCount();
  
}

void anodesOff()
{
  for(int a = 0; a < 6; a++)
  {
     digitalWrite(anodePins[a], LOW);
  }
}

void segmentsOff()
{
  for(int s = 0; s < 8; s++)
  {
    digitalWrite(segmentPins[s], LOW);
  }
}



void updateLeds()
{
  int p, s, q, z;
  
 //anodesOff();
 //segmentsOff();
 
 digitalWrite(anodePins[0], HIGH);
 
 for(p = 0; p < 8; p++)
 {
   digitalWrite(digits[counter[5]][p], HIGH);
 }
 
  anodesOff();
 segmentsOff();
 
 digitalWrite(anodePins[1], HIGH);
 
 for(p = 0; p < 8; p++)
 {
   digitalWrite(digits[counter[4]][p], HIGH);
 }

anodesOff();
 segmentsOff();
 

 digitalWrite(anodePins[2], HIGH);
 
 for(p = 0; p < 8; p++)
 {
   digitalWrite(digits[counter[3]][p], HIGH);
 }

anodesOff();
 segmentsOff();
 

 digitalWrite(anodePins[3], HIGH);
 
 for(p = 0; p < 8; p++)
 {
   digitalWrite(digits[counter[2]][p], HIGH);
 }  

anodesOff();
 segmentsOff();
 
 digitalWrite(anodePins[4], HIGH);
 
 for(p = 0; p < 8; p++)
 {
   digitalWrite(digits[counter[1]][p], HIGH);
 } 

anodesOff();
 segmentsOff();
 

 digitalWrite(anodePins[5], HIGH);
 
 for(p = 0; p < 8; p++)
 {
   digitalWrite(digits[counter[0]][p], HIGH);
 }  
 
 anodesOff();
 segmentsOff();

}

void incCount()
{
  
  count += 1;
  
if(count == 1000)
 {
   counter[5] = counter[5] + 1;
   count = 0;
 }
 
 if(counter[5] == 10)
 {
 counter[5] = 0;
 counter[4] = counter[4] + 1;
 }
 
 if(counter[4] == 10)
 {
   counter[4] = 0;
   counter[3] = counter[3] + 1;
 }
 
if(counter[3] == 10)
{
  counter[3] = 0;
  counter[2] = counter[2] + 1;
}

if(counter[2] == 10)
{
  counter[2] = 0;
  counter[1] = counter[1] + 1;
}

if(counter[1] == 10)
{
  counter[1] = 0;
  counter[0] = counter[0] + 1;
}

if(counter[0] == 10)
{
  for(int z = 0; z < 6; z++)
  {
    counter[z] = 0;
  }
}

}

Now the only issue is that some of the segments are dimmer than other segments.

And this code approximates a clock.

byte anodePins[] = {A0,A1,2,3,4,5};
int segmentPins[] = {6,7,8,9,10,11,12,13};

int digits[10][8] = {
                  {6,7,8,9,12,13,13,13},
                 {6,7,6,7,6,7,6,7},
                 {6,8,9,10,11,12,12,12},
                 {6,7,9,10,11,12,12,12},
                 {6,7,10,11,13,13,13,13},
                 {7,9,10,11,12,13,13,13},
                 {7,8,9,10,11,12,13,13},
                 {6,7,6,7,6,7,6,12},
                 {6,7,8,9,10,11,12,13},
                 {6,7,7,9,10,11,12,13}
                };
                
int counter[6] = {0,2,5,5,0,0};               

int count = 0;

int rollover = 0;

void setup() 
{
  int a, s;
  
 for(a = 0; a < 6; a++)
  {
    pinMode(anodePins[a], OUTPUT);
     anodesOff();
  }
  
  for(s = 0; s < 8; s++)
  {
    pinMode(segmentPins[s], OUTPUT);
    segmentsOff();
  }  
  
}

void loop() 
{
  updateLeds();
  incCount();
  
}

void anodesOff()
{
  for(int a = 0; a < 6; a++)
  {
     digitalWrite(anodePins[a], LOW);
  }
}

void segmentsOff()
{
  for(int s = 0; s < 8; s++)
  {
    digitalWrite(segmentPins[s], LOW);
  }
}

void updateLeds()
{
  int p, s, q, z;
  
 //anodesOff();
 //segmentsOff();
 
 digitalWrite(anodePins[0], HIGH);
 
 for(p = 0; p < 8; p++)
 {
   digitalWrite(digits[counter[5]][p], HIGH);
 }
 
  anodesOff();
 segmentsOff();
 
 digitalWrite(anodePins[1], HIGH);
 
 for(p = 0; p < 8; p++)
 {
   digitalWrite(digits[counter[4]][p], HIGH);
 }

anodesOff();
 segmentsOff();
 

 digitalWrite(anodePins[2], HIGH);
 
 for(p = 0; p < 8; p++)
 {
   digitalWrite(digits[counter[3]][p], HIGH);
 }

anodesOff();
 segmentsOff();
 

 digitalWrite(anodePins[3], HIGH);
 
 for(p = 0; p < 8; p++)
 {
   digitalWrite(digits[counter[2]][p], HIGH);
 }  

anodesOff();
 segmentsOff();
 
 digitalWrite(anodePins[4], HIGH);
 
 for(p = 0; p < 8; p++)
 {
   digitalWrite(digits[counter[1]][p], HIGH);
 } 

anodesOff();
 segmentsOff();
 

 digitalWrite(anodePins[5], HIGH);
 
 for(p = 0; p < 8; p++)
 {
   digitalWrite(digits[counter[0]][p], HIGH);
 }  
 
 anodesOff();
 segmentsOff();

}

void incCount()
{
  
  count += 1;
  
if(count == 1000)
 {
   counter[5] = counter[5] + 1;
   count = 0;
 }
 
 if(counter[5] == 10)
 {
 counter[5] = 0;
 counter[4] = counter[4] + 1;
 }
 
 if(counter[4] == 6)
 {
   counter[4] = 0;
   counter[3] = counter[3] + 1;
 }
 
if(counter[3] == 10)
{
  counter[3] = 0;
  counter[2] = counter[2] + 1;
}

if(counter[2] == 6)
{
  counter[2] = 0;
  counter[1] = counter[1] + 1;
}

if(counter[1] == 10 && rollover == 0)
{
  counter[1] = 0;
  counter[0] = counter[0] + 1;
  rollover = rollover + 1;
}
else 
if(rollover == 1 && counter[1] == 3)
{
  counter[0] = 0;
  counter[1] = 1;
  counter[2] = 0;
  counter[3] = 0;
  counter[4] = 0;
  counter[5] = 0;
  rollover = 0;
}
}

Still need help on why the display is dim while multiplexing.

What is your hardware setup with current limit resistors?
I can't tell from the code - are you turning on more than 1 segment at a time?

Hello,

I am using an arduino micro the anodes are being switched on and off through 2n2222 NPN transistors.

The segment cathodes have 47ohm resistors and are also being switched with 2n2222 NPN trnsistors.

I am not utilizing the RTC in the picture because when I
try to

Wire.begin();
Serial.begin(9600);

The entire display dims significantly. I will try to figure that out later.

20130519_134302.jpg

Should have used PNP transistors for switching the anodes.
PNPs like to source current, NPNs like to sink current.
Speed up the Serial interface, like 115200.

I am beginning to really hate functions. Your code bounces all over the place and is hard to follow. No comments makes it worse. Its not just you, nothing personal.

I cannot tell how long you leave each digit displayed for.
You would have been better off writing it "blink without delay" style,
Test if 20mS elapsed, to update for the next digit,
Test if 1S elapsed, update the counters.
The vast majority of the time, neither of those tests will be true and you can be doing other things, like reading an RTC value.

Interesting results when I switched out the 2n2222 NPN for a 2n3906 PNP for one of the anodes, it was much brighter but it just displays an 8 and no other digits.

Could there be too much current going through with the cathode resistors being so low?

No, I think it is due to not having any hold time on the display.
It is cycling thru everything so fast the segments all look like they are on together.

I believe it's the way I have the PNP wired to the anode.

It never shuts off the voltage to the anode when the arduio pin goes low.

I have wired the PNP in correctly.

It still is dim.

Could the arduino not be able to drive that many displays that brightly?

You only drive 8 at a time, only 160mA, it has plenty for that.
What you need is some hold time for each digit.
To be flicker free, you want to refresh all 6 of them 25 or 30 times a second.
1/30 = 33mS.
6 digits, each held on for 5mS, will do that.
Your code just goes bang-bang-bang-bang-bang-bang, no hold time per digit for the eye to perceive the number.

Brilliant!!

I added a delay of 1 ms right before a switch off of the anodes and segments and the display is much brighter, 5ms produced a flicker.

I had to adjust the count so that it would count up in seconds.

Here is the new code.

byte anodePins[] = {A0,A1,2,3,4,5};
int segmentPins[] = {6,7,8,9,10,11,12,13};

int digits[10][8] = {
                  {6,7,8,9,12,13,13,13},
                 {6,7,6,7,6,7,6,7},
                 {6,8,9,10,11,12,12,12},
                 {6,7,9,10,11,12,12,12},
                 {6,7,10,11,13,13,13,13},
                 {7,9,10,11,12,13,13,13},
                 {7,8,9,10,11,12,13,13},
                 {6,7,6,7,6,7,6,12},
                 {6,7,8,9,10,11,12,13},
                 {6,7,7,9,10,11,12,13}
                };
                
int counter[6] = {0,5,3,3,0,0};               

int count = 0;

int rollover = 0;

int hold = 1;

void setup() 
{
  int a, s;
  
 for(a = 0; a < 6; a++)
  {
    pinMode(anodePins[a], OUTPUT);
     anodesOff();
  }
  
  for(s = 0; s < 8; s++)
  {
    pinMode(segmentPins[s], OUTPUT);
    segmentsOff();
  }  
  
}

void loop() 
{
  updateLeds();
  
  //counter[0] = counter[0] + 1;
  
  incCount();
  
}

void anodesOff()
{
  for(int a = 0; a < 6; a++)
  {
     digitalWrite(anodePins[a], LOW);
  }
}

void segmentsOff()
{
  for(int s = 0; s < 8; s++)
  {
    digitalWrite(segmentPins[s], LOW);
  }
}



void updateLeds()
{
  int p, s, q, z;
  
 //anodesOff();
 //segmentsOff();
 
 digitalWrite(anodePins[0], HIGH);
 
 for(p = 0; p < 8; p++)
 {
   digitalWrite(digits[counter[5]][p], HIGH);
 }
 delay(hold);
  anodesOff();
 segmentsOff();
 
 digitalWrite(anodePins[1], HIGH);
 
 for(p = 0; p < 8; p++)
 {
   digitalWrite(digits[counter[4]][p], HIGH);
 }
delay(hold);
anodesOff();
 segmentsOff();
 

 digitalWrite(anodePins[2], HIGH);
 
 for(p = 0; p < 8; p++)
 {
   digitalWrite(digits[counter[3]][p], HIGH);
 }
delay(hold);
anodesOff();
 segmentsOff();
 

 digitalWrite(anodePins[3], HIGH);
 
 for(p = 0; p < 8; p++)
 {
   digitalWrite(digits[counter[2]][p], HIGH);
 }  
delay(hold);
anodesOff();
 segmentsOff();
 
 digitalWrite(anodePins[4], HIGH);
 
 for(p = 0; p < 8; p++)
 {
   digitalWrite(digits[counter[1]][p], HIGH);
 } 
delay(hold);
anodesOff();
 segmentsOff();
 

 digitalWrite(anodePins[5], HIGH);
 
 for(p = 0; p < 8; p++)
 {
   digitalWrite(digits[counter[0]][p], HIGH);
 }  
 delay(hold);
 anodesOff();
 segmentsOff();

}

void incCount()
{
  
  count += 1;
  
if(count == 150)
 {
   counter[5] = counter[5] + 1;
   count = 0;
 }
 
 if(counter[5] == 10)
 {
 counter[5] = 0;
 counter[4] = counter[4] + 1;
 }
 
 if(counter[4] == 6)
 {
   counter[4] = 0;
   counter[3] = counter[3] + 1;
 }
 
if(counter[3] == 10)
{
  counter[3] = 0;
  counter[2] = counter[2] + 1;
}

if(counter[2] == 6)
{
  counter[2] = 0;
  counter[1] = counter[1] + 1;
}

if(counter[1] == 10 && rollover == 0)
{
  counter[1] = 0;
  counter[0] = counter[0] + 1;
  rollover = rollover + 1;
}
else 
if(rollover == 1 && counter[1] == 3)
{
  counter[0] = 0;
  counter[1] = 1;
  counter[2] = 0;
  counter[3] = 0;
  counter[4] = 0;
  counter[5] = 0;
  rollover = 0;
}
}

That's one way to get there.
What was it counting up in before?

It was counting to 1000 to approximate a second of elapsed time for the incCount()

With the delay set to 1 between the switching off of the anodes and segments, I had to adjust the count to 150 to approximate 1 second of elapsed time.

It works much better.

I am now trying to integrate the RTC that is pictured.

When I try to use

Wire.begin();
Serial.begin(115200);

The two displays in the center almost go completely dark???

This happens no matter what I set the baud to.

Ok so:
Re-write it "blink without delay" style,
Test if 20mS elapsed, to update for the next digit,
Test if 1S elapsed, update the counters.
The vast majority of the time, neither of those tests will be true and you can be doing other things, like reading an RTC value.

I'm sorry, I am not understanding "blink without delay"?

See if this makes sense to you:

all time elements are data type "unsigned long"

void loop(){
currentTime  = millis(;
if ((currentTime - previousTime1) >= duration1){
previousTime1 = previousTime1 + duration1;  // save time for next pass thru loop
// do action 1 - this could be 5 mS check for display updates of counter values
}

if ((currentTime - previousTime2) >= duration2){
previousTime2 = previousTime2 + duration2;  // save time for next pass thru loop
// do action 2 - this could be 100mS check to see if RTC time had changed
// do the Wire.send & Wire. receive transfers to read from DS1307 or whatever here

//When done, see if the time was changed:

if (RTC_time != priorRTC_time){
priorRTC_Time = RTC_time;
// put code here that updates the counters
   }

 }

} // end loop

It does make sense.

It will take some time to re-write the code to incorporate your suggestions.

You help is greatly appreciated.

I am still experimenting with incorporating your suggestions.

In the interim, I have updated the code to clean up some of the brute force coding and correct for instances when the time set is greater than 9 if anyone is interested.

byte anodePins[] = {A0,A1,2,3,4,5};
int segmentPins[] = {6,7,8,9,10,11,12,13};

int digits[10][8] = {
                  {6,7,8,9,12,13,13,13},
                 {6,7,6,7,6,7,6,7},
                 {6,8,9,10,11,12,12,12},
                 {6,7,9,10,11,12,12,12},
                 {6,7,10,11,13,13,13,13},
                 {7,9,10,11,12,13,13,13},
                 {7,8,9,10,11,12,13,13},
                 {6,7,6,7,6,7,6,12},
                 {6,7,8,9,10,11,12,13},
                 {6,7,7,9,10,11,12,13}
                };
                
int counter[6] = {0,9,5,9,0,0};               

int rolloverAssign[6] = {0,1,0,0,0,0};

int count = 0;

int rollover = 0;

int hold = 1;

int anodePosition = 0;
int segmentPosition = 5;

void setup() 
{
  int a, s;
  
 for(a = 0; a < 6; a++)
  {
    pinMode(anodePins[a], OUTPUT);
     anodesOff();
  }
  
  for(s = 0; s < 8; s++)
  {
    pinMode(segmentPins[s], OUTPUT);
    segmentsOff();
  }  
  
  if(counter[0] == 1)
  rollover = 1;
}

void loop() 
{
  for(int i = 0; i < 6; i++)
  updateDisplay();
  
  incCount();
}

void anodesOff()
{
  for(int a = 0; a < 6; a++)
  {
     digitalWrite(anodePins[a], LOW);
  }
}

void segmentsOff()
{
  for(int s = 0; s < 8; s++)
  {
    digitalWrite(segmentPins[s], LOW);
  }
}

void incCount()
{
  
 count += 1;
  
if(count == 150)
 {
   counter[5]  += 1;
   count = 0;
 }
 
 if(counter[5] == 10)
 {
 counter[5] = 0;
 counter[4] += 1;
 }
 
 if(counter[4] == 6)
 {
   counter[4] = 0;
   counter[3] += 1;
 }
 
if(counter[3] == 10)
{
  counter[3] = 0;
  counter[2] += 1;
}

if(counter[2] == 6)
{
  counter[2] = 0;
  counter[1] += 1;
}

if(counter[1] == 10 && rollover == 0)
{
  counter[1] = 0;
  counter[0] += 1;
  rollover += 1;
}
else 
if(rollover == 1 && counter[1] == 3)
{
  for(int i = 0; i < 6; i++)
 counter[i] = rolloverAssign[i]; 
  
  rollover = 0;
}
}
  
void updateDisplay()
{
  if(anodePosition == 6 && segmentPosition == -1 )
  {
    anodePosition = 0;
    segmentPosition = 5;
  }
  else
  {
    digitalWrite(anodePins[anodePosition], HIGH);
 
     for(int p = 0; p < 8; p++)
     {
       digitalWrite(digits[counter[segmentPosition]][p], HIGH);
     }
     delay(hold);
      anodesOff();
       segmentsOff();
       
     anodePosition += 1;
     segmentPosition -= 1;
  }
}

The ultimate goal is to build a clock/timer with larger digits that require around 12 volts to power.

I have this board that is populated with 1 to 12 TPIC6B595 shift registers, good for sinking 12V current thru LED strings.
It can drive up to 12 digits.
http://www.crossroadsfencing.com/BobuinoRev17/