Problem when expanding on the ShifOut tutorial for LEDs

Remember mine wouldn't work at all until I unplugged the 5V jumper going from the arduino to the breadboard. Once I did that, I finally got life out of it. Maybe that is a clue to some other issue. Other than that, Mine is wired just like yours. How about sending COM commands to turn each one on or off individually? Would that be a simple bit of code?

What 5V jumper? You've lost me there. There should be 5 wires going from the Arduino to the breadboard, as pictured above.

This is what it should look like:

If it doesn't, you have a wiring issue.

How about sending COM commands to turn each one on or off individually? Would that be a simple bit of code?

I'm not sure what you mean by COM commands. From where? The 11 x SPI.transfer() instructions will shift out the 11 x 8 bits (88 bits) in about 22 microseconds, much too fast to see. So all you have to do is set up the pattern you want to see in those 11 bytes before shifting it out.

It's hard to demo because I don't have 32 LEDs plugged in.

Say you want every second LED on. Then each byte would be 0xAA. It might be easier to visualize in binary ...

  digitalWrite (LATCH, LOW);
  SPI.transfer (0b00110011);  // chip 1
  SPI.transfer (0b11110011);  // chip 2
  SPI.transfer (0b00111111);  // chip 3
  SPI.transfer (0b00000011);  // chip 4
  SPI.transfer (0b00110000);  // chip 5
  SPI.transfer (0b11111111);  // chip 6
  SPI.transfer (0b01111011);  // chip 7
  SPI.transfer (0b00010011);  // chip 8
  SPI.transfer (0b00110011);  // chip 9
  SPI.transfer (0b00110011);  // chip 10
  SPI.transfer (0b00110011);  // chip 11
  digitalWrite (LATCH, HIGH);

Where there is a 1, the LED will be on. It's your job to make nice patterns, one way or another.

David82:
Remember mine wouldn't work at all until I unplugged the 5V jumper going from the arduino to the breadboard. Once I did that, I finally got life out of it. Maybe that is a clue to some other issue. Other than that, Mine is wired just like yours. How about sending COM commands to turn each one on or off individually? Would that be a simple bit of code?

You cant just chose what you feel like wiring and what not... Things have a reason to be on the schematic, including decoupling caps... Otherwise, its quite normal it wont work properly !!

If I unplug the 5v jumper on the arduino, the LEDs light up and flash/blink. If it's plugged in, nothing works. See green arrow in image below. By COM commands I'm saying I want to be able to use the Serial Monitor to tell each and any individual LED to turn on or off. Once i'ts finally at that level, I can begin to write the software for it.

Have u tried do what you was advised and connect the MOSI to the forward chips, individually to see if they work? That would definitely help you to first and foremost identify which section is causing the issues in the wiring, it seems.
You need to follow some kind of logic when re-checking all the wiring to troubleshoot.

Yep. They all blink randomly (as designed?). If I move MOSI to the forward chips, just the chips from there down work as they should. Can we move on now to turning specific LEDs on and off by command using the Serial Monitor? The whole key to this is I have to be able to send commands to it to have specific LEDs light up when I tell them to.

Mine blink on and off at exactly 200 mS intervals. There is nothing random about it. The first four should look like the video I posted, if you have the LEDs on pin 15 like I did.

Can we move on now to turning specific LEDs on and off by command using the Serial Monitor? The whole key to this is I have to be able to send commands to it to have specific LEDs light up when I tell them to.

Yes you can do that. You would need to take serial data (and only you know what your plan is) and end up converting it into those 11 bytes that get sent to the shift registers.

You may get some ideas for achieving the serial part here:

