This week we go through multiplexing.  Bob gives us a presentation that he gave last weekend on how multiplexing works and how to use an arduino timer to help with the multiplexing.

Downloads

HD Apple HD Apple SD Audio MP3

Display used: http://www.mouser.com/ds/2/216/PDA54-11SRWA-53450.pdf

Maxim MAX6971 chip:  http://www.mouser.com/ds/2/256/MAX6971-90327.pdf

Transistors w/ 1kohm resistors:  v
http://www.mouser.com/ds/2/308/MPS2222-D-111462.pdf

Demo code:

/**************************************************************
 Name      MAX6971_nleds_1_0_0_14segment_multiplex                                 Author    Bob Powell
           texanfromiowa@gmail.com           Copyright (C) 2012-2013, Parallelus Automation, Inc.
 Date      June 20, 2013     Modified  July 22, 2013                                 Version   1.0.0       Arduino   1.0.5
 Notes     
Legal Stuff:============
           This program is free software: you can redistribute it and/or modify           it under the terms of the GNU General Public License as published by           the Free Software Foundation, either version 3 of the License, or           at your option, any later version.
           This program is distributed in the hope that it will be useful,           but WITHOUT ANY WARRANTY; without even the implied warranty of           MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           GNU General Public License for more details.
           You should have received a copy of the GNU General Public License           along with this program.  If not, see <http://www.gnu.org/licenses/>.
Personal note:==============
           If you do something interesting with this code, expand it, or just           have a question, please email me at the address above.  
           I hope you find this example helpful.  Enjoy.
           Bob
****************************************************************/
// Switched to the Shifter library.  This allows for "n" number// shift registers to be used without significant changes to the// code.  For help in adding libraries to the Arduino IDE, go here:// http://www.arduino.cc/en/Hacking/Libraries// This library was obtained from: http://bildr.org/2011/08/74hc595-breakout-arduino///// The short version of installing a library it to, first, download the library// (link above).  They usually download as a zip file, so unzip the file which// will usually create a directory of the libraries contents.  Third, put this// directory into the "libraries" directory of your Arduino IDE (Integrated// Design Enviroment) software.  In a typical Windows installation, the Arduino// IDE executable file is located at: c:\Program Files\Arduino\Arduino.exe// There is a directory called:  c:\Program Files\Arduino\libraries// The Shifter\ directory will go into this libraries directory.// For a Mac, this directory is typically located at://   /Applications/Arduino.app/Contents/Resources/Java/libraries// If you have trouble, see the link above for complete instruction from Arduino// You will need to restart the Arduino IDE for it to realize that this// library is present.  Once you have installed the library and restarted the// IDE, this line tells the compilier to include it:#include <Shifter.h>#include <TimerOne.h>
// THESE VARIABLES CHANGE.// Set the number of leds your using and the number of shift registers used.// The Shifter library assumes one register = 8 bits.  With this in mind,  // NUM_LED can never be greater that NUM_REG x 8 bits.const int NUM_LED = 15;      // number of ledsconst int NUM_REG = 2;       // number of shift registersconst int NUM_DIGIT = 4;     // number of digits
// Set variables - Global variables, except for the Arduino// pins, are CAPITALIZED.  This makes identification of local and// global variables easy to understand.  The compilier is case sensitive// so it understands capitalized and lower case letters.
// These variables are too make things a little easier for humans to read.// The "const" sets the variable so it cannot be changed// later in the program (ie. make them constants).  The standard// constants "true" and "false" function just as well as these.const bool OFF = 0;const bool ON = 1;
const int latchPin = 13;const int clockPin = 11;const int dataPin = 12;const int pwmPin = 10;
const int npn4 = 5;const int npn3 = 4;const int npn2 = 3;const int npn1 = 2;int DIR = MSBFIRST;int DIGITS = OFF;int TIMER, MSDELAY;
// Set up the shifter object used to send data to the registers.Shifter shifter(dataPin, latchPin, clockPin, NUM_REG);
// Set up the array of leds that is used throughout the programbool LED[NUM_LED];    const int NUM_DIGITS = 4;bool DIGIT[NUM_DIGITS][NUM_LED];int DIGIT_TRANSISTOR[] = {npn1, npn2, npn3, npn4};//int DIGIT_TRANSISTOR[] = {npn4, npn3, npn2, npn1};
/*  Added constants for a 14 segment, common cathode single digit   alphanumeric display.  In this example, a PDC54-11GWA was used.   The datasheet can be found at:http://www.mouser.com/ds/2/216/PDC54-11GWA-57682.pdf
   The 2 shift register is connected as:
   Qa = Anode A   Qb = Anode B   Qc = Anode C   Qd = Anode D   Qe = Anode E   Qf = Anode F   Qg = Anode G   Qh = Anode D.P. (decimal point)
   This quick example is for a single LED display with a single 74HC595.   The same basic idea applies for multiple LED's and displays.
*/
 const int SEGA = 1; const int SEGB = 2; const int SEGC = 4; const int SEGD = 8; const int SEGE = 16; const int SEGF = 32; const int SEGG = 64; const int SEGH = 128; // no I const int SEGJ = 256; const int SEGK = 512; const int SEGL = 1024; const int SEGM = 2048; const int SEGN = 4096; // no O const int SEGP = 8192; const int SEGDP = 16384;
 const int NUM0 = SEGA + SEGB + SEGC + SEGD + SEGE + SEGF + SEGJ + SEGN; const int NUM1 = SEGB + SEGC; const int NUM2 = SEGA + SEGB +  + SEGD + SEGE + SEGK + SEGP; const int NUM3 = SEGA + SEGB + SEGC + SEGD + SEGK + SEGP; const int NUM4 = SEGB + SEGC + SEGF + SEGK + SEGP; const int NUM5 = SEGA + SEGC + SEGD + SEGF + SEGK + SEGP; const int NUM6 = SEGA + SEGC + SEGD + SEGE + SEGF + SEGK + SEGP; const int NUM7 = SEGA + SEGB + SEGC; const int NUM8 = SEGA + SEGB + SEGC + SEGD + SEGE + SEGF + SEGK + SEGP; const int NUM9 = SEGA + SEGB + SEGC + SEGD + SEGF + SEGK + SEGP;
 //const int LETA = SEGA + SEGB + SEGC + SEGD + SEGE + SEGF + SEGG + SEGH + SEGJ + SEGK + SEGL + SEGM + SEGN + SEGP; const int LETA = SEGA + SEGB + SEGC + SEGE + SEGF + SEGK + SEGP; const int LETB = SEGA + SEGB + SEGC + SEGD + SEGE + SEGF + SEGK; const int LETC = SEGA + SEGD + SEGE + SEGF; const int LETD = SEGA + SEGB + SEGC + SEGD + SEGH + SEGM; const int LETE = SEGA + SEGD + SEGE + SEGF + SEGP; const int LETF = SEGA + SEGE + SEGF + SEGP; const int LETG = SEGA + SEGC + SEGD + SEGE + SEGF + SEGK; const int LETH = SEGB + SEGC + SEGE + SEGF + SEGK + SEGP; const int LETI = SEGA + SEGD + SEGH + SEGM; const int LETJ = SEGB + SEGC + SEGD + SEGE; const int LETK = SEGE + SEGF + SEGJ + SEGL; const int LETL = SEGD + SEGE + SEGF ; const int LETM = SEGB + SEGC + SEGE + SEGF + SEGG + SEGJ ; const int LETN = SEGB + SEGC + SEGE + SEGF + SEGG + SEGL; const int LETO = SEGA + SEGB + SEGC + SEGD + SEGE + SEGF; const int LETP = SEGA + SEGB + SEGE + SEGF + SEGK + SEGP; const int LETQ = SEGA + SEGB + SEGC + SEGD + SEGE + SEGF + SEGL; const int LETR = SEGA + SEGB + SEGE + SEGF + SEGK + SEGL + SEGP; const int LETS = SEGA + SEGD + SEGG + SEGL; const int LETT = SEGA + SEGH + SEGM; const int LETU = SEGB + SEGC + SEGD + SEGE + SEGF; const int LETV = SEGE + SEGF + SEGJ + SEGN; const int LETW = SEGB + SEGC + SEGE + SEGF + SEGH + SEGL + SEGN; const int LETX = SEGG + SEGJ + SEGL + SEGN; const int LETY = SEGG + SEGJ + SEGM; const int LETZ = SEGA + SEGD + SEGJ + SEGN; const int SPACE = 0; const int APOS = SEGJ; const int COMMA = SEGN; const int PERIOD = SEGDP;
 int SEGMENTS[] = {SEGA, SEGB, SEGC, SEGD, SEGE, SEGF, SEGG, SEGH, SEGJ, SEGK, SEGL, SEGM, SEGN, SEGDP}; int NUMBERS[] = {NUM0, NUM1, NUM2, NUM3, NUM4 , NUM5, NUM6, NUM7, NUM8, NUM9}; int LETTERS[] = {LETA, LETB , LETC, LETD, LETE, LETF, LETG, LETH, LETI, LETJ, LETK, LETL,LETM, LETN, LETO, LETP, LETQ, LETR, LETS, LETT, LETU, LETV, LETW, LETX, LETY, LETZ, SPACE};
