Midi IN LED control/shift registers..help plse!?

Hello.

I am very new to the Arduino, but am already thoroughly enjoying it.

I spent about a week poring over the big discussion regards controlling LEDs with midi. (I will post link in reply - can't add links to my first post!)

I have no real experience with either electronics or coding, so was thrilled that I managed to get this working. I also managed to get two shift registers working using the tutorials on this website.

What I would really like to do now is upscale the midi in LED control to be able to control more than just the 8 leds, each using a dedicated arduino pin, but I simply haven't got the coding knowledge to combine this with a shift register / convert midi instructions into something that can be used to control individual leds.

I am planning to skip back to the start and concentrate on the basics of coding, but if anybody at all could give me an example of where to begin - it might not even be a shiftregister that I need, for instance - then it would be greatly appreciated.

This is the midi discussion I was referring to: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1187962258/

and it was this shift out tutorial I was following: http://arduino.cc/en/Tutorial/ShiftOut

Thanks again for any help/pointers.

Hello.

Yes, I should have been clearer - I am basically trying to switch on LEDs with a midi note on, and off when the note stops (or there is a note on zero-velocity signal).

As many LEDs as possible, basically.

I actually have spent the past week or so doing exactly what you said - separating it into two projects. I think I understand the fundamentals behind each task, it is just building the code to translate midi in signals to be sent back out through shift registers that I am stuck at.

What I am actually asking for advice about is a bit vague, but I can’t work out how to take the cognitive leap from understand what the code is doing, to actually creating my own. I have exhausted google and seen countless led matrixes/control methods, with shift registers etc. but none of them appear to be controlled with midi, apart from the 8-led example that I linked to…

Thanks for your response, in any case. I will keep plugging away.

Yes, the midi decoding part is working, after a fashion. I am misusing a midi shield that I bought with the arduino, as it offered midi out options that I found it easier to bypass.

The code I am using to trigger the 8 leds at the moment is this:

/* Midi In Basic  0.2 // kuki 8.2007
 *
 * -----------------
 * listen for midi serial data, and light leds for individual notes

 IMPORTANT:
 your arduino might not start if it receives data directly after a reset, because the bootloader thinks you want to uplad a new progam.
 you might need to unplug the midi-hardware until the board is running your program. that is when that statusLed turns on.

#####################################################################################################################################################
SOMETHING ABOUT MIDI MESSAGES
 midi messages start with one status byte followed by 1 _or_ 2 data bytes, depending on the command

 example midi message: 144-36-100
   the status byte "144" tells us what to do. "144" means "note on".
   in this case the second bytes tells us which note to play (36=middle C)
   the third byte is the velocity for that note (that is how powerful the note was struck= 100)
  
 example midi message: 128-36
   this message is a "note off" message (status byte = 128). it is followed by the note (data byte = 36)
   since "note off" messages don't need a velocity value (it's just OFF) there will be no third byte in this case
   NOTE: some midi keyboards will never send a "note off" message, but rather a "note on with zero velocity"
  
 do a web search for midi messages to learn more about aftertouch, poly-pressure, midi time code, midi clock and more interesting things.
#####################################################################################################################################################

HARDWARE NOTE:
The Midi Socket is connected to arduino RX through an opto-isolator to invert the midi signal and seperate the circuits of individual instruments.
connect 8 leds to pin2-pin9 on your arduino.

####################################################################################################################################################


 */

//variables setup

byte incomingByte;
byte note;
byte velocity;


int statusLed = 13;   // select the pin for the LED

int action=2; //0 =note off ; 1=note on ; 2= nada


//setup: declaring iputs and outputs and begin serial
void setup() {
  pinMode(statusLed,OUTPUT);   // declare the LED's pin as output
  pinMode(2,OUTPUT);
  pinMode(3,OUTPUT);
  pinMode(4,OUTPUT);
  pinMode(5,OUTPUT);
  pinMode(6,OUTPUT);
  pinMode(7,OUTPUT);
  pinMode(8,OUTPUT);
  pinMode(9,OUTPUT);
  
  //start serial with midi baudrate 31250 or 38400 for debugging
  Serial.begin(31250);        
  digitalWrite(statusLed,HIGH);  
}

//loop: wait for serial data, and interpret the message
void loop () {
  if (Serial.available() > 0) {
    // read the incoming byte:
    incomingByte = Serial.read();

    // wait for as status-byte, channel 1, note on or off
    if (incomingByte== 144){ // note on message starting starting
      action=1;
    }else if (incomingByte== 128){ // note off message starting
      action=0;
    }else if (incomingByte== 208){ // aftertouch message starting
       //not implemented yet
    }else if (incomingByte== 160){ // polypressure message starting
       //not implemented yet
    }else if ( (action==0)&&(note==0) ){ // if we received a "note off", we wait for which note (databyte)
      note=incomingByte;
      playNote(note, 0);
      note=0;
      velocity=0;
      action=2;
    }else if ( (action==1)&&(note==0) ){ // if we received a "note on", we wait for the note (databyte)
      note=incomingByte;
    }else if ( (action==1)&&(note!=0) ){ // ...and then the velocity
      velocity=incomingByte;
      playNote(note, velocity);
      note=0;
      velocity=0;
      action=0;
    }else{
      //nada
    }
  }
}

void blink(){
  digitalWrite(statusLed, HIGH);
  delay(100);
  digitalWrite(statusLed, LOW);
  delay(100);
}


void playNote(byte note, byte velocity){
  int value=LOW;
  if (velocity >10){
      value=HIGH;
  }else{
   value=LOW;
  }

 //since we don't want to "play" all notes we wait for a note between 36 & 44
 if(note>=36 && note<44){
   byte myPin=note-34; // to get a pinnumber between 2 and 9
   digitalWrite(myPin, value);
 }

}

and from what I understand, this can’t be ‘scaled up’ because it relies on the specific pin numbers on the arduino board, which aren’t applicable to shift registers.

So, what I am hoping to work out is how to replace the rules that filter out all notes either side of 36-44, with instructions that will instead shift out different information to the registers/relevant LEDs, depending on what midi note it receives.

If you can tell whether I am heading in the right direction with this, it would be really encouraging to know. Thanks!

Wow. That's definitely something to cut my coding teeth on.

Thanks so much for setting me on the right track, didn't expect help so soon.

Much appreciated.

I'll probably be back, hopelessly stuck, in a little while...

Ok. Well, I’ve sat solidly working at this for a few hours and am coming to the conclusion that whilst this is relatively basic, it’s way beyond my programming skills. It’s frustrating because I understand the logic entirely, I just don’t know the language to communicate it correctly.

The code below is as far as I have got. I know that there will be a formula to calculate each a combination for each midi note, rather than writing out an ‘if’ function for every single one, but I haven’t quite got the capacity to work out how to do it.

I am using 2 shift registers, with a total of 16 LEDS, so as not to get ahead of myself trying to control 64. Furthermore, this code just has the first three midi notes > leds (notes 36, 37, and 38) which would be C1, C#1 and D1 on a midi keyboard.

When I trigger the first note, it does light up the correct led/s, but then it hangs completely. The led stays on, and no further midi signals appear to be recognised.

If anybody has any suggestions about how to move forward, it would be amazing, because I’m quite stuck.

Here’s the code -

//Midi IN Test, with two shift registers trying to control 16 LEDs, culled and adapted from various code found online.


//midi information
byte incomingByte = 255;
byte note = 255;
byte velocity = 255;

//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 information to pass to shifting function
byte ledONE;
byte ledTWO;
byte ledArrayONE[9];
byte ledArrayTWO[9];

// pin for the status LED
int statusLed = 13;   // select the pin for the LED

//0 =note off ; 1=note on ; 2= nada
int action=2; 


//setup: declaring iputs and outputs and begin serial 
void setup() {
 pinMode(statusLed,OUTPUT);   // declare the LED's pin as output

  //start serial with midi baudrate 31250 or 38400 for debugging
 Serial.begin(31250);        
 digitalWrite(statusLed,HIGH); 

 //values for each combination
  ledArrayONE[0] = 0x00; //00000000
  ledArrayONE[1] = 0x01; //00000001
  ledArrayONE[2] = 0x02; //00000010
  ledArrayONE[3] = 0x04; //00000100
  ledArrayONE[4] = 0x08; //00001000
  ledArrayONE[5] = 0x10; //00010000
  ledArrayONE[6] = 0x20; //00100000
  ledArrayONE[7] = 0x40; //01000000
  ledArrayONE[8] = 0x80; //10000000

  ledArrayTWO[0] = 0x00; //00000000
  ledArrayTWO[1] = 0x01; //00000001
  ledArrayTWO[2] = 0x02; //00000010
  ledArrayTWO[3] = 0x04; //00000100
  ledArrayTWO[4] = 0x08; //00001000
  ledArrayTWO[5] = 0x10; //00010000
  ledArrayTWO[6] = 0x20; //00100000
  ledArrayTWO[7] = 0x40; //01000000
  ledArrayTWO[8] = 0x80; //10000000
}



//loop: wait for serial data, and interpret the message 
void loop () {
 if (Serial.available() > 0) {
   // read the incoming byte:
   incomingByte = Serial.read();

   // receive first midi byte
   if (incomingByte== 144){ // note on message starting starting
     action=1;
   }else if (incomingByte== 128){ // note off message starting
     action=0;
   }else if (incomingByte > 144){ // message is anything but note message
   action=2; //nothing happens
     
 
   //process second byte
   }else if ( (incomingByte<=127) && (action ==1 || action==0)&&(note==255) ){ // if we received note number message load this byte in the note byte
     note=incomingByte;
   //process Third byte
   }else if ( (incomingByte<=127) && (action ==1)&&(note!=255) ){ // if we received noteon message load this byte in the velocity byte
    velocity=incomingByte;
    playNote(note, velocity);
    note=255;
    }else if ( (incomingByte<=127) && (action ==0)&&(note!=255) ){ // if we received note message load this byte in the velocity byte
    velocity=0;
    playNote(note, velocity);
    note=255;
   }else{
     //nada
   }
 }
}



void playNote(byte note, byte velocity){
 int value=LOW;
 if (velocity >10){
     value=HIGH;
 }else{
  value=LOW; 
 }

//Starting the LEDS at midi note 36, which is C1 on a midi keyboard.
if(note==36){
    //load the light sequence you want from array
    ledONE = ledArrayONE[1];
    ledTWO = ledArrayTWO[0];
    //ground latchPin and hold low for as long as you are transmitting
    digitalWrite(latchPin, 0);
    //move 'em out
    shiftOut(dataPin, clockPin, ledTWO);   
    shiftOut(dataPin, clockPin, ledONE);
    //return the latch pin high to signal chip that it 
    //no longer needs to listen for information
    digitalWrite(latchPin, 1);
    delay(50);
  }
  
//For note 37, D1 on a midi keyboard  
  if(note==37){
    //load the light sequence you want from array
    ledONE = ledArrayONE[2];
    ledTWO = ledArrayTWO[0];
    //ground latchPin and hold low for as long as you are transmitting
    digitalWrite(latchPin, 0);
    //move 'em out
    shiftOut(dataPin, clockPin, ledTWO);   
    shiftOut(dataPin, clockPin, ledONE);
    //return the latch pin high to signal chip that it 
    //no longer needs to listen for information
    digitalWrite(latchPin, 1);
    delay(50);
  }
  
 //For note 37, D1 on a midi keyboard 
 if(note==38){
    //load the light sequence you want from array
    ledONE = ledArrayONE[3];
    ledTWO = ledArrayTWO[0];
    //ground latchPin and hold low for as long as you are transmitting
    digitalWrite(latchPin, 0);
    //move 'em out
    shiftOut(dataPin, clockPin, ledTWO);   
    shiftOut(dataPin, clockPin, ledONE);
    //return the latch pin high to signal chip that it 
    //no longer needs to listen for information
    digitalWrite(latchPin, 1);
    delay(50);
  }
}

// the shift out function
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);
}