I understand how to send serial data to the arduino and the code involved but I have no idea what command, in code, turns each specific LED on. It would be something like, SPI.transfer (); There would be a loop listening for serial commands. The command data would contain the specific LED address and whether it needs to be on or off. The LED would stay on unless told to turn off. IF, for example, the first LED was told to turn on, and then told to turn on several more times without being told to turn off, it should just stay on. Something tells me that this bizarre configuration will have the lit LED sliding down the chain of LEDs instead of staying on in one place. The idea seems simple in theory, but for whatever reason, not so simple with this configuration. DO you have any idea what the code would look like because I haven't a clue for this setup?

There is no way of turning on or off one LED with a shift register, per se. That's the whole design. The shift register(s) work by sending out one bit after another. So the only way of changing a single one of those LEDs is to send all 88 bits again. As I said before, that is so fast you won't notice it, plus I think the registers don't "commit" the change until you bring the latch high again.

So you need to have in memory the data for all 11 chips. An array might be useful, eg.

const byte numberOfChips = 11;

byte LEDdata [numberOfChips] = { 0b00110011, 0b11110011, 0b11110011 };  // initial pattern

void refreshLEDs ()
  {
  digitalWrite (LATCH, LOW);
  for (byte i = 0; i < numberOfChips; i++)
    SPI.transfer (LEDdata [i]); 
  digitalWrite (LATCH, HIGH);
  } // end of refreshLEDs

OK so now refreshLEDs will set all 88 LEDs to whatever bit pattern you have set up in LEDdata [numberOfChips].

Now inside that array you can tweak bits to your heart's desire. Then when you are done, just do:

refreshLEDs ();

The idea seems simple in theory, but for whatever reason, not so simple with this configuration.

It is simple. Say you have a command from the serial port to turn all LEDs off. Here is how you would do it:

if (command == 'X')  // all LEDs off
  {
  for (byte i = 0; i < numberOfChips; i++)
    LEDdata [i] = 0;
  refreshLEDs ();
  }

And to turn them all on?

if (command == 'Y')  // all LEDs on
  {
  for (byte i = 0; i < numberOfChips; i++)
    LEDdata [i] = 0xFF;
  refreshLEDs ();
  }

Using the code below I was getting weird results so I disconnected the last 5 chips and changed the numberOfChips variable to 6. Now the last 3 LEDs light up. Is that what is supposed to happen?

#include <SPI.h>

const byte LATCH = 10;

void setup ()
{
  SPI.begin ();
}  // end of setup

const byte numberOfChips = 6;

byte LEDdata [numberOfChips] = { 0b00110011, 0b11110011, 0b11110011 };  // initial pattern

void refreshLEDs ()
  {
  digitalWrite (LATCH, LOW);
  for (byte i = 0; i < numberOfChips; i++)
    SPI.transfer (LEDdata [i]); 
  digitalWrite (LATCH, HIGH);
  } // end of refreshLEDs

void loop ()
{
  refreshLEDs ();
  delay(200);
}  // end of loop

I was able to get this code to produce the results it was designed for. As for the other code not always working as expected, I was told I needed to put a capacitor of some value somewhere to limit noise. Do you think noise is an issue?

#include <SPI.h>

const byte LATCH = 10;

void setup ()
{
  SPI.begin ();
  Serial.begin(9600);
}  // end of setup

const byte numberOfChips = 11;

byte LEDdata [numberOfChips] = { 0b00110011, 0b11110011, 0b11110011 };  // initial pattern

void refreshLEDs ()
  {
  digitalWrite (LATCH, LOW);
  for (byte i = 0; i < numberOfChips; i++)
    SPI.transfer (LEDdata [i]); 
  digitalWrite (LATCH, HIGH);
  } // end of refreshLEDs

void loop ()
{
  char command = Serial.read ();
  
  if (command == 'X')  // all LEDs off
  {
  for (byte i = 0; i < numberOfChips; i++)
    LEDdata [i] = 0;
  refreshLEDs ();
  }
  if (command == 'Y')  // all LEDs on
  {
  for (byte i = 0; i < numberOfChips; i++)
    LEDdata [i] = 0xFF;
  refreshLEDs ();
  }
}  // end of loop