/**************************************************************Function: setupPurpose:  set up ArduinoArgs:     noneReturns:  nothingNotes:    This function is required by the Arduino***************************************************************/void setup() {
 // Set timer delay, in microseconds //  .1 sec or 100000 = 10Hz = 1/.1 //  .01 sec or 10000 = 100Hz = 1/.01 //  .004 sec or 4000 = 250Hz = 1/.004   //  .002 sec or 2000 = 500Hz = 1/.002 //  Running the Timer1 faster that 250Hz is not recommended and could result in //  code that does not function. TIMER = 4000; MSDELAY = 150; Timer1.initialize(TIMER); Timer1.attachInterrupt( outBytes );
 //Serial.begin(115200); //Serial.println("Started");
 // Set up the output pins. pinMode(latchPin, OUTPUT); pinMode(clockPin, OUTPUT); pinMode(dataPin, OUTPUT); pinMode(npn1, OUTPUT); pinMode(npn2, OUTPUT); pinMode(npn3, OUTPUT); pinMode(npn4, OUTPUT); pinMode(pwmPin, OUTPUT); analogWrite(pwmPin, 0);
 digitalWrite(npn1, LOW); digitalWrite(npn2, LOW); digitalWrite(npn3, LOW); digitalWrite(npn4, LOW);
 // Set up the shifter output shifter.clear(); shifter.write();
 // turn off all the LEDS, just in case allOff(); writeBytes();
}  // End of Arduino Setup
/**************************************************************Function: loopPurpose:  loop funtion for ArduinoArgs:     noneReturns:  nothingNotes:    This function is required by the Arduino, and the         Arduino will loop through this function indefinately.***************************************************************/void loop() {
/*****  See detailed descriptions for each funcion below  *****///  //  Most of these functions follow the same basic principle.//  A duration is selected for how long each led should be on,//  a repeat count is selected, and how many leds are to be on//  at once is selected.  
//  For example, flashAll(500, 3) tells the function to turn on//  all leds for 1/2 a second, then off 1/2 a second.  The do this//  3 times.//  //  Again:/*****  See detailed descriptions for each funcion below  *****/
 // Set a standard delay between each effect int loopDelay = 2000;   // Flash all leds, to let us know its on flashAll(250, 3); delay(loopDelay);
//  multipexExamples();//  allOff();//  writeDigitBytes();//  delay(2000);
 // 14 segment display tests fourteenSegmentTests(); delay(loopDelay);
}  // End of Arduino Loop
void multipexExamples(){
 int demoTimes[] = {1,2,3,5,10,20,25,30,50,100}; int demotimescount = 10; int cyclecount, loopdelay; int totalDelay = 2000; //char buf[256];
 for(int i = 0; i < demotimescount; i++){
   cyclecount = (demoTimes[i] * (totalDelay/1000));   loopdelay = 333/demoTimes[i];
   for(int j = 0; j < cyclecount; j++){
     setDigitArray(0, NUMBERS[demoTimes[i]%10]);     writeDigitBytes();     sdelay(loopdelay);     setDigitArray(0, SPACE);
     setDigitArray(1, NUMBERS[(demoTimes[i]/10)%10]);     writeDigitBytes();     sdelay(loopdelay);     setDigitArray(1, SPACE);
     setDigitArray(2, NUMBERS[(demoTimes[i]/100)%10]);     writeDigitBytes();     sdelay(loopdelay);     setDigitArray(2, SPACE);
   }      }}
