7 segment multiplex ghosts

Thread Starter

TheButtonThief

Joined Feb 26, 2011
237
Hello

I've searched everywhere for my own answer to this and with no real resolve. I'm building a clock and using an ATmega328 (arduino), a HEF4511 (common cathode 7 seg driver) and 4 7-segment LED modules. The inputs (D0-D3) of the 4511 are pulled low with 10K resistors, outputs directly drive the LEDs of each digit with 160R resistors and to mux, each digit is grounded using a 2N3904 NPN transistor with a 10K resistor at the base. Please see a video below which crudely illustrates the issue and I've included the code too. If I add a delay between turning on the digit and turning it off, the ghost numbers become less apparent, increase that delay and the ghost numbers pretty much disappear but by that point, the delay is sufficient enough to cause significant flicker (anything more than a 5 millisecond delay causes too much flicker but at 5ms, there are still ghosts). I don't know what to do, I've tried tweaking the code, changing components (I thought at first that the transistors aren't switching fast enough) and reading everything about multiplexing but I still don't know what I'm doing wrong.


Code:
int D[] = {8, 9, 10, 11}; // Binary output to D0, D1, D2 & D3

int dig[] = {4, 5, 6, 7}; // Digits to be held high for muxing

int number0 = 5; // number on digit 0  //
int number1 = 5; // number on digit 1   //
int number2 = 3; // number on digit 2    // Start the clock at 23:55 (code will be added later to allow user to set the time)
int number3 = 2; // number on digit 3  //

int j;
int digOn = 0; // Digit to display
int number = 0; // decimal number for output digit
long previousTime = 0; // calculate time lapse
int del = 1000; // delay period in milliseconds

float high = 5.0; // period of time to keep digit held high

int binMatrix[][4] = { // decimal to binary for number output
{0, 0, 0, 0},
{0, 0, 0, 1},
{0, 0, 1, 0},
{0, 0, 1, 1},
{0, 1, 0, 0},
{0, 1, 0, 1},
{0, 1, 1, 0},
{0, 1, 1, 1},
{1, 0, 0, 0},
{1, 0, 0, 1}
};

int digMatrix[][4] = { // digit to be held high for muxing
{0, 0, 0, 1}, // digit 0
{0, 0, 1, 0}, // digit 1
{0, 1, 0, 0}, // digit 2
{1, 0, 0, 0}, // digit 3
};

void digitOn() { // write binary to BCD multiplexer and mux
digit
j = 3;
for (int i = 0; i <= 3; i++) {
digitalWrite (dig[i], digMatrix[digOn][j]);
digitalWrite (D[i], binMatrix[number][j]);
j--;
}
}

void digitOff() {
j = 3;
for (int i = 0; i <= 3; i++) {
digitalWrite (dig[i], 0);
j--;
}
}

void counter() {
if (number0 == 10) {
number0 = 0;
number1++;
}
if (number1 == 6) {
number1 = 0;
number2++;
}
if (number2 == 10) {
number2 = 0;
number3++;
}
if (number3 == 2 & number2 == 4) {
number3 = 0;
number2 = 0;
number1 = 0;
number0 = 0;
}
}

void setup() {

for (int i = 0; i <= 3; i++) {
pinMode (D[i], OUTPUT);
}

for (int i = 0; i <= 3; i++) {
pinMode (dig[i], OUTPUT);
}

// del = del * 60; // Increment of 60 seconds (disabled to allow display to change once every second)
}

void loop() {
counter();

if (digOn == -1) {
digOn = 3; // reset to first digit
}

switch (digOn) { // send counted number to each digit
in turn
case 0: number = number0;
break;
case 1: number = number1;
break;
case 2: number = number2;
break;
case 3: number = number3;
break;
}

digitOn(); // Turn on the digit and display number
delay(high); // Time to keep digit high
digitOff(); // Turn off the digit

unsigned long currentTime = millis();
if (currentTime - previousTime >= del) {
number0++; // Add up
previousTime = currentTime;
}
digOn--; // Shift to next digit

}
Thanks for looking
Jay
 

joeyd999

Joined Jun 6, 2011
5,283
I haven't looked at your code. Here's my guess:

You need dwell time between digits. Wait a bit between releasing the common cathode of a digit before asserting the drive for the subsequent digit.
 

dannyf

Joined Sep 13, 2015
2,197
The code is a little bit hard to follow and can benefit from a rewrite.

The general logic goes like this:

Code:
  turn_off_all_digits();  //turn off all digits
  display_digit(vRAM[digit]);  //display font contained in vRAM[]
  turn_on_digit(digit++); //turn on the digit and advance to the next digit
  if (digit==4) digit=0; //bound digit
in the loop, you can decide how fast / slow to advance "digit" in order to control the update speed.
 

Thread Starter

TheButtonThief

Joined Feb 26, 2011
237
Turns out I was sending the binary number to the 4511 at the same time as turning on a digit and this was causing problems, I've taken the bit of code and split in into 2 parts.

So this is what I had:
Code:
void digitOn() { // write binary to BCD multiplexer and mux digit
  j = 3;
  for (int i = 0; i <= 3; i++) {
    digitalWrite (dig[i], digMatrix[digOn][j]);  // turn on digit [digOn] and keep the rest low
    digitalWrite (D[i], binMatrix[number][j]); // send data to 4511
    j--;
  }
}
And this is what works:
Code:
void digitOn() { // write binary to BCD multiplexer and mux digit
  j = 3;
  for (int i = 0; i <= 3; i++) {
    digitalWrite (D[i], binMatrix[number][j]); // send data to 4511
    j--;
  }

  j = 3;
  for (int i = 0; i <= 3; i++) {
     digitalWrite (dig[i], digMatrix[digOn][j]);  // turn on digit [digOn] and keep the rest low
    j--;
  }
}
Only need to use a 1ms delay between digOn() and digOff() and the display shines nice and bright with no flicker. It still seems to work without any delay but the display doesn't quite shine so bright, I think I may actually prefer that.

Thanks chaps
 
Top