ShiftOut confusion-having four 595s

I’ve been pouring over the examples in the ShiftOut tutorial and I have made a lot of progress, but now I am needing to extend my code to work on 32 outputs, and I’m hitting a roadblock.

I am lighting four banks of 8 LEDs, and what I need to do is a little tricky.

Each one of these LEDs is connected to a MIDI trigger, and I’m using it in my band. There are four people and each of us has 8 MIDI triggers to work with-so each person is utilizing one 595.

Right now, by using the example code, I’m using this:

 // the first register and one for the second:
  byte registerOne = lowByte(bitsToSend);
  byte registerTwo = highByte(bitsToSend);


  // shift the bytes out:
  shiftOut(dataPin, clockPin, MSBFIRST, registerTwo);
  shiftOut(dataPin, clockPin, MSBFIRST, registerOne);

So I have access to 16 LEDs.

The first question is how do I extend this so I can access 32 LEDs?

Because it may effect the answer, I should say that the next step is that I will need to have each of the banks of LEDs be independent of the other 8 LEDs-specifically, if bank A has LED #5 lit up, and I light a LED on bank B, I need that Bank A LED to stay lit until I do something again with Bank A…make sense? (though I am thinking this is something I can handle with coding the triggering)…

Here is the function in question (and let me know if you need to see more code!):

void registerWrite(int whichPin, int whichState) {
// the bits you want to send
//  static byte bitsToSend = 0;
   static int bitsToSend = 0;

  // turn off the output so the pins don't light up
  // while you're shifting bits:
  digitalWrite(latchPin, LOW);

  // turn on the next highest bit in bitsToSend:
  bitWrite(bitsToSend, whichPin, whichState);

// break the bits into two bytes, one for 
  // the first register and one for the second:
  byte registerOne = lowByte(bitsToSend);
  byte registerTwo = highByte(bitsToSend);

  // shift the bytes out:
  shiftOut(dataPin, clockPin, MSBFIRST, registerTwo);
  shiftOut(dataPin, clockPin, MSBFIRST, registerOne);

    // turn on the output so the LEDs can light up:
  digitalWrite(latchPin, HIGH);

}

Use a different latchPin for each shift register. That way the input registers on them see the same data, but only the 1 whose latchPin is toiggled will have its output changed.

8, 16, 32, 1024 it doesn’t matter how many LEDs you have they can all be “independent”, you just keep the values in RAM and shift them all at once. String all the shift regs in series and do something like this

byte led_values [4]; //  32 bits, make this any size you like, every bytes is another 8 LEDs

void send_bytes () {
     digitalWrite(latchPin, LOW);
  
     for (int i = 0; i < sizeof(led_values); i++) {
        shiftOut(dataPin, clockPin, MSBFIRST, led_values[i];
       }

    // turn on the output so the LEDs can light up:
     digitalWrite(latchPin, HIGH);
}


void registerWrite(int whichPin, int whichState) {
   
   // sets a bit within the led_values array

   bitWrite (led_values[whichPin / 8)], // calc the byte
               whichPin % 8,            // calc the bit
               whichState);

}

Rob

Thanks guys. Rob, I'm still trying to wrap my head around your solution. I'm really not that good at programming. Here is my complete code. I'm trying to figure out how to impliment your changes, but I keep getting errors because different variables are used. Any help would be appreciated!

If I can not use a different latchPin for each register, that would be very good, because I'm going to have to send this out over distance and to four different groups, so the less wires the better...

Here is my complete code, if anyone would be willing to show me from there how to extend this to the four 595s...again thanks for helping a noob out!

/*
  Shift Register Example
 for 74HC595 shift register

 This sketch turns reads serial input and uses it to set the pins
 of a 74HC595 shift register.

 Hardware:
 * 74HC595 shift register attached to pins 2, 3, and 4 of the Arduino,
 as detailed below.
 * LEDs attached to each of the outputs of the shift register

 Created 22 May 2009
 Created 23 Mar 2010
 by Tom Igoe

 */

//Pin connected to latch pin (ST_CP) of 74HC595
const int latchPin = 8;
//Pin connected to clock pin (SH_CP) of 74HC595
const int clockPin = 12;
////Pin connected to Data in (DS) of 74HC595
const int dataPin = 11;
int midiMessage = 0;
int noteNumber = 0;
int velocity = 0;

int Triggered = 126;
int Playing = 127;
int Looping = 1;
int Stopped = 0;

void setup() {
  //set pins to output because they are addressed in the main loop
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin, OUTPUT);  
  pinMode(clockPin, OUTPUT);
  Serial.begin(57600);
  Serial.println("reset");
}