void fourteenSegmentTests(){ int loopDelay = 2000;   int j = 0;
 allOff();
 //setDigitString(250, "Bob was here."); //sdelay(loopDelay);
 int segsequence[] = {SEGA, SEGB, SEGC, SEGD, SEGE, SEGF, SEGG, SEGH, SEGJ, SEGK, SEGL, SEGM, SEGN, SEGP, SEGDP}; for(int i = 0; i <15;i++ ){   setArray(segsequence[i]);   writeBytes();   sdelay(150);   }
 allOff(); writeBytes(); sdelay(loopDelay);
//==========================================================
 setDigitString(100, "As seen on Lets Make It -- www.letsmakeit.tv"); sdelay(loopDelay);
 setDigitString(75, "abcdefghijklmnopqrstuvwxyz 1234567890 . -"); sdelay(loopDelay);
//==========================================================
 int clockSequence[] = {SEGH, SEGJ, SEGK, SEGL, SEGM, SEGN, SEGP, SEGG};
 //  Digits are 3-2-1-0    // Cycle through loop once    for(int m = 0; m < 1; m++){   // digit 3 - Commented out for this demo   for(int l = 0; l < 8; l++){     setDigitArray(3, clockSequence[l]);
     // Digit 2     for(int k = 0; k < 8; k++){   
       setDigitArray(2, clockSequence[k]);
       // Digit 1       for(int i = 0; i < 8; i++){
         setDigitArray(1, clockSequence[i]);
           // Digit 0           for(int j = 0; j < 8; j++){             setDigitArray(0, clockSequence[j]);             writeDigitBytes();             sdelay(2);           }      
       }     }   }   // Set the end back to initial position   setDigitArray(0, clockSequence[0]);   setDigitArray(1, clockSequence[0]);   setDigitArray(2, clockSequence[0]);   setDigitArray(3, clockSequence[0]);   writeDigitBytes(); }
 sdelay(loopDelay/4); allOff(); writeBytes();
 sdelay(loopDelay);
