SPI / 595 shift register demo code

I’ve been playing around with 595 shift registers and the wonderful tutorial about it. After some initial confusion (embarrassingly immortalized in this thread), I got it up and running very nicely.

I wanted to make sure I understood exactly what was going on, so I attached two momentary switches with pull-down resistors to two of the Arduino inputs, and set them up to send out a high or low bit, respectively, to the shift registers. It worked well, and I wanted to post the code in case any other beginners who are scared by all these clock pins might find it helpful.

/* This code uses the same wiring setup found in Carlyn Maw and Tom Igoe's excellent
 ShiftOut Tutorial (http://www.arduino.cc/en/Tutorial/ShiftOut), with the addition of
 two momentary switches with pull-down resistors on pins 2 and 3 (which could of course
 be change). A tutorial explaining the wiring and code behind these switches can be found
 in Limor "ladyada" Fried's tutorial lesson five (http://www.ladyada.net/learn/arduino/lesson5.html)
 
 This code shifts a bit to the 595 register(s) each time a button is pressed (a 1 for one button,
 and a 0 for the other) and displays the current state of the shift registers on LEDs. It can be 
 run with any number of 595s chained together without modification, except you might want to change the
 defined number "daisy" if you want the initial LED blanking to work properly.
 
 Writing this code convinced me that I more-or-less understood what was going on in the 595 tutorials.
 I hope it's useful to others!
 
 */

//Pin connected to ST_CP (storage, or latch clock) of 74HC595
#define latchPin 8
//Pin connected to SH_CP (shift clock) of 74HC595
#define clockPin 12
//Pin connected to DS (data input) of 74HC595
#define dataPin 11

//Pins connected to the two momentary switches
#define but1pin  2
#define but2pin  3

//Number of 595 chips daisy chained together (only important for blanking LEDs ininitially)
#define daisy 1

int but1state = 0;
int but2state = 0;

int but1val;
int but2val;

void setup() {
  // Set the pins for controlling the 595(s)
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);

  // Write blank data to the LEDs to start out. Repeat for as many chips are chained together
  digitalWrite(latchPin, LOW); // First, bring the latch pin low to allow data to be written
  // Next, use the shiftOut function to write a 0 to each of the 595 chips.
  // Changing the "0" to something else like B10101010 might be useful for debugging
  for(int chipnumber = 0; chipnumber < daisy; ++chipnumber){ 
    shiftOut(dataPin, clockPin, MSBFIRST, 0);
  }
  digitalWrite(latchPin, HIGH); // Bring the latch pin high again to display the data

  // Set the pins for the buttons
  pinMode(but1pin, INPUT);
  pinMode(but2pin, INPUT);

  // Initialize the momentary switch values
  but1val = digitalRead(but1pin);
  but2val = digitalRead(but2pin);
}

void loop(){
  but1val = digitalRead(but1pin); // Check whether the button is pressed or not
  delay(5); // This delay and the top if loop are to debounce the button
  if(but1val == digitalRead(but1pin)){
    /* This next if loop checks if the button state has changed, and if the button is currently 
     pressed. If you wanted the event to occur when the button was released, or if you're using a 
     pull-up resistor instead of a pull-down, you should change the "HIGH" to "LOW" here. */
    if(but1state != but1val && but1val == HIGH){ 
      digitalWrite(latchPin, LOW); // First, set the latch low to allow new data to be written
        digitalWrite(clockPin, LOW); // Next, set the clock pin low to tell the chip to start listening
          digitalWrite(dataPin, HIGH); // Set the data bit high to write out a high bit to the register
        digitalWrite(clockPin, HIGH); // Set the clock high to save the high data bit
      digitalWrite(latchPin, HIGH); // Finally, set the latch high to display the new contents of the register
      digitalWrite(dataPin, 0); // Just to keep to data path clear
    }
    but1state = but1val;
  }

  // This is exactly the same as above, or it's for button two, and we set the data bit low instead of high
  but2val = digitalRead(but2pin);
  delay(5);
  if(but2val == digitalRead(but2pin)){
    if(but2state != but2val && but2val == HIGH){
      digitalWrite(latchPin, LOW);
        digitalWrite(clockPin, LOW);
          digitalWrite(dataPin, LOW); //This should already be low, so it's sort of redundant. It's here for clarity
        digitalWrite(clockPin, HIGH);
      digitalWrite(latchPin, HIGH);
    }
    but2state = but2val;
  }
}

(Edit: fixed the links)

Glad to hear you have you have it working. And nicely commented. Your link doesn't seem to work (are there are some extra characters in there?).

FWIW, you could highlight the core functionality even more by moving the latching code into a seperete function.

void latchData( boolean Data){ digitalWrite(latchPin, LOW); // First, set the latch low to allow new data to be written digitalWrite(clockPin, LOW); // Next, set the clock pin low to tell the chip to start listening digitalWrite(dataPin,Data); // Set data bit high if Data is true, low if false digitalWrite(clockPin, HIGH); // Set the clock high to save data bit digitalWrite(latchPin, HIGH); // Finally, set the latch high to display the new contents of the register digitalWrite(dataPin, 0); // Just to keep to data path clear }