Introduction: The 74HC164 Shift Register and Your Arduino

Shift registers are a very important part of digital logic, they act as glue in between the parallel and serial worlds. They reduce wire counts, pin use and even help take load off of your cpu by being able to store their data.

They come in different sizes, with different models for different uses, and different features. The one I will be discussing today is the 74HC164 8 bit, serial in parallel out, non latched, shift register.

Why? Well for one it is one of the most basic shift registers out there, which makes learning about it easier, but it just so happened to be the only one I had (lol!)

This instructable covers how this chip works, how to wire it, and interface it with an arduino including some sample sketches and led circuits.

I hope you all enjoy!



Step 1: So, What Are Shift Registers?

As mentioned earlier they come in all different flavors, and I also mentioned that I am using a 74HC164 8 bit, serial in parallel out, non latched, shift register

so what does that all mean?!?

First, the name
74 -- means its part of the 74xx logic family, and since its logic it cannot directly control very much current  (16-20ma for the entire chip is common) , it only passes signals around, but that does not mean that signal is not going to a transistor which can switch a higher current load.

HC means its a high speed cmos device, you can read about that on the link below, but what you basicly need to know about that is that it is a  low power device and will run from 2 to 5 volts (so if your using a 3.3 volt arduino your ok)

Also it can work properly at high speeds this particular chip has a typical speed of 78mhz, but you can go as slow or as fast (until it starts goofing up) as you want
www.kpsec.freeuk.com/components/74series.htm

164 is the model number for this chip, there is a large chart of them on wikipedia
en.wikipedia.org/wiki/List_of_7400_series_integrated_circuits

Next, 8 bit
A shift register is made up of flip flop circuits, a flip flop is 1 bit of memory, this one has 8 (or 1 byte of memory). Since it is memory, if you do not need to update the register you can just stop "talking" to it and it will remain in whatever state you left it, until you "talk" to it again or reset power.

other 7400 logic series shift registers can go upto 16 bit

serial in parallel out

This means your arduino sends it data serially (on off pulses one after another) and the shift register places each bit on the correct output pin. This model only requires 2 wires to be controlled, so you can use 2 digital pins on the arduino, and break those 2 out to 8 more digital outputs

some other models are parallel in serial out, they do the same thing but as inputs to the arduino (for example a NES gamepad)

non latched

This may be a downfall of this chip if you need it. As data enters a shift register via serial, it shows up on the first output pin, when a clock pulse enters in, the first bit shifts over 1 place, creating a scrolling effect on the outputs, for example 00000001 would show up on the outputs as

1
01
001
0001
00001
000001
0000001
00000001

If your talking to other logic devices who are sharing the same clock and not expecting this, it  could cause issues. Latched shift registers have an extra set of memory, so once the data is done entering the register you can flip a switch and show the outputs, but it adds another wire, software, and things to keep up with.

In the case of this instructable we are controlling LED displays, the scrolling effect happens so fast you cant see it (except when you very first turn on the chip), and once the byte is in the shift register there is no more scrolling

We will be controlling bargraph type, 7 segment, and a 16LED 4x4 dot matrix with this chip and software on the arduino using only 2 digital pins (+ power and ground)



Step 2: Basic Wiring and Operation

Wiring
The 74HC164 is a 14 pin chip, it has 4 input pins, 8 output pins, power and ground, so lets start from the top.

Pins 1 and 2 are both serial inputs, they are setup as a logical AND gate, meaning that they both have to be logic high (ie 5 volts) in order for the bit to be seen as a 1, a low state (0 volts) on either will read as a zero.  We dont really need this and its easier to deal with in software, so choose one and tie it to V+ so it always reads high. I choose to use a jumper from pin 1 to pin 14 (V+) since you can just pop a breadboard jumper over the chip. The one remaining serial input (pin 2 in my schematics) will goto digital pin 2 of the arduino.

Pins 3,4,5,and 6 of the 74HC164 are the first 4 bytes of output

Pin 7 connects to ground

Jumping to the right, pin 8 is the clock pin, this is how the shift register knows the next serial bit is ready for it to read, this should be connected to digital pin 3 on the arduino.

Pin 9 is to clear the entire register at once, if it goes low, you have the option to use it, but nothing in this inscrutable does, so tie it to V+

pins 10, 11 12 and 13 are the last 4 bytes of output