Thank you.

Your time is appreciated, but I'm afraid to say that I don't fully understand how to apply this to where I have got to so far.

I will do some experimenting, to try and make it work. When you say in your notes i should declare the chromatic scale, should i be doing something along these lines, like in the previous code I posted:

chromatic[0] = 0x00; //00000000 chromatic[1] = 0x01; //00000001 chromatic[2] = 0x02; //00000010 chromatic[3] = 0x04; //00000100 chromatic[4] = 0x08; //00001000 chromatic[5] = 0x10; //00010000 chromatic[6] = 0x20; //00100000 chromatic[7] = 0x40; //01000000 chromatic[8] = 0x80; //10000000

or am I missing the point here?

I'll keep going...

Thank you.

I am SO close to understanding, I can feel it. I’m just trying to put the code together. It’s like speaking a foreign language with a wooden tongue.

I think the only thing that is holding me back now is that I am using this stretch of code to calculate the midi note:

 // wait for as status-byte, channel 1, note on or off
   if (incomingByte== 144){ // note on message starting starting
     action=1;
   }else if (incomingByte== 128){ // note off message starting
     action=0;
   }else if (incomingByte > 144){ // message is anything but note message
   action=2; //nothing happens
      //not implemented yet
   //}else if (incomingByte== 160){ // polypressure message starting
      //not implemented yet
   //process second byte
   }else if ( (incomingByte<=127) && (action ==1 || action==0)&&(note==255) ){ // if we received note number message load this byte in the note byte
     note=incomingByte;
   //process Third byte
   }else if ( (incomingByte<=127) && (action ==1)&&(note!=255) ){ // if we received noteon message load this byte in the velocity byte
    velocity=incomingByte;
    playNote(note, velocity);
    note=255;
    }else if ( (incomingByte<=127) && (action ==0)&&(note!=255) ){ // if we received note message load this byte in the velocity byte
    velocity=0;
    playNote(note, velocity);
    note=255;
   }else{
     //nada
   }
 }
}