The more you add, the more noise will become an issue, no doubt about that !

If the LEDdata array only contains 11 elements, how in the world does that allow for the control of 88 LEDs? If, for example, I send the command of '3' through the serial monitor I could have the for loop go through the LEDdata array and whenever the for loop counter matches the command variable, it turns that LED on. But not if there is only 11 elements. Bottom line: I need to be able to send serial commands of 0-87 (or 1-88) with some sort of prefix or suffix to indicate on or off. An example of that would be the command: '3y' which would turn only the 3rd LED (out of 88 LEDs) on.

I figured out part of it

SPI.transfer (0b00110011);
Where there is a 1, the LED will be on. It's your job to make nice patterns, one way or another.

Didn't see that tidbit of info posted earlier. Now I have to write the rest of the code.

David82:
If the LEDdata array only contains 11 elements, how in the world does that allow for the control of 88 LEDs?

8 bits per byte, 11 bytes, 8 x 11 = 88.

If input was given through serial monitor such that the first two digits represented the LED to be modified and the 3rd digit represented The LED's state (on or off), I'm having the hardest time coming up with a function that keeps the previous state of all of the LEDs while allowing the state of any specific LED to be changed according to input. For example, I type 071 into serial monitor. That is supposed to turn the 7th LED on and leave the rest of the LEDs in whatever state they were in. It sounds simple but it is not simple at all to implement. Do you have any rough idea of what a function that does that would look like?

I've hooked up 16 LEDs so far, but this sketch seems to work along the lines of what you said:

// Demo sketch to turn on or off bits in a set of shift registers
// Author: Nick Gammon
// Date: 2 May 2012

#include <SPI.h>

const byte LATCH = 10;

const byte numberOfChips = 11;
const byte maxLEDs = numberOfChips * 8;

byte LEDdata [numberOfChips] = { 0 };  // initial pattern

void refreshLEDs ()
  {
  digitalWrite (LATCH, LOW);
  for (int i = numberOfChips - 1; i >= 0; i--)
    SPI.transfer (LEDdata [i]); 
  digitalWrite (LATCH, HIGH);
  } // end of refreshLEDs
  

// how much serial data we expect before a newline
const unsigned int MAX_INPUT = 10;

void setup ()
{
  Serial.begin(115200);
  SPI.begin ();
  refreshLEDs ();
} // end of setup

// here to process incoming serial data after a terminator received
void process_data (char * data)
  {
  Serial.print ("Got command: ");
  Serial.println (data);
  
  // C: clear all bits
  switch (toupper (data [0]))
    {
     case 'C':
        {
        for (int i = 0; i < numberOfChips; i++) 
          LEDdata [i] = 0;
        Serial.println ("All bits cleared.");
        refreshLEDs ();
        return;
        }
  
    // S: set all bits
    case 'S':
        {
        for (int i = 0; i < numberOfChips; i++) 
          LEDdata [i] = 0xFF;
        Serial.println ("All bits set.");
        refreshLEDs ();
        return;
        }
    
    // I: invert all bits
    case 'I':
        {
        for (int i = 0; i < numberOfChips; i++) 
          LEDdata [i] ^= 0xFF;
        Serial.println ("All bits inverted.");
        refreshLEDs ();
        return;
        }
    } // end of switch
  
  // otherwise: nnx 
  //   where nn is 1 to 89 and x is 0 for off, or 1 for on
  
  // check we got numbers
  for (int i = 0; i < 3; i++)
    if (!isdigit (data [i]))
      {
      Serial.println ("Did not get 3 digits.");
      return;
      }
      
  // convert first 2 digits to the LED number
  byte led = (data [0] - '0') * 10 + (data [1] - '0');
  
  // convert third digit to state (0 = off)
  byte state = data [2] - '0';  // 0 = off, otherwise on
  
  if (led > maxLEDs)
      {
      Serial.println ("LED # too high.");
      return;
      }
   
   led--;  // make zero relative
   
   // divide by 8 to work out which chip
   byte chip = led / 8;  // which chip
   
   // remainder is bit number
   byte bit = 1 << (led % 8);
   
   // turn bit on or off
   if (state)
     LEDdata [chip] |= bit;
   else
     LEDdata [chip] &= ~ bit;
  
  Serial.print ("Turning ");
  Serial.print (state ? "on" : "off");
  Serial.print (" bit ");
  Serial.print (led & 0x7, DEC);
  Serial.print (" on chip ");
  Serial.println (chip, DEC);
  
  refreshLEDs ();
  }  // end of process_data
  