//==========================================================// count up then down
 for(int i = 0; i <= 2000; i++){   setNumber(i);   sdelay(2);    } delay(loopDelay/2);
 allOff(); writeBytes(); //delay(loopDelay/2); for(int i = 99; i >= 0; i--){   setNumber(i);   sdelay(50);     } sdelay(500); allOff(); writeBytes(); sdelay(loopDelay);
}
/**************************************************************Function: setNumberPurpose:  Set a number into the displayArgs:     int num - number to displayReturns:  nothingNotes:    Sets a number on the display.  THis is hard coded         for 4 digits and should be controlled by the         NUM_DIGITS variable.***************************************************************/void setNumber(int num){
 allOff(); setDigitArray(0, NUMBERS[num%10]); if(num >= 10)    setDigitArray(1, NUMBERS[(num/10)%10]); if(num >= 100)    setDigitArray(2, NUMBERS[(num/100)%10]); if(num >= 1000)    setDigitArray(3, NUMBERS[(num/1000)%10]); writeDigitBytes();
}
/**************************************************************Function: setDigitStringPurpose:  Send a string to the displayArgs:     int duration - how long an led is on         char* buffer - string to displayReturns:  nothingNotes:    I had to write this fast and hard coded it for         4 digits.  This should be in a loop that is         controlled by NUM_DIGITS variable.  Sorry.***************************************************************/void setDigitString(int delayTime, char* buffer){
 int bufferLength = strlen(buffer); int i;
 for(i = 0; i < bufferLength; i++){
   setDigitArray(0, getLetterInt(buffer[i]));
   if(i == 0){     setDigitArray(1, SPACE);     setDigitArray(2, SPACE);     setDigitArray(3, SPACE);   }else if(i == 1){     setDigitArray(1, getLetterInt(buffer[i-1]));     setDigitArray(2, SPACE);     setDigitArray(3, SPACE);   } else if(i == 2){     setDigitArray(1, getLetterInt(buffer[i-1]));     setDigitArray(2, getLetterInt(buffer[i-2]));     setDigitArray(3, SPACE);   }  else {     setDigitArray(1, getLetterInt(buffer[i-1]));     setDigitArray(2, getLetterInt(buffer[i-2]));     setDigitArray(3, getLetterInt(buffer[i-3]));   }   writeDigitBytes();   sdelay(delayTime);   }
   setDigitArray(0, SPACE);   setDigitArray(1, getLetterInt(buffer[i-1]));   setDigitArray(2, getLetterInt(buffer[i-2]));   setDigitArray(3, getLetterInt(buffer[i-3]));   writeDigitBytes();   sdelay(delayTime);
   setDigitArray(0, SPACE);   setDigitArray(1, SPACE);   setDigitArray(2, getLetterInt(buffer[i-1]));   setDigitArray(3, getLetterInt(buffer[i-2]));   writeDigitBytes();   sdelay(delayTime);
   setDigitArray(0, SPACE);   setDigitArray(1, SPACE);   setDigitArray(2, SPACE);   setDigitArray(3, getLetterInt(buffer[i-1]));   writeDigitBytes();   sdelay(delayTime);
 allOff(); writeBytes(); sdelay(delayTime);
}
/**************************************************************Function: getLetterIntPurpose:  Converts an alphanumeric string to a number codeArgs:     int letter - letter to returnReturns:  int of the characters valueNotes:    Not all alphanumeric characters are supported***************************************************************/int getLetterInt(int letter){
 switch (letter) {
   case '0':     return NUM0;   case '1':     return NUM1;   case '2':     return NUM2;   case '3':     return NUM3;   case '4':     return NUM4;   case '5':     return NUM5;   case '6':     return NUM6;   case '7':     return NUM7;   case '8':     return NUM8;   case '9':     return NUM9;   case 'A':   case 'a':     return LETA;   case 'B':   case 'b':     return LETB;   case 'C':   case 'c':     return LETC;   case 'D':   case 'd':     return LETD;   case 'E':   case 'e':     return LETE;   case 'F':   case 'f':     return LETF;   case 'G':   case 'g':     return LETG;   case 'H':   case 'h':     return LETH;   case 'I':   case 'i':     return LETI;   case 'J':   case 'j':     return LETJ;   case 'K':   case 'k':     return LETK;   case 'L':   case 'l':     return LETL;   case 'M':   case 'm':     return LETM;   case 'N':   case 'n':     return LETN;   case 'O':   case 'o':     return LETO;   case 'P':   case 'p':     return LETP;   case 'Q':   case 'q':     return LETQ;   case 'R':   case 'r':     return LETR;   case 'S':   case 's':     return LETS;   case 'T':   case 't':     return LETT;   case 'U':   case 'u':     return LETU;   case 'V':   case 'v':     return LETV;   case 'W':   case 'w':     return LETW;   case 'X':   case 'x':     return LETX;   case 'Y':   case 'y':     return LETY;   case 'Z':   case 'z':     return LETZ;   case '.':     return SEGDP;   case '-':     return SEGK + SEGP;
   default:     return SPACE;
 }
}
/**************************************************************Function: flashAllPurpose:  Flashes all ledsArgs:     int duration - how long an led is on         int count - how many times to flashReturns:  nothingNotes:    ***************************************************************/void flashAll(int duration, int count){ for(int i = 0; i < count; i++){   allOn();     writeBytes();     delay(duration);   allOff();   writeBytes();     delay(duration); }  
}  
/**************************************************************Function: countUpPurpose:  Count up, in binary, from one number to anotherArgs:     int duration - how long an led is on         int startNum - starting number         int endNum - ending number         bool reverse - true or false - a value of true                      - reverses the normal directionReturns:  nothingNotes:    **************************************************************/void countUp(int startNum, int endNum, int duration, bool reverse){// Clear the array and turns off any leds still onallOff();
if((endNum <= startNum) || (endNum < 0))   return;
 for (int numberToDisplay = startNum; numberToDisplay <= endNum; numberToDisplay++) {
   setArray(numberToDisplay);   if(reverse == true){     writeBytesRev();   }   else{     writeBytes();   }   delay(duration); }
 allOff(); writeBytes();
}
/**************************************************************Function: countDownPurpose:  Count down, in binary, from one number to anotherArgs:     int duration - how long an led is on         int startNum - starting number         int endNum - ending number         bool reverse - true or false - a value of true                      - reverses the normal directionReturns:  nothingNotes:    **************************************************************/void countDown(int startNum, int endNum, int duration, bool reverse){// Clear the array and turns off any leds still onallOff();
if(endNum >= startNum)   return;
 for (int numberToDisplay = startNum; numberToDisplay > endNum; numberToDisplay--){   setArray(numberToDisplay);
   if(reverse == true)     writeBytesRev();   else     writeBytes();
   delay(duration); }
 // turn off the last led allOff(); writeBytes();}  
/**************************************************************Function: sumArrayPurpose:  Take a binary representation of the array of ON and OFF         positions, and generates an integer.Args:     int array[]Returns:  integer of the totalNotes:    See comments on bit shifting at the beginning         of this file.**************************************************************/  int sumArray(bool array[]){  int total = 0;
  for (int i = 0; i < NUM_LED; i++){    if (array[i] == ON)     total = total + (1<<i);  }
  return(total);}
/**************************************************************Function: setArrayPurpose:  Sets the primary array to the binary of the number         given.Args:     int num - number to put into arrayReturns:  nothingNotes:    See comments on bit shifting at the beginning         of this file.  Since this is an integer, it must be         between -32,768 and 32,767, HOWEVER, it should         always be a positive number (0 to 32,767).**************************************************************/  void setArray(int num){ // Clear the array allOff(); int i = -1; bool value;
 while (num > 0){    value = num & 1;    if(value == true)      LED[i] = ON;    else      LED[i] = OFF;
    num >>= 1;    i++;  }  }
void setDigitArray(int digit, int num){
 bool value;
  for(int i = 0; i < NUM_LED; i++){   DIGIT[digit][i] = ON;    value = num & 1;    if(value == 1)      DIGIT[digit][i] = ON;    else      DIGIT[digit][i] = OFF;   num >>= 1; }  }
/**************************************************************Function: allOnPurpose:  Turns ON all ledsArgs:     noneReturns:  noneNotes:    **************************************************************/  void allOn(){  for (int i = 0; i < NUM_LED; i++)  {    LED[i] = ON;  }}
/**************************************************************Function: allOffPurpose:  Turns OFF all ledsArgs:     noneReturns:  noneNotes:    **************************************************************/  void allOff(){  for (int i = 0; i < NUM_LED; i++)  {    LED[i] = OFF;  }}
  for(int i = 0; i < NUM_DIGITS; i++)    for(int k = 0; k < NUM_LED; k++)      DIGIT[i][k] = OFF;}
