Help Multiplexing a 4 Digit Seven Segment Display

I'm working on an Arduino project where I'm attempting to display 4 digits from a serial monitor input to a 4-digit seven segment display based on an input from the serial monitor.... this seems like a very simple project, but my lack of Arduino and coding experience is the problem.

Fast forward...the circuit is wired appropriately and the display is illuminated, I've also written the program code to get my serial input numbers separated into variables and displayed on the 4 digit display successfully where they should be....but they won't stay put.

I'm able to get four digits to display(very rapidly), but the numbers run through their sequence and end at the last one, remaining illuminated on the final digit.

The issue I'm having I believe comes down to multiplexing. I'm aware what multiplexing is, but again my lack of formal experience makes me unsure exactly how to apply it in my code or circuit. Is it as simple as switching the pin modes at HIGH and LOW at a VERY rapid pace? or somehting more complicated?

Here's the complete code I'm working with... please excuse my working mess:

// Global declarations

// shift register pins
const int latchPin = 5;  //74HC595  pin 9 ST_CP
const int clockPin = 6;  //74HC595  pin 10 SH_CP
const int dataPin  = 4;  //74HC595  pin 8 DS

// multi-segment digit select pins
const int digit1Pin = 9;    // segment pin 12
const int digit2Pin = 10;   // segment pin 10
const int digit3Pin = 11;   // segment pin 8
const int digit4Pin = 12;   // segment pin 6 

// digitTable stores the binary patterns for displaying the hexadecimal digits 0-9
byte digitTable[16]={
                             B11111100,   //  0 
                             B01100000,   //  1 
                             B11011010,   //  2
                             B11110010,   //  3
                             B01100110,   //  4
                             B10110110,   //  5
                             B10111110,   //  6   
                             B11100000,   //  7
                             B11111110,   //  8
                             B11100110,   //  9
                             };
                             
//  Declares a variable to store the integer.
   int displayValue;  //  This is the value that will be shown on the multi-digit display.

const byte numChars = 32;
char receivedChars[numChars];
char tempChars[numChars];        // temporary array for use when parsing

      // variables to hold the parsed data
int integer1FromPC = 0;
int integer2FromPC = 0;
int integer3FromPC = 0;
int integer4FromPC = 0;

boolean newData = false;

void setup() 
{
   //  Set pinMode for shift register pins:
  pinMode( latchPin , OUTPUT ); 
  pinMode( clockPin , OUTPUT ); 
  pinMode( dataPin  , OUTPUT ); 
   
  //  Set pinMode for seven segment pins:
  pinMode( digit1Pin , OUTPUT ); 
  pinMode( digit2Pin , OUTPUT );  
  pinMode( digit3Pin , OUTPUT );  
  pinMode( digit4Pin , OUTPUT ); 
      
  //  Setup serial port
  Serial.begin(9600); 
      
  //  Initialize displayValue to 0.
  displayValue = 0;    

  //  Display 0000 at Start
  digitalWrite( latchPin , LOW );
  shiftOut( dataPin , clockPin , LSBFIRST , digitTable[ displayValue ] );  
  digitalWrite( latchPin , HIGH );

  Serial.println("This demo accepts up to 4 integers");
    Serial.println("Enter data in this style < 1, 2, 3, 4 >  ");
    Serial.println();
}

//  Sends binary pattern for 4 digits to the shift register */
void displayDigit1(  byte integer1FromPC,   byte integer2FromPC,  byte integer3FromPC,  byte integer4FromPC)
{
  digitalWrite( latchPin, LOW );
  shiftOut(dataPin , clockPin , LSBFIRST , digitTable[ integer1FromPC ] );
  digitalWrite( latchPin, HIGH); 

  //  Sets digit 1 ON
  digitalWrite( digit1Pin , LOW  );
  digitalWrite( digit2Pin , HIGH );
  digitalWrite( digit3Pin , HIGH );
  digitalWrite( digit4Pin , HIGH ); 
  delay(100);

  digitalWrite( latchPin , LOW );
  shiftOut( dataPin , clockPin , LSBFIRST , digitTable[ integer2FromPC ] );
  digitalWrite( latchPin, HIGH ); 

  //  Sets digit 2 ON
  digitalWrite( digit1Pin , HIGH );
  digitalWrite( digit2Pin , LOW  );
  digitalWrite( digit3Pin , HIGH );
  digitalWrite( digit4Pin , HIGH );
  delay(100);
  
    digitalWrite( latchPin, LOW );
  shiftOut( dataPin , clockPin , LSBFIRST , digitTable[ integer3FromPC ] );
  digitalWrite( latchPin , HIGH ); 

  //  Sets digit 3 ON
  digitalWrite( digit1Pin , HIGH );
  digitalWrite( digit2Pin , HIGH );
  digitalWrite( digit3Pin , LOW  );
  digitalWrite( digit4Pin , HIGH );
  delay(100);

    digitalWrite( latchPin , LOW );
  shiftOut(dataPin , clockPin , LSBFIRST , digitTable[ integer4FromPC ] );
  digitalWrite( latchPin , HIGH ); 
  
  //  Sets digit 4 ON  
  digitalWrite( digit1Pin , HIGH );
  digitalWrite( digit2Pin , HIGH );
  digitalWrite( digit3Pin , HIGH );
  digitalWrite( digit4Pin , LOW  );
  delay(100);
}