void blink(){
 digitalWrite(statusLed, HIGH);
 delay(100);
 digitalWrite(statusLed, LOW);
 delay(100);
}


void playNote(byte note, byte velocity){
 int value=LOW;
 if (velocity >10){
     value=HIGH;
 }else{
  value=LOW; 
 }

This is what was stripping down the midi data to a single note number for me previously.

What I can’t work out now is exactly how to phrase the instruction to send this note to the array code that you just explained to me.

It feels like the code I just posted is overcomplicated everything you’ve just refined, but I can’t quite work out the fix…

Ok.

Thanks Richard, I'm reassured that I don't have flaws in my understanding, just the code.

I do have the MIDI decoding part worked out. My original 8 led set-up was definitely picking out the midi notes no problem.

It's just the combining of the two different pieces of code. Think I just need to study some coding rules/vocabulary for a while.

I'll crack it eventually, and then I'll post it here for any future googlers.

Cheers.

The notes were hanging as a result of me experimenting with combining the original 'midi in' code I had with the 'shift out' code.

However, this was before your guidance. It was messy and I wasn't sure what I was doing.

Now I have backtracked to the original 'midi in' code I was using, which was handling note ON and note OFF just fine.

It worked perfectly, in fact - the only problem was it was only written to allow the midi to switch on or off arduino pins. So, in theory, like you say, all I should have to do is implement your chromatic shift out code in the right places, and it should work.

I think(?)

No real progress made so far, unfortunately. This is my attempt at trying to combine the code I’ve culled from various places around here.

If I strip out the chromatic array and shift out stuff, the MIDI IN is still being received and the code to recognise the ‘note OFF’ command is working fine. If anyone has any clues…

/* Midi IN, - note numbers to control LEDS via shift registers. NOT WORKING YET!
*/

//variables setup

byte incomingByte = 255; // midi signal #1
byte note = 255; // midi signal #2
byte velocity = 255; // midi signal #3

byte bytenumb; // 
byte bitnumb; //
byte chromatic[10];   // declare chromatic scale, 8 x 11 = 88 notes

//Shift Out Pins to 74HC595s
int latchPin = 8;
int clockPin = 12;
int dataPin = 11;

int statusLed = 13;   // select the pin for the LED

int action=2; // MIDI rules: 0 =note off ; 1=note on ; 2= nada


//setup: declaring iputs and outputs and begin serial 
void setup() {

pinMode(statusLed,OUTPUT);   // declare the LED's pin as output
pinMode(latchPin, OUTPUT);
 
//start serial with midi baudrate 31250 or 38400 for debugging
Serial.begin(31250);        
digitalWrite(statusLed,HIGH); 
 
for (int i = 0; i < 11; i++){ //  (i.e. for i = 0 to 10)
chromatic[i] = 0;
}

}

//loop: wait for serial data, and interpret the message 
void loop () {
 if (Serial.available() > 0) {
   // read the incoming byte:
   incomingByte = Serial.read();

   // wait for as status-byte, channel 1, note on or off
   if (incomingByte== 144){ // note on message starting starting
     action=1;
   }else if (incomingByte== 128){ // note off message starting
     action=0;
   }else if (incomingByte > 144){ // message is anything but note message
   action=2; //nothing happens
     
      
   //process second byte
   }else if ( (incomingByte<=127) && (action ==1 || action==0)&&(note==255) ){ // if we received note number message load this byte in the note byte
     note=incomingByte;
  
   
   
   //process Third byte
   }else if ( (incomingByte<=127) && (action ==1)&&(note!=255) ){ // if we received note ON message load this byte in the velocity byte
    velocity=incomingByte;
    playNote(note, velocity);
    note=255;
   
    
    }else if ( (incomingByte<=127) && (action ==0)&&(note!=255) ){ // if we received note message load this byte in the velocity byte
    velocity=0;
    playNote(note, velocity);
    note=255;
   
    }
  else if (note>=1 && note<89){
  bytenumb = (note / 8);  // calculate which array byte 0 ~ 10
  bitnumb  = (note % 8);   // calculate which bit  (0 ~ 7)
  chromatic[bytenumb] = bitSet(chromatic[bytenumb], bitnumb);
   
    //ground latchPin and hold low for as long as you are transmitting
    digitalWrite(latchPin, 0);
    //move 'em out
    shiftOut(dataPin, clockPin, chromatic[bytenumb]);   
    
    //return the latch pin high to signal chip that it 
    //no longer needs to listen for information
    digitalWrite(latchPin, 1);
    delay(50);
  }  //nada
   }
 }


void blink(){
 digitalWrite(statusLed, HIGH);
 delay(100);
 digitalWrite(statusLed, LOW);
 delay(100);
}


void playNote(byte note, byte velocity){
 int value=LOW;
 if (velocity >10){
     value=HIGH;
 }else{
  value=LOW; 
 }
}
// the shift out function
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);
}