/**************************************************************Function: sdelayPurpose:  delay function that accounts for timer interuptsArgs:     int msec - number of milliseconds of delayReturns:  noneNotes:    This function was created because while testing,         timer interupts were effecting the delays.**************************************************************/void sdelay(int msec){ if(msec > 15){   long time = millis();   long delaytime = time + msec;   long timenow = millis();
   while(timenow <= delaytime)     timenow = millis(); } else{   msec = msec * 1000;  
   long time = micros();   long delaytime = time + msec;   long timenow = micros();
   while(timenow <= delaytime)     timenow = micros(); }}
/**************************************************************Function: writeBitsPurpose:  Write the array with Most Significant Bit first (MSFBFIRST)Args:     noneReturns:  nothingNotes:    This function is a wrapper function for outBytes()***************************************************************/void writeBytes(){ DIR = MSBFIRST; DIGITS = OFF;}void writeBytesRev(){ DIR = MSBFIRST; DIGITS = OFF;}/**************************************************************Function: writeDigitBytesPurpose:  Write the array with Least Significant Bit first (MSFBFIRST)Args:     noneReturns:  nothingNotes:    This function is a wrapper function for outBytes()***************************************************************/void writeDigitBytes(){ DIR = MSBFIRST; DIGITS = ON;}void writeDigitBytesRev(){ DIR = MSBFIRST; DIGITS = ON;}
/**************************************************************Function: outBytesPurpose:  Send array data to shift registerArgs:     noneReturns:  nothingNotes:    This is where data is actually sent out, but is not         intended to be used directly, but by the interupt.***************************************************************/void outBytes(){  int dir = DIR;
 //  Set each digit one by one if(DIGITS == ON){   
   for(int i = 0; i < NUM_DIGITS; i++){
     digitalWrite(latchPin, LOW);
     //digitalWrite(DIGIT_TRANSISTOR[i], HIGH);
     // most significant bit first     if(dir == MSBFIRST){              for(int j = 0; j < NUM_LED;j++){         if(DIGIT[i][j] == ON)           shifter.setPin(j, HIGH);         else           shifter.setPin(j, LOW);       }    }     // least significant bit first - reverses what is in LED[]     else if(dir == LSBFIRST){       int k = 0;       for(int j = NUM_LED - 1; j > -1;j--){
         if(DIGIT[i][j] == ON){           shifter.setPin(k, HIGH);         }           else{           shifter.setPin(k, LOW);         }                 k++;         }    }   
    // Write the data to the registers    shifter.write();    // set the latch high to turn on the output    digitalWrite(latchPin, HIGH);
    digitalWrite(DIGIT_TRANSISTOR[i], HIGH);    delayMicroseconds(MSDELAY);    digitalWrite(DIGIT_TRANSISTOR[i], LOW);    }  }  // end DIGIT == ON
  //  All digits show the same data  else{  // DIGIT = OFF
    // most significant bit first    if(dir == MSBFIRST){
      for(int i = 0; i < sizeof(LED);i++){       if(LED[i] == ON)         shifter.setPin(i, HIGH);       else         shifter.setPin(i, LOW);      }    }     // least significant bit first - reverses what is in LED[]    else if(dir == LSBFIRST){      int j = 0;      for(int i = sizeof(LED) - 1; i > -1;i--){        if(LED[i] == ON){          shifter.setPin(j, HIGH);        }          else{          shifter.setPin(j, LOW);        }                j++;        }    }   
    // Write the data to the registers    shifter.write();    // set the latch high to turn on the output    digitalWrite(latchPin, HIGH);
    for(int i = 0; i < NUM_DIGITS; i++){      digitalWrite(DIGIT_TRANSISTOR[i], HIGH);      delayMicroseconds(MSDELAY);      digitalWrite(DIGIT_TRANSISTOR[i], LOW);    }  
  }
}
//  End of program