7 segment multiplex ghosts

Discussion in 'Embedded Systems and Microcontrollers' started by TheButtonThief, Sep 24, 2015.

  1. TheButtonThief

    Thread Starter Active Member

    Feb 26, 2011
    219
    38
    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 (Text):
    1. int D[] = {8, 9, 10, 11}; // Binary output to D0, D1, D2 & D3
    2.  
    3. int dig[] = {4, 5, 6, 7}; // Digits to be held high for muxing
    4.  
    5. int number0 = 5; // number on digit 0  //
    6. int number1 = 5; // number on digit 1   //
    7. 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)
    8. int number3 = 2; // number on digit 3  //
    9.  
    10. int j;
    11. int digOn = 0; // Digit to display
    12. int number = 0; // decimal number for output digit
    13. long previousTime = 0; // calculate time lapse
    14. int del = 1000; // delay period in milliseconds
    15.  
    16. float high = 5.0; // period of time to keep digit held high
    17.  
    18. int binMatrix[][4] = { // decimal to binary for number output
    19. {0, 0, 0, 0},
    20. {0, 0, 0, 1},
    21. {0, 0, 1, 0},
    22. {0, 0, 1, 1},
    23. {0, 1, 0, 0},
    24. {0, 1, 0, 1},
    25. {0, 1, 1, 0},
    26. {0, 1, 1, 1},
    27. {1, 0, 0, 0},
    28. {1, 0, 0, 1}
    29. };
    30.  
    31. int digMatrix[][4] = { // digit to be held high for muxing
    32. {0, 0, 0, 1}, // digit 0
    33. {0, 0, 1, 0}, // digit 1
    34. {0, 1, 0, 0}, // digit 2
    35. {1, 0, 0, 0}, // digit 3
    36. };
    37.  
    38. void digitOn() { // write binary to BCD multiplexer and mux
    39. digit
    40. j = 3;
    41. for (int i = 0; i <= 3; i++) {
    42. digitalWrite (dig[i], digMatrix[digOn][j]);
    43. digitalWrite (D[i], binMatrix[number][j]);
    44. j--;
    45. }
    46. }
    47.  
    48. void digitOff() {
    49. j = 3;
    50. for (int i = 0; i <= 3; i++) {
    51. digitalWrite (dig[i], 0);
    52. j--;
    53. }
    54. }
    55.  
    56. void counter() {
    57. if (number0 == 10) {
    58. number0 = 0;
    59. number1++;
    60. }
    61. if (number1 == 6) {
    62. number1 = 0;
    63. number2++;
    64. }
    65. if (number2 == 10) {
    66. number2 = 0;
    67. number3++;
    68. }
    69. if (number3 == 2 & number2 == 4) {
    70. number3 = 0;
    71. number2 = 0;
    72. number1 = 0;
    73. number0 = 0;
    74. }
    75. }
    76.  
    77. void setup() {
    78.  
    79. for (int i = 0; i <= 3; i++) {
    80. pinMode (D[i], OUTPUT);
    81. }
    82.  
    83. for (int i = 0; i <= 3; i++) {
    84. pinMode (dig[i], OUTPUT);
    85. }
    86.  
    87. // del = del * 60; // Increment of 60 seconds (disabled to allow display to change once every second)
    88. }
    89.  
    90. void loop() {
    91. counter();
    92.  
    93. if (digOn == -1) {
    94. digOn = 3; // reset to first digit
    95. }
    96.  
    97. switch (digOn) { // send counted number to each digit
    98. in turn
    99. case 0: number = number0;
    100. break;
    101. case 1: number = number1;
    102. break;
    103. case 2: number = number2;
    104. break;
    105. case 3: number = number3;
    106. break;
    107. }
    108.  
    109. digitOn(); // Turn on the digit and display number
    110. delay(high); // Time to keep digit high
    111. digitOff(); // Turn off the digit
    112.  
    113. unsigned long currentTime = millis();
    114. if (currentTime - previousTime >= del) {
    115. number0++; // Add up
    116. previousTime = currentTime;
    117. }
    118. digOn--; // Shift to next digit
    119.  
    120. }
    Thanks for looking
    Jay
     
  2. joeyd999

    AAC Fanatic!

    Jun 6, 2011
    2,677
    2,727
    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.
     
  3. dannyf

    Well-Known Member

    Sep 13, 2015
    1,782
    360
    The code is a little bit hard to follow and can benefit from a rewrite.

    The general logic goes like this:

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

    Thread Starter Active Member

    Feb 26, 2011
    219
    38
    I can follow it ok (I guess that matters most) but I think you're right, maybe a re-write.
     
  5. KeepItSimpleStupid

    Well-Known Member

    Mar 4, 2014
    1,143
    203
    You basically need to turn off all the digits for a short time (i.e. Blank the display), load the new value of the next digit and turn on the new digit.

    The term is "inter-digit blanking"
     
    TheButtonThief likes this.
  6. TheButtonThief

    Thread Starter Active Member

    Feb 26, 2011
    219
    38
    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 (Text):
    1. void digitOn() { // write binary to BCD multiplexer and mux digit
    2.   j = 3;
    3.   for (int i = 0; i <= 3; i++) {
    4.     digitalWrite (dig[i], digMatrix[digOn][j]);  // turn on digit [digOn] and keep the rest low
    5.     digitalWrite (D[i], binMatrix[number][j]); // send data to 4511
    6.     j--;
    7.   }
    8. }
    9.  
    And this is what works:
    Code (Text):
    1. void digitOn() { // write binary to BCD multiplexer and mux digit
    2.   j = 3;
    3.   for (int i = 0; i <= 3; i++) {
    4.     digitalWrite (D[i], binMatrix[number][j]); // send data to 4511
    5.     j--;
    6.   }
    7.  
    8.   j = 3;
    9.   for (int i = 0; i <= 3; i++) {
    10.      digitalWrite (dig[i], digMatrix[digOn][j]);  // turn on digit [digOn] and keep the rest low
    11.     j--;
    12.   }
    13. }
    14.  
    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
     
    ErnieM likes this.
Loading...