Tutorial: Shift Registers

IMG_1168Introduction

Got that project that requires more pins than what’s available on your Arduino? Shift registers are a way to expand the number of outputs on your microcontroller. In this tutorial, we’ll examine how a shift register works and how to connect it all up with an Arduino Uno.

The Chip

The shift register that we’ll be using in this tutorial is 74HC595N. This shift register has 8-bit serial input, 8-bit serial or parallel output, and a storage register with 3-state outputs (HIGH, LOW, HIGH-Z or high impedance). Let’s take a moment to see what all this means.

Serial and parallel are ways of describing the way data is transmitted. Serial output means that one bit of data is being transmitted at a time through one pin. In a parallel data transmission, all bits of data are sent out at once where each bit gets its own pin. For this specific chip, this means that we input data one bit at a time through one pin (serial), and have all 8 bits of data output on 8 different pins (parallel) or each bit one at a time through one pin (serial).

The storage register can have three states: HIGH, LOW, or HIGH-Z. The last one, HIGH-Z, means high impedance where the output does not affect the circuit. This is controlled by one pin and affects all outputs.

Now that we know a few features of the chip, lets take a look at the pinout.

pinoutThis diagram was taken directly from the datasheet. Here’s a description of the pins:

Vcc and GND are power and ground for the shift register, respectively.

Q0-Q7 are our parallel outputs. Q7S on pin 9 is our serial output.

DS is serial input where we input our data.

/OE is our output enable pin (active LOW). This pin can be used to enable or disable all output pins. It can also be connected to a pin on an Arduino to PWM all pins.

STCP is the shift register clock input, or latch. This pin is used to send all of the data in the storage register to the output.

SHCP is the storage register clock input, or clock. This is the clock that basically keeps the bits in the storage register moving, or shifting.

/MR is the master reset (active LOW).

How it works

Here is the timing graph in the datasheet:

timingdiagram

The timing graph is a bit confusing because they always try to show off all of the different combinations. It may come in handy in my explanation, but I’m going to explain it in the way that we’re going to use it.

To send 8 bits into the storage register, we’re going to pulse the clock (SHCP) 8 times. Remember that we’re doing this serially through the DS pin. On every pulse of the clock, we set DS HIGH or LOW depending on the bit and which clock pulse we’re on. For example, if we’re going to set the storage register to 1001 1101, we would set DS to HIGH on the first, third, fourth, fifth, and eighth clock pulses. Once we’ve got all of our bits of data into the storage register, we pulse the latch pin (STCP) which will set our outputs, Q0-Q7.

But what if you want to use more than one shift register by “daisy chaining” them? What’s going on there?

Remember that in addition to the parallel outputs on Q0-Q7, we also have a serial output on Q7S (sometimes noted as Q7′) which we connect to the data (DS) pin of the next shift register. Once the storage register of the first shift register is full, the bits then get shifted through Q7S to the next shift register as the clock pulses. The first bit on the first shift register is shifted onto the second shift register on the 9th clock pulse, and so on. In our code that you’ll see soon, we keep shifting all the way to the end of our last shift register before we pulse our latch pin which sets the outputs on all three shift registers.

Circuit

Here’s the schematic we’ll be using:
connectiondiagramThis is really the most you’ll need as continuing the chain is very simple. All you have to do is connect pin 9 (Q7S) of the previous shift register to pin 14 (DS) of the next shift register. I added a capacitor between power and ground on the schematic but I forgot to when I set it up on my breadboard. It’s used to condition the power so it’s not completely mandatory…

picThis is what I set up for this tutorial. There are three shift registers with all 24 (8×3) outputs connected to a blue LED.

As you keep expanding your outputs, you’re going to be drawing more and more current. Consider using an external power supply.

Code

I did some modifications to Code Sample 1.3 on the ShiftOut tutorial. My code starts with all of the LEDs on, chases the LEDs off then back on again. The .ino file is available for download below. Let’s go through the entire program piece by piece to see what’s going on.

int latchPin = 3;
int clockPin = 2;
int dataPin = 4;