void loop() {
  
  if (Serial.available()>=3) {
  // now at least 3 bytes are in the buffer.
  midiMessage = Serial.read() ; 
  noteNumber = Serial.read() ; 
  velocity = Serial.read() ; 

  int bitToSet = noteNumber - 60; //Set The output pin to the MIDI note number - 60.
  int bitToSet2 = noteNumber - 60; //Set The output pin to the MIDI note number - 60.

   if (midiMessage == 144){
    
         if (velocity == Triggered){
           registerWrite(bitToSet, HIGH);
          
            
         }

         if (velocity == Playing){
           registerWrite(bitToSet, HIGH);
         }
         if (velocity == Looping){
           registerWrite(bitToSet, HIGH);
           delay(100);
           registerWrite(bitToSet, LOW); 
           delay(100);
           registerWrite(bitToSet, HIGH);
         }
     
     }
     if (midiMessage == 128){
    
         if (velocity == Stopped){
           registerWrite(bitToSet, LOW);
         }
     
     }
   }


}
// This method sends bits to the shift register:

void registerWrite(int whichPin, int whichState) {
// the bits you want to send
//  static byte bitsToSend = 0;
   static int bitsToSend = 0;
   static int bitsToSend2 = 0;
  // turn off the output so the pins don't light up
  // while you're shifting bits:
  digitalWrite(latchPin, LOW);

  // turn on the next highest bit in bitsToSend:
  bitWrite(bitsToSend, whichPin, whichState);
  bitWrite(bitsToSend2, whichPin, whichState);

  // shift the bits out:
//  shiftOut(dataPin, clockPin, MSBFIRST, bitsToSend);

// break the bits into two bytes, one for 
  // the first register and one for the second:
  byte registerOne = lowByte(bitsToSend);
  byte registerTwo = highByte(bitsToSend);
  byte registerThree = lowByte(bitsToSend2);
  byte registerFour = highByte(bitsToSend2);
  // shift the bytes out:
  shiftOut(dataPin, clockPin, MSBFIRST, registerThree);
  shiftOut(dataPin, clockPin, MSBFIRST, registerThree);
  shiftOut(dataPin, clockPin, MSBFIRST, registerTwo);
  shiftOut(dataPin, clockPin, MSBFIRST, registerOne);

    // turn on the output so the LEDs can light up:
  digitalWrite(latchPin, HIGH);

}

What sort of errors, that compiles? However:-

// shift the bytes out:
  shiftOut(dataPin, clockPin, MSBFIRST, registerThree);
  shiftOut(dataPin, clockPin, MSBFIRST, registerThree);
  shiftOut(dataPin, clockPin, MSBFIRST, registerTwo);
  shiftOut(dataPin, clockPin, MSBFIRST, registerOne);

should be:-

// shift the bytes out:
  shiftOut(dataPin, clockPin, MSBFIRST, registerFour);
  shiftOut(dataPin, clockPin, MSBFIRST, registerThree);
  shiftOut(dataPin, clockPin, MSBFIRST, registerTwo);
  shiftOut(dataPin, clockPin, MSBFIRST, registerOne);

Also there is no need to split up the bytes:-

// break the bits into two bytes, one for 
  // the first register and one for the second:
  byte registerOne = lowByte(bitsToSend);
  byte registerTwo = highByte(bitsToSend);
  byte registerThree = lowByte(bitsToSend2);
  byte registerFour = highByte(bitsToSend2);
  // shift the bytes out:
  shiftOut(dataPin, clockPin, MSBFIRST, registerThree);
  shiftOut(dataPin, clockPin, MSBFIRST, registerThree);
  shiftOut(dataPin, clockPin, MSBFIRST, registerTwo);
  shiftOut(dataPin, clockPin, MSBFIRST, registerOne);

Can be replaced with:-

  // shift the bytes out:
  shiftOut(dataPin, clockPin, MSBFIRST, bitsToSend2 >> 8);
  shiftOut(dataPin, clockPin, MSBFIRST, bitsToSend2 & 0xff);
  shiftOut(dataPin, clockPin, MSBFIRST, bitsToSend >> 8);
  shiftOut(dataPin, clockPin, MSBFIRST, bitsToSend & 0xff);

You are using the >> shift right to leave only the top 8 bits shifted down to the lower 8 bits. The logical AND & will leave only the 8 lower bits.

If you define bitsToSend as a long int that will hold 32 bits in one go, although I am not sure if the function bitWrite() will work with long ints, it would be easy enough to write a version that did.

Thanks Grumpy_Mike.

If you define bitsToSend as a long int that will hold 32 bits in one go, although I am not sure if the function bitWrite() will work with long ints, it would be easy enough to write a version that did.

Are you saying that I need to do this, or are you saying that if I did this, then I could get rid of the BitsToSend2 variable?

Using the code you provided, for some reason, the LEDs are only lighting for the first 16 lights, the second 16 are not lighting...

I believe I have correctly implemented your changes:

/*
  Shift Register Example
 for 74HC595 shift register

 This sketch turns reads serial input and uses it to set the pins
 of a 74HC595 shift register.

 Hardware:
 * 74HC595 shift register attached to pins 2, 3, and 4 of the Arduino,
 as detailed below.
 * LEDs attached to each of the outputs of the shift register

 Created 22 May 2009
 Created 23 Mar 2010
 by Tom Igoe

 */

//Pin connected to latch pin (ST_CP) of 74HC595
const int latchPin = 8;
//Pin connected to clock pin (SH_CP) of 74HC595
const int clockPin = 12;
////Pin connected to Data in (DS) of 74HC595
const int dataPin = 11;
int midiMessage = 0;
int noteNumber = 0;
int velocity = 0;

int Triggered = 126;
int Playing = 127;
int Looping = 1;
int Stopped = 0;

void setup() {
  //set pins to output because they are addressed in the main loop
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin, OUTPUT);  
  pinMode(clockPin, OUTPUT);
  Serial.begin(57600);
  Serial.println("reset");
}

void loop() {
  
  if (Serial.available()>=3) {
  // now at least 3 bytes are in the buffer.
  midiMessage = Serial.read() ; 
  noteNumber = Serial.read() ; 
  velocity = Serial.read() ; 

  int bitToSet = noteNumber - 60; //Set The output pin to the MIDI note number - 60.
  int bitToSet2 = noteNumber - 60; //Set The output pin to the MIDI note number - 60.

   if (midiMessage == 144){
    
         if (velocity == Triggered){
           registerWrite(bitToSet, HIGH);
          
            
         }

         if (velocity == Playing){
           registerWrite(bitToSet, HIGH);
         }
         if (velocity == Looping){
           registerWrite(bitToSet, HIGH);
           delay(100);
           registerWrite(bitToSet, LOW); 
           delay(100);
           registerWrite(bitToSet, HIGH);
         }
     
     }
     if (midiMessage == 128){
    
         if (velocity == Stopped){
           registerWrite(bitToSet, LOW);
         }
     
     }
   }


}
// This method sends bits to the shift register:

void registerWrite(int whichPin, int whichState) {
// the bits you want to send
//  static byte bitsToSend = 0;
   static int bitsToSend = 0;
   static int bitsToSend2 = 0;
  // turn off the output so the pins don't light up
  // while you're shifting bits:
  digitalWrite(latchPin, LOW);

  // turn on the next highest bit in bitsToSend:
  bitWrite(bitsToSend, whichPin, whichState);
  bitWrite(bitsToSend2, whichPin, whichState);

  // shift the bits out:
//  shiftOut(dataPin, clockPin, MSBFIRST, bitsToSend);

// shift the bytes out:
  shiftOut(dataPin, clockPin, MSBFIRST, bitsToSend2 >> 8);
  shiftOut(dataPin, clockPin, MSBFIRST, bitsToSend2 & 0xff);
  shiftOut(dataPin, clockPin, MSBFIRST, bitsToSend >> 8);
  shiftOut(dataPin, clockPin, MSBFIRST, bitsToSend & 0xff);

    // turn on the output so the LEDs can light up:
  digitalWrite(latchPin, HIGH);

}

Any help is greatly appreciated!!

I’m actually realizing I don’t understand something in this function:

void registerWrite(int whichPin, int whichState) {
// the bits you want to send
   static int bitsToSend = 0;
   static int bitsToSend2 = 0;

  // turn off the output so the pins don't light up
  // while you're shifting bits:
  digitalWrite(latchPin, LOW);

  // turn on the next highest bit in bitsToSend:
  
  bitWrite(bitsToSend, whichPin, whichState);
  bitWrite(bitsToSend2, whichPin, whichState);

// shift the bytes out:
  shiftOut(dataPin, clockPin, MSBFIRST, bitsToSend2 >> 8);
  shiftOut(dataPin, clockPin, MSBFIRST, bitsToSend2 & 0xff);
  shiftOut(dataPin, clockPin, MSBFIRST, bitsToSend >> 8);
  shiftOut(dataPin, clockPin, MSBFIRST, bitsToSend & 0xff);

    // turn on the output so the LEDs can light up:
  digitalWrite(latchPin, HIGH);

}

What does this line do?

  bitWrite(bitsToSend, whichPin, whichState);

Specifically what is bitsToSend doing there if it is just declared as an int with “0” value? I guess I don’t really know what bitsToSend is??

EDIT: OK, I just RTFM:
http://www.arduino.cc/en/Reference/BitWrite

Sweet! I got it! Just had to actually sit and understand it for a minute. I put in this conditional, and it is working as expected:

  if (whichPin <=15){
  bitWrite(bitsToSend, whichPin, whichState);
  } else {
    
  bitWrite(bitsToSend2, whichPin - 16, whichState);
  }

Well done! :) You are on the way to being able to fault find and that is a good skill to have.

if it helps I wrote a library using shiftOut functions in "wiring_shift.c" that allows you to do something like that, what it does is it abstracts you from doing all the coding and figuring out. all you do is instantiate an object of the class called shiftOutX, for example if you call it MIDI_LEDs then call functions "MIDI_LEDs.pinOn(shPin4);" to turn on a pin 4 and "MIDI_LEDs.pinOff(shPin4);" to turn it off, up to 64 outputs. registers must be daisy chained like in the tutorial you are reading. here is the library http://arduino.cc/playground/Main/ShiftOutX