void loop() {

  recvWithStartEndMarkers();
    if (newData == true) {
        strcpy(tempChars, receivedChars);
            // this temporary copy is necessary to protect the original data
            //   because strtok() used in parseData() replaces the commas with \0
        parseData();
        showParsedData();
        newData = false;
displayDigit1(integer1FromPC, integer2FromPC, integer3FromPC, integer4FromPC);

}
}


//
void recvWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '<';
    char endMarker = '>';
    char rc;

    while (Serial.available() > 0 && newData == false) {
        rc = Serial.read();

        if (recvInProgress == true) {
            if (rc != endMarker) {
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars) {
                    ndx = numChars - 1;
                }
            }
            else {
                receivedChars[ndx] = '\0'; // terminate the string
                recvInProgress = false;
                ndx = 0;
                newData = true;
            }
        }

        else if (rc == startMarker) {
            recvInProgress = true;
        }
    }
}

//
void parseData() {      // split the data into its parts

    char * strtokIndx; // this is used by strtok() as an index

    strtokIndx = strtok(tempChars, ","); // this continues where the previous call left off
    integer1FromPC = atoi(strtokIndx);     // convert this part to an integer
 
    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    integer2FromPC = atoi(strtokIndx);     // convert this part to an integer

    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    integer3FromPC = atoi(strtokIndx);     // convert this part to an integer

    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    integer4FromPC = atoi(strtokIndx);     // convert this part to an integer
    

    
}

//
void showParsedData() {
    Serial.print("Integer 1: ");
    Serial.println(integer1FromPC);
    Serial.print("Integer 2: ");
    Serial.println(integer2FromPC);
    Serial.print("Integer 3: ");
    Serial.println(integer3FromPC);
    Serial.print("Integer 4: ");
    Serial.println(integer4FromPC);

}

I'm unsure if I need to implement a simple delay like this :

//  Sets digit 1 ON
  digitalWrite( digit1Pin , LOW  );
  digitalWrite( digit2Pin , HIGH );
  digitalWrite( digit3Pin , HIGH );
  digitalWrite( digit4Pin , HIGH ); 
  delay(100);

or something more complicated like a timer or new function to implement in the loop.

Please help me get this display to show all four digits at once! Thank you in advance!

Cute toy.

Better to do it properly - use a MAX7219.

Hey, look you say "the circuit is wired appropriately" but I even doubt that. Fine to play about and learn coding, but if you want to use it for any purpose, you need to use the proper hardware.

Paul__B:
Cute toy.

Isn't it?

I realize there are better options out there, but I am limited to this configuration based on the assignment protocol.

I know it's hokey, but I need to get it working as assigned.

I've been tinkering with the circuit and I'm now able to get all digits to display appropriately, but now it's only displaying the final last digit of my 4 digit number on all digits of the display.

The code I'm using to get all digits to display is:

//  Sends binary pattern for 4 digits to the shift register */
void displayDigit1(  byte integer1FromPC,   byte integer2FromPC,  byte integer3FromPC,  byte integer4FromPC)
{


  //  Sets digit 1 ON
  digitalWrite( digit1Pin , LOW );
  digitalWrite( latchPin, LOW );
  shiftOut(dataPin , clockPin , LSBFIRST , digitTable[ integer1FromPC ] );
  digitalWrite( latchPin, HIGH);
  Serial.print(integer1FromPC);

  digitalWrite( digit2Pin , LOW );
    digitalWrite( latchPin , LOW );
  shiftOut( dataPin , clockPin , LSBFIRST , digitTable[ integer2FromPC ] );
  digitalWrite( latchPin, HIGH );
  Serial.print(integer2FromPC);
  
  digitalWrite( digit3Pin , LOW );
   digitalWrite( latchPin, LOW );
  shiftOut( dataPin , clockPin , LSBFIRST , digitTable[ integer3FromPC ] );
  digitalWrite( latchPin , HIGH ); 
  Serial.print(integer3FromPC);
  
  digitalWrite( digit4Pin , LOW ); 
  digitalWrite( latchPin , LOW );
  shiftOut(dataPin , clockPin , LSBFIRST , digitTable[ integer4FromPC ] );
  digitalWrite( latchPin , HIGH ); 
  Serial.print(integer4FromPC);
}

Any ideas how I can get each individual number from a four-digit number to appear on the display at each digit?

Got it! Now to make it look purty!

COMediSun:
Got it! Now to make it look purty!

Glad to hear you have solved it.

Without any details of what you have wired up, or how you have presently coded it, we naturally cannot help you with it.

recvWithStartEndMarkers() seems to be blocking on unfinished data. This prevents displayDigit1() from updating the display. I think sending data with an ending line break might be unfinished data.

I think you have 3 options:

  • use a max7219
  • make recvWithStartEndMarkers() non-blocking
  • rewrite displayDigit1() to use timer interrputs