pin 14 is the chips power

Operation
First you need to set the serial input of the register (digital pin 2 on the arduino) high or low, next you need to flip the clock pin (digital pin 3) from low to high, the shift register will read the data on the serial input and shift the output pins by 1, repeat 8 times and you have set all 8 outputs.

This can be done by hand with for loops and digital writes in the arduino IDE, but since this is a very common hardware level communications (SPI) they have a single function that does it for you.

shiftOut(dataPin, clockPin, bitOrder, value)

Just tell it where the data and clock pins are connected to the arduino, which way to send the data and what to send, and its taken care of for you (handy)

Step 3: Projects

Okay, enough lecture and theory, lets do some fun stuff with this chip!

There are 3 projects to try in this instructable, the first 2 are easy and can be breadboarded out in moments. The third one, the 4x4 led matrix, requires more time and thought to construct, due to the led wiring.

List of parts

Project 1: '2 Wire' bargraph LED displaycontroller
1 * 74HC164 Shift register
1 * solderless breadboard
1 * arduino, or arduino compatible (5v)
1 * 330 ohm 1/4 watt resistor
8 * normal output red LED's
12 * jumper wires

Project 2: '2 Wire' 7 segment display controller

1 * 74HC164 Shift register
1 * solderless breadboard
1 * arduino, or arduino compatible (5v)
1 * 330 ohm 1/4 watt resistor
1 * common cathode seven segment display
9 * jumper wires

Project 3: '2 Wire' 4x4 led matrix display
1 * 74HC164 Shift register
1 * arduino, or arduino compatible (5v)
4 * 150 ohm 1 1/4 watt resistor
8 * 1Kohm 1/8 watt resistor (or larger)
8 * NpN transistor (2n3904 or better)
16 * normal output red LED's

a means to construct it and regulated 5 volt power that can handle 160+ma (you can turn on all the LED's at once like a brake light)


Step 4: Project 1[pt 1]: '2 Wire' Bargraph LED Display Controller Hardware

Hook up the arduino and shift register according to the schematic, I already have a 10 segment bargraph display ready for breadboard use and that is what you will see in the image, but you can do the same thing  with individual led's

On the second page I stated that these were not driver devices, that they were logic devices, with tiny amounts of current able to pass through them. In order run 8 LEDs, while keeping the circuit simple, and not cooking the shift register, requires that we limit the current quite a bit.

The LED's are wired in parallel and share a common ground (common cathode), before going into the power supply ground they need to pass through a 330 ohm resistor, limiting the total amount of current that all the LED's could possibly use to 10ma (at 5 volts)

This leaves the LED's in a sickly looking state but they do light up and thus serve for this example, in order to drive the LED's at their proper current you will need to insert a transistor where the shift register can turn on / off a higher current source (see project 3)

The Data pin of the shift register (pin 2) needs to connect to arduino digital pin # 2
The Clock pin of the shift register (pin 8) needs to connect to arduino digital pin # 3

Step 5: Project 1[pt 2]: '2 Wire' Bargraph LED Display Controller Software

Example 1:
Open the file " _164_bas_ex.pde" Inside the arduino IDE, Its a simple sketch that just lets you define on or off  LED's in the bargraph display

The first 2 lines define the pin numbers we will be using for data and clock, I use #define over const integer, I find it easier to remember, and there is no advantage to one or the other once compiled

#define data 2
#define clock 3


next is the void setup function, it only runs once, so the arduino turns on, sets the shift register and has nothing else to do. Inside the void setup function we set the clock and data pins as OUTPUT pins, then using the shiftOut function we send the data to the shift register

void setup()
{
  pinMode(clock, OUTPUT); // make the clock pin an output
  pinMode(data , OUTPUT); // make the data pin an output
  shiftOut(data, clock, LSBFIRST, B10101010); // send this binary value to the shift register
}


In the shiftOut function you can see its arguments
data is the data pin, clock is the clock pin

LSBFIRST refers to what order its in, when writing it out in binary notation (Bxxxxxxxx) the 7th element past the B is the Least Signifigant Bit First, this is fed in first so it ends up on the last output once all 8 bits are fed in

B10101010 is the Binary value being sent to the shift register, and it will turn on every odd light, try playing with different values to turn on or off different patterns

and finally a empty void loop (because you need one even if your not using it)

void loop(){} // empty loop for now


Example 2:
the first 8 lines are the same as the first 8 lines of the first example, in fact they will not change for any of the other projects, so

#define data 2
#define clock 3

void setup()
{
  pinMode(clock, OUTPUT); // make the clock pin an output
  pinMode(data , OUTPUT); // make the data pin an output


But now in void setup there is an 8 count for loop, its taking an empty byte and shifting 1 bit in at a time starting from the leftmost bit and moving right. This is backwards from the first example where we started from the rightmost bit and worked left, but using MSBFIRST the shift out function sends the data the correct way

Also we add a delay in the for loop so it slows down enough to be visible.

  for(int i = 0; i < 8; ++i) //for 0 - 7 do
  {
    shiftOut(data, clock, MSBFIRST, 1 << i); // bit shift a logic high (1) value by i
    delay(100); // delay 100ms or you would not be able to see it
  }

}

void loop(){} // empty loop for now


upload the script and you should now see the bargraph light up each light one at a time



Step 6: Project 2: '2 Wire' 7 Segment Display Controller

Look at the pinout of your 7 segment display (I only had a dual one but just using half) and use the drawing below to connect each segment to the correct bit on the shift register

bit 1 = pin 3
bit 2 = pin 4
bit 3 = pin 5
bit 4 = pin 6
bit 5 = pin 10
bit 6 = pin 11
bit 7 = pin 12
bit 8 = pin 13 (if you want to use the decimal point)

And the cathode of the display through the 330ohm resistor and to power supply ground

now open the seven_seg_demo.pde in the arduino IDE

First you see where we define the data and clock pins

#define data 2
#define clock 3


Next we set all of the charater patterns in binary, this is pretty easy, look at the drawing below, if you need the middle segment type in a one, next do you need the top segment, if so  type in another one, keep doing this until you cover all 8 segments, notice my rightmost bit (bit 8) is always 0, thats becuase i never turn on the decimal point.

byte zero  = B01111110;
byte one   = B00000110;
byte two   = B11011010;
byte three = B11010110;
byte four  = B10100110;
byte five  = B11110100;
byte six   = B11111100;
byte seven = B01000110;
byte eight = B11111110;
byte nine  = B11110110;


next in void setup we set our data and clock pins to outputs

void setup()
{
  pinMode(clock, OUTPUT); // make the clock pin an output
  pinMode(data , OUTPUT); // make the data pin an output3
}


then in void loop we use shiftOut to display each pattern (number) wait 1/2 a second and display the next, 0 to 9, since its being done in the void loop function it will count 0-9 and repeat forever.

void loop()
{
    shiftOut(data, clock, LSBFIRST, zero);
    delay(500);
    shiftOut(data, clock, LSBFIRST, one);
    delay(500);
    shiftOut(data, clock, LSBFIRST, two);
    delay(500);
    shiftOut(data, clock, LSBFIRST, three);
    delay(500);
    shiftOut(data, clock, LSBFIRST, four);
    delay(500);
    shiftOut(data, clock, LSBFIRST, five);
    delay(500);
    shiftOut(data, clock, LSBFIRST, six);
    delay(500);
    shiftOut(data, clock, LSBFIRST, seven);
    delay(500);
    shiftOut(data, clock, LSBFIRST, eight);
    delay(500);
    shiftOut(data, clock, LSBFIRST, nine);
    delay(500);
}


Step 7: Project 3[pt 1]: '2 Wire' 4x4 Led Matrix Display

The 4x4 LED matrix project is quite a bit more complex, but it is almost all in construction, I choose to make mine soldered on perfboard, but it should be possible to replicate on a breadboard , just a lot more spaced out.

The circuitry also differs in that the shift register is not directly driving the led's, instead the shift register outputs are sent through a 1Kohm resistor to the base of a NpN transistor, when the output of the bit is high, it lets enough current and voltage pass into the transistor to switch the connection tween the collector and emitter, the collectors are tied to a "sturdy" regulated 5 volts.

The emitters of the transistors are connected to 150 ohm resistors and the resistors are tied to the annodes of 4 led's in a row and limits the row to 20ma, although when drawing images on the display only 1 led is on at a time, and therefore near full brightness (near becuase they switch on and off really fast to make up the whole image)

There are 4 rows and 4 columns, each row gets a resistor and a transistor, on each column the LED's cathodes are tied together, ran into the collector of a transistor, whose base is also controlled by the shift register, and finally out to ground.

Large version of schematic
www.instructables.com/files/orig/F7J/52X0/G1ZGOSRQ/F7J52X0G1ZGOSRQ.jpg


Step 8: Project 3[pt 2]: '2 Wire' 4x4 Led Matrix Display

The shift register controls both the anode and the cathodes of the LED's in a YX format, look at the following

bit 1 = column 1 (rightmost)
bit 2 = column 2
bit 3 = column 3
bit 4 = column 4
bit 5 = row 1 (topmost)
bit 6 = row 2
bit 7 = row 3
bit 8 = row 4

To make an image draw out a 4x4 square on graph paper and fill in which ones you want displayed, next make a YX table. Below you will see a mapping for a simile, well as best one can do on 4x4 "pixels"

For each filled in section I write down which column (Y) it is in, then which row it is in (X)

Now open up the _4x4.pde file in the arduino IDE you will see our old 2 friends

#define data 2
#define clock 3


then a array of integers

int img[] = {1,1,4,1,1,3,4,3,2,4,3,4};

If you look its just a list of my written down YX coordinates, it would be a big pain in the butt to convert those values by hand, and we have a computer ... let it do it!

Moving on there is void setup where we make our clock and data pins OUTPUTS

void setup()
{
  pinMode(clock, OUTPUT); // make the clock pin an output
  pinMode(data , OUTPUT); // make the data pin an output3
}


And a confusing looking void loop, to start things off we need to declare some local variables

void loop()
{
  int Y;
  int X;
  byte out;


Then a for loop, this loop needs to be as long as the amount of entries in the img array, for this image I only used 6 pixels, so that makes 12 YX coordinates. I make it skip every other number by using i +=2, because we read 2 coordinates per loop

  for(int i = 0; i < 12; i += 2) // number of points in the img array, this case 12
  {


Now we read the Y  entery at [i] in the array, and subtract one from its value, because bytes don't start at one, they start at zero, but we counted from 1

    // get the first pair of YX cords
    Y = (img[i] - 1); // subtract one since the bit count starts at 0


Next we read the X  entery at [i + 1] in the array, and subtract one from its value, because of the same reason

  X = (img[i+1] - 1);

After we have the YX values of the pixel, we do some bitwise or math and shifting to the left.

First we need to read the X value, and whatever its value is shift it that many places + 4 left, so if X is 4 and add 4 it is bit 8 (MSB), looking at the chart again ...

bit 1 = column 1 (rightmost)
bit 2 = column 2
bit 3 = column 3
bit 4 = column 4
bit 5 = row 1 (topmost)
bit 6 = row 2
bit 7 = row 3
bit 8 = row 4

Bit 8 is the last row

Next the Y value is also shifted to the left, this time just by its self, nothing added on.

Finally the two are or'ed together into 1 byte instead of 2 half bytes (nibbles), using bitwise or (the symbol |   ) takes two bytes and basicly adds them together, lets assume

X   = 10000000
Y   = 00000001
--------------------
OR =10000001

row 4 column 1

out = 1 << (X + 4) | 1 << Y;

And finally shiftOut to display the current picture,  and keep doing that until we have no more data in the array ... delay a moment and loop forever, since we were shifting data to the left and we need the MSB to be on the last output pin of the shift register send it out first.

  shiftOut(data, clock, MSBFIRST, out); // shift the byte out to our register
    delay(1); // delay it abit so it has a chance to leave a spot of light in your eyes


Feel free to make your own images, and effects, There are 3 sample files, the smiley face and a checkerboard (which looks more like stripes), and finally a random sparkle maker


Step 9: Conclusion

Over all this is a pretty handy little chip, and I am glad I scrapped it off of a old piece of electronics headed to the trash.

It can be used for other things besides display systems, but everyone likes lights and the instant feedback of seeing whats going on is extremely helpful for the visual thinkers like I.

Also please forgive my code, I have only had the arduino since bout the third week of October, and its been a pretty big crash course. But that's the great thing about the system, if you sit down and work with it, its full of neat features that make controlling the world with an 8 bit microcontroller quite easy to do.

As always questions and comments are most welcome, and thanks for reading, I hope you learned a lot

Arduino Contest

Participated in the
Arduino Contest