void setup() {
pinMode(latchPin, OUTPUT);
}

We assign numbers to variables that represent the latch, clock, and data pins as connected to the Arduino. On the shift register chip, these are pins 12,11, and 14, respectively. We set latchPin as an output.

void shiftOut(int myDataPin, int myClockPin, byte myDataOut) {
int i=0;
int pinState;
pinMode(myClockPin, OUTPUT);
pinMode(myDataPin, OUTPUT);

digitalWrite(myDataPin, 0);
digitalWrite(myClockPin, 0);

for (i=7; i>=0; i–) {
digitalWrite(myClockPin, 0);

if ( myDataOut & (1<<i) ) {
pinState= 1;
}
else {
pinState= 0;
}

digitalWrite(myDataPin, pinState);
digitalWrite(myClockPin, 1);
digitalWrite(myDataPin, 0);
}

digitalWrite(myClockPin, 0);
}

This is the function that we use to send data to the shift registers. Before the for loop, we’re just initializing the clock and data pins. In every count of the for loop, we compare the data (8 bits) to 1 (0000 0001) that is shifted on every count of the for loop. For example, if i=3, we compare our data, let’s say 1010 1010, to 0000 1000 (remember, i starts at 0) so the data, or pinState, would be 1. For this case, we’d set the data pin to 1, then we pulse the clock to put it in the register. After we’re done, we set the data and clock pins back to 0.

void loop() {
byte data[3]={0xFF,0xFF,0xFF};

for(int group=2; group>=0; group–){
for(int steps=0; steps<9; steps++){
if(steps==0) data[group] = 0xFF;
if(steps==1) data[group] = 0xFE;
if(steps==2) data[group] = 0xFC;
if(steps==3) data[group] = 0xF8;
if(steps==4) data[group] = 0xF0;
if(steps==5) data[group] = 0xE0;
if(steps==6) data[group] = 0xC0;
if(steps==7) data[group] = 0x80;
if(steps==8) data[group] = 0x00;
digitalWrite(latchPin, 0);
shiftOut(dataPin, clockPin, data[0]);
shiftOut(dataPin, clockPin, data[1]);
shiftOut(dataPin, clockPin, data[2]);
digitalWrite(latchPin, 1);
delay(50);
}
}
for(int group=0; group<3; group++){
for(int steps=0; steps<8; steps++){
if(steps==7) data[group] = 0xFF;
if(steps==6) data[group] = 0xFE;
if(steps==5) data[group] = 0xFC;
if(steps==4) data[group] = 0xF8;
if(steps==3) data[group] = 0xF0;
if(steps==2) data[group] = 0xE0;
if(steps==1) data[group] = 0xC0;
if(steps==0) data[group] = 0x80;
digitalWrite(latchPin, 0);
shiftOut(dataPin, clockPin, data[0]);
shiftOut(dataPin, clockPin, data[1]);
shiftOut(dataPin, clockPin, data[2]);
digitalWrite(latchPin, 1);
delay(50);
}
}
}

This is the code that I wrote for myself. We initialize three bytes (8 bits) of data for the three registers as 0xFF which would be 1111 1111 in binary. The “group” variable in the first for loop represents the three shift registers and their groups of LEDs. The “steps” variable is used to change the states of the LEDs from all on to all off and the states in between. After the “steps” for loop is over, it moves onto the next register because of the “group” for loop. Remember that they were initialized as 0xFF so all of the LEDs are sent as 1’s unless it’s changed by the “steps” for loop.

Notice that we call shiftOut three times. The shiftOut function sends one byte of data at a time, so when we call it three times, the data keeps shifting through the Q7S pin to the next register until we’ve got all three bytes of data across the three SRs. Once we’ve sent the three bytes, only then we set the latch pin to HIGH which sets all of the outputs (Q0-Q7) on the SRs.

Links & Downloads

74HC595N Datasheet

Buy these shift registers from Adafruit

ShiftOut tutorial on the Arduino website

My example code (It’s not documented, just come back here if you need a reference.)

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s