[SOLVED] 74HC595 not displaying proper digits past "7"?

Hello:

I'm working with a bit of code that I found earlier trying to drive a single 7 segment display with a 74HC595 using some code that the forum user "Spiked Cola" mentioned in the forum post http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1247631566.

I have modified the array to contain the decimal values of the segments I want to light up and it appears to work but only for a couple of iterations before the LED display becomes corrupted (pixels don't light as expected or unexpected pixels light). I'm not entirely sure why this is not working. The general idea is that the code should be able to display 0 through 9 and loop indefinitely.

Admittedly, I'm still learning this code and am not sure if I'm doing the shift out properly. Please feel free to advise if I've messed up something somewhere.

Thank you.

//**************************************************************//
//  Name    : shiftOutCode, Predefined Array Style              //
//  Author  : Carlyn Maw, Tom Igoe                           //
//  Date    : 25 Oct, 2006                                      //
//  Version : 1.0                                               //
//  Notes   : Code for using a 74HC595 Shift Register           //
//          : to count from 0 to 255                            //
//****************************************************************

//
//  This code is modified from it's original design by FIRESTORM_v1
//  to store the predefined pixels to light in a byte array.

//Pin connected to ST_CP of 74HC595
int latchPin = 8;
//Pin connected to SH_CP of 74HC595
int clockPin = 12;
////Pin connected to DS of 74HC595
int dataPin = 11;

//holders for infromation you're going to pass to shifting function
byte data;
byte dataArray[8];

void setup() {
  //set pins to output because they are addressed in the main loop
  pinMode(latchPin, OUTPUT);
  Serial.begin(9600);

/*
   The seven segment display is set up as follows:
       A
     #####
 F #       #  B
   #   G   #
     #####
 E #       #  C
   #       #
     #####
      D
 
 Each element is attached to the output pun of the 74HC595, A to Q1, B to Q2, C to 
 Q3 and so on.. That being said, each element also has a decimal value assigned to
 it for the purpose of calculating the decimal version of the needed byte to turn on
 that segment and is computed below:
 
  #  segments      Byte values =   Decimal Values
  1  B,C           2, 4            = 6
  2  A,B,D,E,G     1,2,8,16,64     = 91
  3  A,B,C,D,G     1,2,4,8,64      = 79
  4  B,C,F,G       2,4,32,64       = 102
  5  A,C,D,F,G     1,4,8,32,64     = 109
  6  A,C,D,E,F,G   1,4,8,16,32,64  = 125
  7  A,B,C         1,2,4           = 7
  8  A,B,C,D,E,F,G 1,2,4,8,16,32,64= 127
  9  A,B,C,D,F,G   1,2,4,8,32,64   = 111
  0  A,B,C,D,E,F   1,2,4,8,16,32   = 63

 These values are stored in an array with the index set to the number that should
 appear on the seven segment LED display.
 */

  dataArray[0] = 63; 
  dataArray[1] = 6; 
  dataArray[2] = 91; 
  dataArray[3] = 79; 
  dataArray[4] = 102; 
  dataArray[5] = 109; 
  dataArray[6] = 125; 
  dataArray[7] = 7; 
  dataArray[8] = 127;
  dataArray[9] = 111;
}

void loop() {
  // This loop will run indefinitely, counting from 0 to 9 and
  // displays 0 through 9 on the seven segment LED display.
    
  for (int j = 0; j < 10; j++) {
    //load the light sequence you want from array
    data = dataArray[j];
    //ground latchPin and hold low for as long as you are transmitting
    digitalWrite(latchPin, 0);
    //move 'em out
    shiftOut(dataPin, clockPin, data);  
    //return the latch pin high to signal chip that it
    //no longer needs to listen for information
    digitalWrite(latchPin, 1);
    delay(1000);
  }
}



// the heart of the program
void shiftOut(int myDataPin, int myClockPin, byte myDataOut) {
  // This shifts 8 bits out MSB first,
  //on the rising edge of the clock,
  //clock idles low

  //internal function setup
  int i=0;
  int pinState;
  pinMode(myClockPin, OUTPUT);
  pinMode(myDataPin, OUTPUT);
  //clear everything out just in case to
  //prepare shift register for bit shifting
  digitalWrite(myDataPin, 0);
  digitalWrite(myClockPin, 0);

  //for each bit in the byte myDataOut
  //NOTICE THAT WE ARE COUNTING DOWN in our for loop
  //This means that %00000001 or "1" will go through such
  //that it will be pin Q0 that lights.
  for (i=7; i>=0; i--)  {
    digitalWrite(myClockPin, 0);

    //if the value passed to myDataOut and a bitmask result
    // true then... so if we are at i=6 and our value is
    // %11010100 it would the code compares it to %01000000
    // and proceeds to set pinState to 1.
    if ( myDataOut & (1<<i) ) {
      pinState= 1;
    }
    else {
      pinState= 0;
    }

    //Sets the pin to HIGH or LOW depending on pinState
    digitalWrite(myDataPin, pinState);
    //register shifts bits on upstroke of clock pin  
    digitalWrite(myClockPin, 1);
    //zero the data pin after shift to prevent bleed through
    digitalWrite(myDataPin, 0);
  }

  //stop shifting
  digitalWrite(myClockPin, 0);
}

First question, why have you reinvented shiftout()?


Rob

Rob:

Because I don't know any better. (Seriously). I tried researching this on my own and kept coming back to this code. Additionally, shiftout reinvention or not, I did finally get the fix I was looking for, the issue was that I was reading past the end of my array. I had dataArray[8] defined in my variable declaration but there are 10 elements defined in my array which meant the other two got assigned to the ether instead of being defined properly.

Is there a place where I can pick up an "Arduino code for n00bs" book? I know programming, but I don't know C programming (as is evident here) nor am I familiar with the arduino-specific instructions. Do you know of any books (physical media preferred) that contain a newbie's guide to arduino programming that demonstrate the function set of the language with a practical circuit/code example? I've used microcontrollers before, namely a few from Parallax's line, but they came with a lot of documentation and examples that I'm not finding here or as you pointed out, really old and outdated code that leaves me reinventing the wheel.

Thank you.

For any other newbies trying their hand at 74HC595, take a look at my revised code (with instructions)

/*
74HC595 7 segment LED driver example code
by FIRESTORM_v1 on 9/19/11
*/

// Declare our pins
int latchPin = 4; // Connected to LATCH on 74HC595 (12)
int clockPin = 3; // Connected to CLK on 74HC595   (11)
int dataPin = 2;  // Connected to DATA on 74HC595  (14)

//Declare our variables
byte dataArray[10]; // there are 10 elements in our array, 0-9
byte interval = 0;  // Interval counter for loop.

void setup() {
  // Our pins are OUTPUT only.
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  
  // Previously calculated values to light the seven segment display
  // to form the number of the index value.  Read the end of the code for more details
  // on how this information was collected.
  dataArray[0] = 63; 
  dataArray[1] = 6; 
  dataArray[2] = 91; 
  dataArray[3] = 79; 
  dataArray[4] = 102; 
  dataArray[5] = 109; 
  dataArray[6] = 125; 
  dataArray[7] = 7; 
  dataArray[8] = 127;
  dataArray[9] = 111;
  
}

void loop () {
  // This loop will count from 0 to 9, read the array element at that index then use SHIFTOUT to send
  // the data to the 74HC595 which will display the desired number.
  
  for(interval = 0; interval < 10; interval++) {
    
    // set Latch low during shiftout so the 74HC595 will receive properly
    digitalWrite(latchPin, LOW);
    
    // Shift out the contents of of the dataArray element at the interval index.
    // shiftOut can do either least significant bit first
    // or most significant bit first.  The 74HC595 requires MSB First.  
    shiftOut(dataPin, clockPin, MSBFIRST, dataArray[interval]);

    //Done transmitting, setting latchPin high again.
    digitalWrite(latchPin, HIGH);

    //Sleep 1 second
    delay(1000);
  }
}

/*  HOW TO CALCULATE VALUES FOR THE DATA TABLE

   A typical seven segment display is set up as follows:
   
       A
     #####
 F #       #  B
   #   G   #
     #####
 E #       #  C
   #       #
     #####
      D
 
 Each element is attached to the output pin of the 74HC595, A to Q1, B to Q2, C to 
 Q3 and so on. That being said, each element also has a binary value assigned to it
 that will cause the respective output on the 74HC595 to turn on. Instead of writing it
 in binary, I stored them in decimal format, and just added the values of all the segments
 that I wanted to turn on.  
 
 Seg  Binary Value    Decimal Value
 A    00000001        1
 B    00000010        2
 C    00000100        4
 D    00001000        8
 E    00010000        16
 F    00100000        32
 G    01000000        64

So, in order to get the numbers, it was only necessary to add up the decimal values of the segments
I wanted to light up.  
 
  #  segments      Byte values =   Decimal Values
  0  A,B,C,D,E,F   1,2,4,8,16,32   = 63
  1  B,C           2, 4            = 6
  2  A,B,D,E,G     1,2,8,16,64     = 91
  3  A,B,C,D,G     1,2,4,8,64      = 79
  4  B,C,F,G       2,4,32,64       = 102
  5  A,C,D,F,G     1,4,8,32,64     = 109
  6  A,C,D,E,F,G   1,4,8,16,32,64  = 125
  7  A,B,C         1,2,4           = 7
  8  A,B,C,D,E,F,G 1,2,4,8,16,32,64= 127
  9  A,B,C,D,F,G   1,2,4,8,32,64   = 111

 These values are stored in an array with the index set to the number that should
 appear on the seven segment LED display. If I read dataArray[0], I will get the decimal value of the
 bits needed to send to the 74HC595 to turn the respective segments to show a 0.
 
 If you wanted to, you could calculate additional patterns into the array and include the decimal point
 however for the sake of length, I didn't do that here.  Hint:  The Decimal Point requires decimal value
 of 128. 
 */

He he, I should have picked that array bound, welcome to the world of C.

There are books around but I have no idea what there are called or indeed anything about them, I just know I've heard of them on occasion.

If you don't mind a little C 101 you can replace this

 dataArray[1] = 6; 
  dataArray[2] = 91; 
  dataArray[3] = 79; 
  dataArray[4] = 102; 
  dataArray[5] = 109; 
  dataArray[6] = 125; 
  dataArray[7] = 7; 
  dataArray[8] = 127;
  dataArray[9] = 111;

with

byte  dataArray[] = {63,6,91,79,102,109,125,7,127,111};

Which is fine for an array of numbers, but in this case we're really talking about bit positions on a shift register that's driving a 7-seg display so I would normally to this

byte  dataArray[] = {
//    abcdefg.
    0b11110000,   // 0
    0b11110000,   // 1
    0b11110000,   // 2
    0b11110000,   // 3
    0b11110000,   // 4
    0b11110000,   // 5
    0b11110000,   // 6
    0b11110000,   // 7
    0b11110000,   // 8
    0b11110000    // 9
};

with the correct bits set of course.

While the computer is happy with either 123 or 0b11011011 in this case I think the binary representation is better. Sometimes HEX is better, it's a matter of the number is used and why.


Rob