void loop()
{
static char input_line [MAX_INPUT];
static unsigned int input_pos = 0;

  if (Serial.available () > 0) 
    {
    char inByte = Serial.read ();

    switch (inByte)
      {

      case '\n':   // end of text
        input_line [input_pos] = 0;  // terminating null byte
        
        // terminator reached! process input_line here ...
        process_data (input_line);
        
        // reset buffer for next time
        input_pos = 0;  
        break;
  
      case '\r':   // discard carriage return
        break;
  
      default:
        // keep adding if not full ... allow for terminating null byte
        if (input_pos < (MAX_INPUT - 1))
          input_line [input_pos++] = inByte;
        break;

      }  // end of switch

  }  // end of incoming data

  // do other stuff here like testing digital input (button presses) ...

}  // end of loop

Try typing "S" (and then ) which should set all bits (all LEDs on). Then "C" to clear them. And "I" to invert them.

After that you should be able to try 441 (turn led 44 on) or 440 (turn led 44 off). And so on.

Well I wired up 32 LEDs to the outputs of the 4 shift registers I had in the other photo:

It is running this sketch which just shifts the bits back and forwards:

#include <SPI.h>

const byte LATCH = 10;

const byte numberOfChips = 4;

byte LEDdata [numberOfChips];  // initial pattern

void refreshLEDs ()
  {
  digitalWrite (LATCH, LOW);
  for (byte i = 0; i < numberOfChips; i++)
    SPI.transfer (LEDdata [i]); 
  digitalWrite (LATCH, HIGH);
  } // end of refreshLEDs
  

void setup ()
{
  SPI.begin ();
}  // end of setup


void showPattern (const unsigned int p1, const unsigned int p2)
  {
  LEDdata [0] = highByte (p1);
  LEDdata [1] = lowByte (p1);
  LEDdata [2] = highByte (p2);
  LEDdata [3] = lowByte (p2);
  refreshLEDs ();
  delay (30);
  } // end of showPattern
  
void loop ()
{
unsigned int pattern;
 
  pattern = 1;
  for (int i = 0; i < 16; i++)
    {
    showPattern (pattern, pattern);
    pattern <<= 1;
    }

  pattern = 0x8000;
  for (int i = 0; i < 16; i++)
    {
    showPattern (pattern, pattern);
    pattern >>= 1;
    }    

  pattern = 1;
  for (int i = 0; i < 16; i++)
    {
    showPattern (~pattern, ~pattern);
    pattern <<= 1;
    }

  pattern = 0x8000;
  for (int i = 0; i < 16; i++)
    {
    showPattern (~pattern, ~pattern);
    pattern >>= 1;
    }    
    
}  // end of loop

Result looks more-or-less like this:

The video doesn't totally do it justice because it refreshes faster than the video frame rate.

Important note: It behaved a bit randomly until I added the decoupling capacitors (little blue things in the photo) between the +5V and Gnd line, in a few places.

I love that important note- Seems a lot of people just chose what to include and what not, instead of following schematics.Specially decoupling caps, that tend to be such pillar of the foundations.
Nick, you are a star mate; Always ready to help people. Nice to see that, specially in the times that we live