Shift registers

Hey everyone
I'm trying to figure out how to turn on/off random pins in my 595 shift register.
I can easily turn one or more on at a time, but doing that I need to follow the same pattern. Like I said, I would like to be able to monitor the state of the register and be able to randomly turn on/off pins.

I have tried some things and gotten nowhere.

Here is a snippit of code from my sketch

void setLED(int LED, int state) {
  if (state == 1) {
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, MSBFIRST, LED);
    digitalWrite(latchPin, HIGH);
    //    digitalWrite(LED, HIGH);
  } 
  else {
    //    digitalWrite(latchPin, LOW);
    //  shiftOut(dataPin, clockPin, MSBFIRST, LED);
    //digitalWrite(latchPin, HIGH);
    //    digitalWrite(LED, LOW);
  }
}

As you can see, before shift register I would just set the pin high/low and it works, but I need more pins.

Thanks in advance.

-Eric

A shiftregister doesn't work like that. It's more indirect, than just having a pin set high or low. And you cannot directly read a shiftregister's pin states (unless you connect them back to the Arduino, for instance, but that wouldn't be very practical).

The shiftout() function puts out 8 bits of data, one bit at a time, in rapid succession into a shiftregister (or whatever you connect to the corresponding pins). For this you need two output pins:

  • One for the data itself (the bits)
  • One for the clock pulses, which essentially says that one new bit is ready to be read by the shiftregister.

Essentially the shiftout() function takes care of all this, as long as the shiftregister shifts in bits on a low-to-high clock transition (which the 595 and lots others do). MSBFIRST and LSBFIRST just sets the direction of the bits.

Some shiftregisters, like the 595, have an additional latching ability, and needs an additional latch signal. It makes sure the outputs of the shiftregister stays the same (latched), even when shifting in new data, until a new latch signal is received. It varies whether this latching signal is active LOW or HIGH depending on the chip. You can look this up in the datasheet under whats called a truth table. So you need an additional output pin for latching. For the '595 it is called the "RCK" (Register Clock?) in the truth table.

Also some chips have some sort of enable/disable input, that may turn the function of the chip on or off, or put its outputs into an off-state (high-Z) or similar. You may hardwire this to always be active if you don't need to control it. the '595 have an active-low input marked as a letter "G" with a line above it (hence active-low, inverted function. I just call it "not-G"). This controls the output state of the shiftregister, and you want to have this enabled. Being active-low it needs to be low (zero volt / GND / digital zero).

There might also be other control inputs, like resets and whatnot. The '595 have an active-low shiftregister clear (marked SCLR with a line above it - "not SCLR"). You probably don't want this active, so you need to set this high (+Vcc, + 5V if this is your supply voltage).

To know what the outputs are on the shiftregister, you simply have to store it in some variable. For one 8-bit shiftregister a byte is enough (8 bits).

byte LEDstring = b11110000;  // 4 LEDs on, 4 off

To check for an individual LED (well, at least after you have shifted the data out), just check for a particilar bit postition within the byte.

if (bitRead(LEDstring, 7) == 1)  // reads and checks if the last bit position is on (0 is first (LSB), 7 is last (MSB))
{
   some code..
}

http://arduino.cc/en/Reference/BitRead

Example code (not tested on a circuit):

// Simple counting test with a latching shiftregister

const int clockPin =  10;  // for example
const int dataPin = 11;
const int latchPin = 12;

byte LEDstring = 0; // will represent the 8 LEDs.

void setup()   {                
  // set output mode
  pinMode(clockPin, OUTPUT);     
  pinMode(dataPin, OUTPUT);     
  pinMode(latchPin, OUTPUT);     

  // to make sure all outputs are LOW when starting
  digitalWrite(clockPin,LOW);
  digitalWrite(dataPin,LOW);
  digitalWrite(latchPin,LOW);
}

void loop()                     
{
  LEDstring++; // will wrap around by itself 
  shiftOut(dataPin, clockPin, LSBFIRST, LEDstring);

  // now for the latch signal, without which the result wont show on the output of the shiftregister
  digitalWrite(latchPin,HIGH);
  delayMicroseconds(10); // probably don't need this
  digitalWrite(latchPin,LOW);
  
  delay(100); // wait 100 ms before counting up
  
}

Hi,
See my post here I made the same kind of function and it is working very well:
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1267041963

Thank you
Using bitwrite I am able to do exactly what I wanted.

I have a variable up top like this

byte shiftRegister = B00000000;

and my new function looks like this

void setLED(int LED, int state) {
  shiftRegister = bitWrite(shiftRegister, LED, state);
  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, MSBFIRST, shiftRegister);
  digitalWrite(latchPin, HIGH);
}

from a first try, as in I did this change 3 minutes ago, it seems to work perfectly.

again, thank-you

Nice first try!

One thing:

shiftRegister = bitWrite(shiftRegister, LED, state);

Seems a bit superfluous. Why not just use

bitWrite(shiftRegister, LED, state);

?

I did, and it works. However using this method

void setOutput(int output, int state) {
  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, MSBFIRST, bitWrite(shiftRegister, output, state));
  digitalWrite(latchPin, HIGH);
}

makes the sketch 14 bytes bigger than using

void setOutput(int output, int state) {
  shiftRegister = bitWrite(shiftRegister, output, state);
  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, MSBFIRST, shiftRegister);
  digitalWrite(latchPin, HIGH);
}

I would have thought that to be the other way around. Weird.

But using

void setOutput(int output, int state) {
  [glow]bitWrite(shiftRegister, output, state);[/glow]
  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, MSBFIRST, shiftRegister);
  digitalWrite(latchPin, HIGH);
}

will also be 14 bytes less than the other method.

I thought it strange that "shiftRegister = bitWrite(shiftRegister, output, state);" worked. Probably the function returns the value it has manipulated, as well as manipulate it.

void setOutput(int output, int state) {
  bitWrite(shiftRegister, output, state);
  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, MSBFIRST, shiftRegister);
  digitalWrite(latchPin, HIGH);
}

Works exactly the same, and is exactly the same size when compiled. The only difference is cleaner code, which we all like. So this is how I'm doing it.

Thanks very much :wink: