shift register basic questions

ok, I'm trying to wrap my head around shift registers all day long. I understand how they work, but I do not understand how to talk to them because every example people show of how they are talking to them does a very specific and usually very complex action, like cycling through patterns of all the lights. Not just calling for a single light to come on.

I found this tutorial code that I think is supposed to let you light just a single light, but again, doesn't actually tell you how to do that. If anyone could modify this code to just light up the #3 light, so that I can dissect how you did it, I would really appreciate it: (details on WHY I need this function are bellow the picture in case that's relevant)

//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;

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(9600);
  Serial.println("reset");
}

void loop() {
  if (Serial.available() > 0) {
    // ASCII '0' through '9' characters are
    // represented by the values 48 through 57.
    // so if the user types a number from 0 through 9 in ASCII, 
    // you can subtract 48 to get the actual value:
    int bitToSet = Serial.read() - 48;

  // write to the shift register with the correct bit set high:
    registerWrite(bitToSet, HIGH);
  }
}

// This method sends bits to the shift register:

void registerWrite(int whichPin, int whichState) {
// the bits you want to send
  byte 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);

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

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

}

I am trying to get the shift register to control a large number of indicator lights on a pinball game. The lights will come on when a target is hit, and remain on until it is told to turn off. I only point out what I need this for, because in all the tutorials and videos I have watched on shift registers, I have never seen anyone use them for anything other than shifting through pre-set cycles of running lights and paterns. So I do not know if that's all shift registers are capable of.

Here's what it looks like: If you want to light LED #3, then send a 3 to function registerWrite(), rather than something that comes in from the serial port.

   registerWrite(3, HIGH);

Does that work?

Here are 2 links that were very useful for me, so should be for you too:

To control a number of lights with a shift register, you shift out all of the lights every time you want to change one.

If your lights are ooxooxxoo and you want to turn off the fourth light, you shift out the entire string oooxxoxxoo. So it takes time, but that’s the tradeoff. Your shift register is faster than the arduino itself, so you don’t need delays and whatnot. Just blatt the whole lot out each time. There’s only noticeable flicker if you have a lot of lights and update them very frequently. If the flicker is a problem, then you can get shift registers with internal latches.

A bit late to the party, but this might be useful. It's a function I wrote that lets you set individual outputs on an arbitrary number of chained shift registers. Just change QUANT_REG according to your needs.

/******************************************************************************************
 * setLocus. A function for easily turning on or off any specified output ("locus") on an
 * arbitrary number of chained shift registers--eg, 74HC595s. Usage similar to digitalWrite.
 * 
 * MOA:
 *   - Initialize array with cell for each register: cell[QUANT_REG]
 *   - Determine which cell[n] will store the locus
 *   - Determine position of locus in cell
 *   - Load locus into its cell: bitWrite(cell[n], cellPosition, state)
 *   - Step through and SPI.transfer all cells
 ********************************************************************************************/

#define CLOCK 4              // Shift register control
#define LATCH 5              // aka strobe
#define DATA 6
const byte QUANT_REG = 15;   // Number of 8-bit shift registers (equiv--eg, QUANT_REG for
                             // a single A6818 32-bit shift register would be 4)
byte cell[QUANT_REG];        // Array of cells holding all loci

void setup() {
  pinMode(LATCH, OUTPUT);    // Initialize outputs
  pinMode(CLOCK, OUTPUT);
  pinMode(DATA, OUTPUT);
  Serial.begin(115200);
}

void loop() {
  setLocus(6, HIGH);        // Eg, turn on output 6 (counting from 0)
  idle();
}

//------------------------- setLocus -------------------------+
void setLocus(byte locus, byte state) {
  byte cellPosition = 0;
  byte cellNumber = locus / 8;                                  // Calculate which cell will hold locus...
  if (cellNumber > 0) cellPosition = locus % (cellNumber * 8);  // ... and position of locus within cell
  else cellPosition = locus;                                    // If test prevents modulo from dividing by 0
  bitWrite(cell[cellNumber], cellPosition, state);              // Write locus to cell
  digitalWrite(LATCH, LOW);
  for (int n = QUANT_REG - 1; n >= 0; n--) {
    shiftOut(DATA, CLOCK, MSBFIRST, cell[n]);                   // Transfer all cells out to shift registers
  }
  digitalWrite(LATCH, HIGH);
}

//------------------------- idle -----------------------------+
void idle() {
  Serial.println("");
  Serial.println(F("idling..."));
  for(;;){}                         // Do nothing in no-exit loop
}

--Michael

One more detail. On line 33 ("void setLocus(byte locus, byte state)"), you might have to change byte locus to int, depending on how many outputs you're controlling. I've got a test setup that controls 240 (30 chained '595s).
--Michael

#define CLOCK 4              // Shift register control
#define LATCH 5              // aka strobe
#define DATA 6
:
:
  for (int n = QUANT_REG - 1; n >= 0; n--) {
    shiftOut(DATA, CLOCK, MSBFIRST, cell[n]);                   // Transfer all cells out to shift registers
  }

Why not use SPI.transfer to send data out? Outputs can then be changed much faster.

Typically I do, but I thought for a novice learning shiftOut, this would be better.
--Michael

ok I got the outputs working!

new question.

I have quite a few inputs I need to manage. Is it possible to manage them on the same shift register daisy chain as the shift outputs?

If not, how does one set up a different shift register that doesn't conflict with the first ones commands?

sorry if that's vague. I'm setting up a test now. I'll have more specific info and images once its hooked up.

I have quite a few inputs I need to manage. Is it possible to manage them on the same shift register daisy chain as the shift outputs?

I don't really understand your question, but I would say: no. Input and output shift registers would at least need a separate slave select line. I certainly don't see how you could daisy-chain them together.

See shift register - output and shift register - input