Ok. Here is the catch.

These three steps to strip down the MIDI IN signal to a note number and an ON or OFF command does work. The first instruction makes sure the first byte is either 144 (midi note on), or 128 (midi note off). If it is anything else, it is ignored:

   // wait for as status-byte, channel 1, note on or off
   if (incomingByte== 144){ // note on message starting starting
     action=1;
   }else if (incomingByte== 128){ // note off message starting
     action=0;
   }else if (incomingByte > 144){ // message is anything but note message
   action=2; //nothing happens

Then the following instructions process the second byte, which is the note number:

 //process second byte
   }else if ( (incomingByte<=127) && (action ==1 || action==0)&&(note==255) ){ // if we received note number message load this byte in the note byte
     note=incomingByte;

and then the third instruction reads the third byte, which is the velocity. (This is important because sometimes midi keyboards/software send a note ON message with a 0 velocity rather than a note OFF message):

 //process Third byte
   }else if ( (incomingByte<=127) && (action ==1)&&(note!=255) ){ // if we received note ON message load this byte in the velocity byte
    velocity=incomingByte;
    playNote(note, velocity);
    note=255;

The key to all this, as far as I can understand it, is the playNote function, which is defined as this:

void playNote(byte note, byte velocity){
 int value=LOW;
 if (velocity >10){
     value=HIGH;
 }else{
  value=LOW; 
 }

Now. When this is being routed directly to the Arduino pins, it is fine. What I have tried to do is point the playNote instruction toward the array that you explained to me, by doing this:

if (note>=1 && note<89){
  bytenumb = (note / 8);  // calculate which array byte 0 ~ 10
  bitnumb  = (note % 8);   // calculate which bit  (0 ~ 7)
  chromatic[bytenumb] = bitSet(chromatic[bytenumb], bitnumb);
   
    //ground latchPin and hold low for as long as you are transmitting
    digitalWrite(latchPin, 0);
    //move 'em out
    shiftOut(dataPin, clockPin, chromatic[bytenumb]);

followed by all the shift out stuff. But this doesn’t work. I suspect that I have written the code incorrectly, but I don’t know if this is the only problem, or if it is in the wrong place, or if it should actually be replacing the playNote function entirely.

This is the crux of my problem. When uploading the code to the board, I get absolutely no response from any midi signal.

The shift registers work fine if I upload predefined ShiftOut programs, and the Midi works fine if I take out the Array stuff again. I just can’t seem to fit them together!

That’s good to know. Thanks.
Just had a bit of a minor break through - for the moment I am ignoring the third byte (velocity) because I happen to know that the midi signal I send sending to the arduino is definitely sending a note OFF signal too. I swapped the code around and now the midi is responding and LEDs are lighting up!

The only problem is - the order of the lights appears to be random, as far as I can tell. At the moment I have five shift registers running 40 LEDS. Each midi note lights up a different random collection of LEDS. Also, each different midi note off leaves another, different collection of LEDS left on.

It also appears to be only allowing one midi note at a time, which will be problematic for me further down the line, but right now I’m just happy to have some signs of life.

Is there anything you can see in using the code this way which might explain the seemingly random collections of LEDS assigned to each midi note?

void loop () {
 if (Serial.available() > 0) {
   // read the incoming byte:
   incomingByte = Serial.read();

   // wait for as status-byte, channel 1, note on or off
   if (incomingByte== 144){ // note on message starting starting
     action=1;
   }else if (incomingByte== 128){ // note off message starting
     action=0;
   }else if (incomingByte > 144){ // message is anything but note message
   action=2; //nothing happens
     
      
   //process second byte
   }else if ( (incomingByte<=127) && (action ==1)&&(note==255) ){ // if we received note number message load this byte in the note byte
     note=incomingByte;
      bytenumb = (note / 8);  // calculate which array byte 0 ~ 10
  bitnumb  = (note % 8);   // calculate which bit  (0 ~ 7)
  chromatic[bytenumb] = bitSet(chromatic[bytenumb], bitnumb);
    //ground latchPin and hold low for as long as you are transmitting
    digitalWrite(latchPin, 0);
    //move 'em out

    
    //return the latch pin high to signal chip that it 
    //no longer needs to listen for information
    digitalWrite(latchPin, 1);
    delay(50);
  }   
  
  else if ( (incomingByte<=127) && (action ==0)&&(note==255) ){ // if we received note number message load this byte in the note byte
     note=incomingByte;
      bytenumb = (note / 8);  // calculate which array byte 0 ~ 10
  bitnumb  = (note % 8);   // calculate which bit  (0 ~ 7)
  chromatic[bytenumb] = bitClear(chromatic[bytenumb], bitnumb);
    //ground latchPin and hold low for as long as you are transmitting
    digitalWrite(latchPin, 0);
    //move 'em out
    shiftOut(dataPin, clockPin, chromatic[bitClear]);   
    
    //return the latch pin high to signal chip that it 
    //no longer needs to listen for information
    digitalWrite(latchPin, 1);
    delay(50);
  }

Ahh… you’re right. My desktop is cluttered with code debris. Apologies.

This is the code that made the lights come alive as mentioned in my previous post:

void loop () {
 if (Serial.available() > 0) {
   // read the incoming byte:
   incomingByte = Serial.read();

   // wait for as status-byte, channel 1, note on or off
   if (incomingByte== 144){ // note on message starting starting
     action=1;
   }else if (incomingByte== 128){ // note off message starting
     action=0;
   }else if (incomingByte > 144){ // message is anything but note message
   action=2; //nothing happens
     
      
   //process second byte 
   }else if ( (incomingByte<=127) && (action ==1)&&(note==255) ){ // IF THE FIRST BYTE WAS A NOTE ON MESSAGE...
     note=incomingByte;
      bytenumb = (note / 8);  // calculate which array byte 0 ~ 10
  bitnumb  = (note % 8);   // calculate which bit  (0 ~ 7)
  chromatic[bytenumb] = bitSet(chromatic[bytenumb], bitnumb);
    //ground latchPin and hold low for as long as you are transmitting
    digitalWrite(latchPin, 0);
    //move 'em out
    shiftOut(dataPin, clockPin, chromatic[bytenumb]);   
    //return the latch pin high to signal chip that it 
    //no longer needs to listen for information
    digitalWrite(latchPin, 1);
    delay(50);
  }   
  
  else if ( (incomingByte<=127) && (action ==0)&&(note==255) ){ //IF THE FIRST BYTE WAS A NOTE OFF MESSAGE...
     note=incomingByte;
      bytenumb = (note / 8);  // calculate which array byte 0 ~ 10
  bitnumb  = (note % 8);   // calculate which bit  (0 ~ 7)
  chromatic[bytenumb] = bitClear(chromatic[bytenumb], bitnumb);
    //ground latchPin and hold low for as long as you are transmitting
    digitalWrite(latchPin, 0);
    //move 'em out
    shiftOut(dataPin, clockPin, chromatic[bytenumb]);   
    
    //return the latch pin high to signal chip that it 
    //no longer needs to listen for information
    digitalWrite(latchPin, 1);
    delay(50);
  }

Is this shiftOut code correct? I’m not sure that it should be chromatic[bytenumb] but I am not sure how else to phrase it…

Looking closely at the LEDs, the correct LEDs are lighting (i.e - the first LED on the first shift register is getting turned on with midi note 1) but a whole lot more are lighting too, and the note off data holds no pattern that i can see.

Ahhhh… I see.

So just because the array itself can deal with 88 midi notes, it doesn’t automatically find its own.

If I repeat the shiftOut(dataPin, clockPin, chromatic[bytenumb]); five times, then all five shift registers respond the same.

What I don’t understand is if there is just a single array, based around the formula, how do I give each shift register a separate instruction?

Would it be something along the lines of:

if(note>=1 && note<9){
shiftOut(dataPin, clockPin, chromatic[bytenumb]);
shiftOut(dataPin, clockPin, chromatic[0]);
shiftOut(dataPin, clockPin, chromatic[0]);
shiftOut(dataPin, clockPin, chromatic[0]);
shiftOut(dataPin, clockPin, chromatic[0]);
}

else if(note>=9 && note<17){
shiftOut(dataPin, clockPin, chromatic[0]);
shiftOut(dataPin, clockPin, chromatic[bytenumb]);
shiftOut(dataPin, clockPin, chromatic[0]);
shiftOut(dataPin, clockPin, chromatic[0]);
shiftOut(dataPin, clockPin, chromatic[0]);
}

etc.? or would that be me heading off in the wrong direction again?

Amazing!

I now have the 40 LEDs responding to individual notes running through 5 shift registers!

I'm very grateful for your help.

There still seems to be plenty of debugging/refining to do because if any of the signals overlap it causes the LEDs to get stuck.

Also, the monophonic issue is something that I will have to work out how to overcome at some point. I am going to look into it. I really have to be able to light up different combinations of notes at the same time.

I have one last question which would be really useful in knowing the answer to regards that - is it possible to send more than one midi note at a time to the relevant LEDs if they have to pass through various shift registers? Or would I be looking at some kind of persistence of vision thing here?

I've noticed that the shortening the delay after the shiftout commands is affecting the midi response quite a lot, but even so I can run the midi signals too fast or the arduino can't keep up. This doesn't bode well for any strobing effects...

Anyway - thanks again for helping me get this far. I will post the code I have so far later (once I've cleaned it up and made some notes), in case any else finds it useful.

Ok.

I now have things running pretty smoothly. I dealt with most of the problems in my last post by stripping out a bunch of redundant code that I was too unfamiliar with to understand at first.

If more than 16 LEDS are lit at any one time and the midi signals are coming thick and fast, then some LEDS will hang, but it doesn’t crash and as soon as they are flashed again, they catch up and things keep running. It’s rare that I’d be putting that much midi through at once anyways.

Once I get more comfortable with coding, I might try and build some predefined patterns involving some/all leds, which could be triggered by a particular midi note, but best not run before I can walk. Next step for me is building the hardware side of things into something usable.

Anyway, for the record, here is the code that is currently working, just in case anyone ever googles this question.

Thanks again for your help Richard, couldn’t have done it without you.

/* /* Controlling up to 88 LEDs independently with Midi notes from a Midi in.
//

// This code has been cobbled together from existing material found on the internet and help from the Arduino forums.

// The midi stuff in particular was gleaned from this thread: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1187962258/

// The shift register stuff is pulled straight from the arduino tutorials.

// I have not fine tuned it yet and there are still probably fragments of code in here that are either unnecessary or
// perhaps even detrimental to the performance.
// However, it DOES work, so if you happen to need to be able to control LEDS via midi notes, then this will be
// a useful place to start.
*/

// A midi signal comes in 3 bits. The first is Midi On (144), or Midi off(128). It can be a bunch of other things too,
// but for this situation I'm not interested in them.
// The second bit is the note number (e.g 36 = C1, 37 = C#1, 38 = D1, etc.)
// The third bit is velocity (0-127).

// Finally - at the moment this code only deals with 5 shift registers, giving control over 40 leds,
// although the array caters for all 88 notes.
//

//variables setup

byte incomingByte = 255; // midi signal #1
byte note = 255; // midi signal #2
byte velocity = 255; // midi signal #3

byte bytenumb; // 
byte bitnumb; //
byte chromatic[10];   // declare chromatic scale, 8 x 11 = 88 notes

//Shift Out Pins to 74HC595s
int latchPin = 8;
int clockPin = 12;
int dataPin = 11;
int statusLed = 13;   // select the pin for the LED
int startupBeep =  6; // connect to a piezo buzzer. not strictly necessary, but use to know arduino is on & good to receive midi   
int action=2; // MIDI rules: 0 =note off ; 1=note on ; 2= nada


//setup: declaring iputs and outputs and begin serial 
void setup() {

pinMode(statusLed,OUTPUT);   // declare the LED's pin as output
pinMode(latchPin, OUTPUT);  // declare latch pin as output
 
//start serial with midi baudrate 31250 or 38400 for debugging
Serial.begin(31250);        
digitalWrite(statusLed,HIGH); 
 

//function that blinks all the LEDs and then switches them off
  //gets passed the number of blinks and the pause time
  blinkAll_2Bytes(1,750);
  killAll_2Bytes(1,500);
  
  for (int i = 0; i < 11; i++){ //  (i.e. for i = 0 to 10)
chromatic[i] = 0; // resets the array.
}

  
}

//loop: wait for serial data, and interpret the message 
void loop () {
 if (Serial.available() > 0) {
   // read the incoming byte:
   incomingByte = Serial.read();

   // wait for as status-byte, channel 1, note on or off
   if (incomingByte== 144){ // note on message starting starting
     action=1;
   }else if (incomingByte== 128){ // note off message starting
     action=0;
   }else if (incomingByte > 144){ // message is anything but note message
   action=2; //nothing happens
     
      
   //process second byte 
   }else if ( (incomingByte<=127) && (action ==1) ){ // IF THE FIRST BYTE WAS A NOTE ON MESSAGE...
     bytenumb = (incomingByte / 8);  // calculate which array byte 0 ~ 10
     bitnumb  = (incomingByte % 8);   // calculate which bit  (0 ~ 7)
     chromatic[bytenumb] = bitSet(chromatic[bytenumb], bitnumb);
    //ground latchPin and hold low for as long as you are transmitting
    digitalWrite(latchPin, 0);
    //move 'em out
    shiftOut(dataPin, clockPin, chromatic[4]);   
    shiftOut(dataPin, clockPin, chromatic[3]);   
    shiftOut(dataPin, clockPin, chromatic[2]);   
    shiftOut(dataPin, clockPin, chromatic[1]);   
    shiftOut(dataPin, clockPin, chromatic[0]);   
    //return the latch pin high to signal chip that it 
    //no longer needs to listen for information
    digitalWrite(latchPin, 1);
    
  }   
  
  else if ( (incomingByte<=127) && (action ==0) ){ //IF THE FIRST BYTE WAS A NOTE OFF MESSAGE...
     bytenumb = (incomingByte / 8);  // calculate which array byte 0 ~ 10
     bitnumb  = (incomingByte % 8);   // calculate which bit  (0 ~ 7)
     chromatic[bytenumb] = bitClear(chromatic[bytenumb], bitnumb);
     //ground latchPin and hold low for as long as you are transmitting
     digitalWrite(latchPin, 0);
     //move 'em out
     shiftOut(dataPin, clockPin, chromatic[4]);
     shiftOut(dataPin, clockPin, chromatic[3]);
     shiftOut(dataPin, clockPin, chromatic[2]);
     shiftOut(dataPin, clockPin, chromatic[1]);
     shiftOut(dataPin, clockPin, chromatic[0]);  
    
     //return the latch pin high to signal chip that it 
     //no longer needs to listen for information
     digitalWrite(latchPin, 1);
     
  } 
  
   
   
   //process Third byte - the velocity
   }else if ( (incomingByte<=127) && (action ==1) ){ // if we received note ON message load this byte in the velocity byte
    velocity=incomingByte;
    note=255;
   }else if ( (incomingByte<=127) && (action ==0) ){ // if we received note message load this byte in the velocity byte
    velocity=0;
    note=255;
   }
  }


// the shift out function
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);
}


//blinks the whole register based on the number of times you want to 
//blink "n" and the pause between them "d"
//starts with a moment of darkness to make sure the first blink
//has its full visual effect.
void blinkAll_2Bytes(int n, int d) {
  digitalWrite(latchPin, 0);
  shiftOut(dataPin, clockPin, 0);
  shiftOut(dataPin, clockPin, 0);
  shiftOut(dataPin, clockPin, 0);
  shiftOut(dataPin, clockPin, 0);
  shiftOut(dataPin, clockPin, 0);
  digitalWrite(startupBeep, 0);
  digitalWrite(latchPin, 1);
  delay(200);
  for (int x = 0; x < n; x++) {
    digitalWrite(latchPin, 0);
    shiftOut(dataPin, clockPin, 255);
    shiftOut(dataPin, clockPin, 255);
    shiftOut(dataPin, clockPin, 255);
    shiftOut(dataPin, clockPin, 255);
    shiftOut(dataPin, clockPin, 255);
    digitalWrite(startupBeep, 1);
    digitalWrite(latchPin, 1);
    delay(d);
    digitalWrite(latchPin, 0);
    shiftOut(dataPin, clockPin, 0);
    shiftOut(dataPin, clockPin, 0);
    shiftOut(dataPin, clockPin, 0);
    shiftOut(dataPin, clockPin, 0);
    shiftOut(dataPin, clockPin, 0);
    digitalWrite(startupBeep, 0);
    digitalWrite(latchPin, 1);
    delay(d);
  }
}

void killAll_2Bytes(int n, int d){
  digitalWrite(latchPin, 0);
  shiftOut(dataPin, clockPin, 0);
  shiftOut(dataPin, clockPin, 0);
  shiftOut(dataPin, clockPin, 0);
  shiftOut(dataPin, clockPin, 0);
  shiftOut(dataPin, clockPin, 0);
  digitalWrite(latchPin, 1);
  delay(200);
  }

Not at all - appreciated being taught rather than just told, if you see what I mean.

The code as a whole doesn't look very elegant, even to my untrained eyes, but now that's working I can use it as a reference to learn how to tidy things up/write things more effectively, whilst having a failsafe to fall back on.

All good. Now I just need to work on my soldering skills...

Ok.

So after a lot of wiring and soldering, i now have a long strip of 64 LEDS, each being controlled by a different midi note, running through 8 shift registers wired up as explained in the ‘shiftOut’ tutorial.

At slow to moderate speeds this thing is working perfectly. But it’s just not running quite fast enough for what I want it to do.

I’m not sure if it is the code, or the speed of the shift registers, or the arduino itself.

During the void (setup) there is a an instruction to blink ALL the LEDS, and then this happens all 64 blink instantaneously. If I try and recreate the same effect by sending 64 midi signals, there is a staggered effect (not long - perhaps 200-300ms) but the effect is very noticeable. In addition to this, odd LEDs will hang, presumably because for whatever reason they miss their ‘note off’ commands.

If it weren’t for the fact that the Blink command deals with all the LEDs instantly I would suspect it was the shift register speed. But as it is… I am confused.

What I am hoping for is that there are some loose ends in the code I can tidy up to get that extra little boost I need.

Richard, previously you said

Furthermore, you don’t necessarily have to shift out the chromatic array into the shift registers every time through the loop, either. Maybe only every 100ms would be fast enough(?)

but I am not sure what you mean by that. Do you think this might be something that could help?

Here is the code I am using. As above, except with instructions for 8 shift registers instead of 5…

//variables setup

byte incomingByte = 255; // midi signal #1
byte note = 255; // midi signal #2
byte velocity = 255; // midi signal #3

byte bytenumb; // 
byte bitnumb; //
byte chromatic[10];   // declare chromatic scale, 8 x 11 = 88 notes

//Shift Out Pins to 74HC595s
int latchPin = 8;
int clockPin = 12;
int dataPin = 11;
int statusLed = 13;   // select the pin for the LED
int startupBeep =  6; // connect to a piezo buzzer. not strictly necessary, but use to know arduino is on & good to receive midi   
int action=2; // MIDI rules: 0 =note off ; 1=note on ; 2= nada


//setup: declaring iputs and outputs and begin serial 
void setup() {

pinMode(statusLed,OUTPUT);   // declare the LED's pin as output
pinMode(latchPin, OUTPUT);  // declare latch pin as output
 
//start serial with midi baudrate 31250 or 38400 for debugging
Serial.begin(31250);        
digitalWrite(statusLed,HIGH); 
 

//function that blinks all the LEDs and then switches them off
  //gets passed the number of blinks and the pause time
  blinkAll_2Bytes(1,750);
  killAll_2Bytes(1,500);
  
  for (int i = 0; i < 11; i++){ //  (i.e. for i = 0 to 10)
chromatic[i] = 0; // resets the array.
}

  
}

//loop: wait for serial data, and interpret the message 
void loop () {
 if (Serial.available() > 0) {
   // read the incoming byte:
   incomingByte = Serial.read();

   // wait for as status-byte, channel 1, note on or off
   if (incomingByte== 144){ // note on message starting starting
     action=1;
   }else if (incomingByte== 128){ // note off message starting
     action=0;
   }else if (incomingByte > 144){ // message is anything but note message
   action=2; //nothing happens
     
      
   //process second byte 
   }else if ( (incomingByte<=127) && (action ==1) ){ // IF THE FIRST BYTE WAS A NOTE ON MESSAGE...
     bytenumb = (incomingByte / 8);  // calculate which array byte 0 ~ 10
     bitnumb  = (incomingByte % 8);   // calculate which bit  (0 ~ 7)
     chromatic[bytenumb] = bitSet(chromatic[bytenumb], bitnumb);
    //ground latchPin and hold low for as long as you are transmitting
    digitalWrite(latchPin, 0);
    //move 'em out
    shiftOut(dataPin, clockPin, chromatic[8]);  
    shiftOut(dataPin, clockPin, chromatic[7]);  
    shiftOut(dataPin, clockPin, chromatic[6]);  
    shiftOut(dataPin, clockPin, chromatic[5]);  
    shiftOut(dataPin, clockPin, chromatic[4]);   
    shiftOut(dataPin, clockPin, chromatic[3]);   
    shiftOut(dataPin, clockPin, chromatic[2]);   
    shiftOut(dataPin, clockPin, chromatic[1]);   
    shiftOut(dataPin, clockPin, chromatic[0]);   
    //return the latch pin high to signal chip that it 
    //no longer needs to listen for information
    digitalWrite(latchPin, 1);
    
  }   
  
  else if ( (incomingByte<=127) && (action ==0) ){ //IF THE FIRST BYTE WAS A NOTE OFF MESSAGE...
     bytenumb = (incomingByte / 8);  // calculate which array byte 0 ~ 10
     bitnumb  = (incomingByte % 8);   // calculate which bit  (0 ~ 7)
     chromatic[bytenumb] = bitClear(chromatic[bytenumb], bitnumb);
     //ground latchPin and hold low for as long as you are transmitting
     digitalWrite(latchPin, 0);
     //move 'em out
     shiftOut(dataPin, clockPin, chromatic[8]);  
    shiftOut(dataPin, clockPin, chromatic[7]);  
    shiftOut(dataPin, clockPin, chromatic[6]);  
    shiftOut(dataPin, clockPin, chromatic[5]);  
    shiftOut(dataPin, clockPin, chromatic[4]);   
    shiftOut(dataPin, clockPin, chromatic[3]);   
    shiftOut(dataPin, clockPin, chromatic[2]);   
    shiftOut(dataPin, clockPin, chromatic[1]);   
    shiftOut(dataPin, clockPin, chromatic[0]);   
    
     //return the latch pin high to signal chip that it 
     //no longer needs to listen for information
     digitalWrite(latchPin, 1);
     
  } 
  
   
   
   //process Third byte - the velocity
   }else if ( (incomingByte<=127) && (action ==1) ){ // if we received note ON message load this byte in the velocity byte
    velocity=incomingByte;
    note=255;
   }else if ( (incomingByte<=127) && (action ==0) ){ // if we received note message load this byte in the velocity byte
    velocity=0;
    note=255;
   }
  }


// the shift out function
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);
}


//blinks the whole register based on the number of times you want to 
//blink "n" and the pause between them "d"
//starts with a moment of darkness to make sure the first blink
//has its full visual effect.
void blinkAll_2Bytes(int n, int d) {
  digitalWrite(latchPin, 0);
  shiftOut(dataPin, clockPin, 0);
  shiftOut(dataPin, clockPin, 0);
  shiftOut(dataPin, clockPin, 0);
  shiftOut(dataPin, clockPin, 0);
  shiftOut(dataPin, clockPin, 0);
  shiftOut(dataPin, clockPin, 0);
  shiftOut(dataPin, clockPin, 0);
  shiftOut(dataPin, clockPin, 0);
  digitalWrite(startupBeep, 0);
  digitalWrite(latchPin, 1);
  delay(200);
  for (int x = 0; x < n; x++) {
    digitalWrite(latchPin, 0);
    shiftOut(dataPin, clockPin, 255);
    shiftOut(dataPin, clockPin, 255);
    shiftOut(dataPin, clockPin, 255);
    shiftOut(dataPin, clockPin, 255);
    shiftOut(dataPin, clockPin, 255);
     shiftOut(dataPin, clockPin, 255);
      shiftOut(dataPin, clockPin, 255);
       shiftOut(dataPin, clockPin, 255);
    digitalWrite(startupBeep, 1);
    digitalWrite(latchPin, 1);
    delay(d);
    digitalWrite(latchPin, 0);
    shiftOut(dataPin, clockPin, 0);
    shiftOut(dataPin, clockPin, 0);
    shiftOut(dataPin, clockPin, 0);
    shiftOut(dataPin, clockPin, 0);
    shiftOut(dataPin, clockPin, 0);
     shiftOut(dataPin, clockPin, 0);
      shiftOut(dataPin, clockPin, 0);
       shiftOut(dataPin, clockPin, 0);
    digitalWrite(startupBeep, 0);
    digitalWrite(latchPin, 1);
    delay(d);
  }
}

void killAll_2Bytes(int n, int d){
  digitalWrite(latchPin, 0);
  shiftOut(dataPin, clockPin, 0);
  shiftOut(dataPin, clockPin, 0);
  shiftOut(dataPin, clockPin, 0);
  shiftOut(dataPin, clockPin, 0);
  shiftOut(dataPin, clockPin, 0);
  shiftOut(dataPin, clockPin, 0);
  shiftOut(dataPin, clockPin, 0);
  shiftOut(dataPin, clockPin, 0);
  digitalWrite(latchPin, 1);
  delay(200);
  }