Thursday, February 24, 2011

Saving I/O Pins by using "Parallel-in Serial-Out" Shift Registers (SN74HC165)

SN74HC165N "Parallel-in/Serial-out" Shift Register
 


INTRO:
     In one of my previous articles I wrote about the SN74HC595 which is a shift register that takes serial input and gives parallel output.  This article is about the SN74HC165N which is also a shift register but it takes parallel input and gives serial output.

Why?:
     Why would you want parallel input?  Perhaps a video game controller?    For example, the NES used this type of shift register for its gamepad and the SNES used two of them.  In my case I decided to hook up eight push-button switches to the shift register.  Because I used a shift register I only needed to use 3 I/O pins instead of 1 I/O pin per button.  This leaves me with more I/O pins available for other purposes such as sensors.  The Arduino has 19 I/O pins with 17 of them usable so saving I/O pins can be a big deal.

MORE INFO:
     So, like the SN74HC595, the SN74HC165 only needs three I/O pins to operate and it can be daisy-chained.  So with only a data pin, a clock pin, and a latch pin you can have eight buttons or more.  The SN74HC165 also has a "clock inhibit" pin which if tied HIGH will cause the chip to not accept clock pulses.  This pin is active low.  This is somewhat confusing but was clarified by another version of the chip's datasheet which referred to the pin as "Clock Enable."  So, if you want to accept clock input then you will need to tie it LOW.  In fact, just keep it that way because with an Arduino you can control the clock pulses.  I think that perhaps the "clock inhibit" pin is useful in situations where you have an external clock that you can not control.

HOW TO:
     Here is a simple function to operate the chip:

void readit()
{
  digitalWrite(pLatch, LOW);  delayMicroseconds(5);  digitalWrite(pLatch, HIGH);
  button1state = digitalRead(pIN);   digitalWrite(pClock, HIGH);   delayMicroseconds(5);   digitalWrite(pClock, LOW);
  button2state = digitalRead(pIN);   digitalWrite(pClock, HIGH);   delayMicroseconds(5);   digitalWrite(pClock, LOW); 
  button3state = digitalRead(pIN);   digitalWrite(pClock, HIGH);   delayMicroseconds(5);   digitalWrite(pClock, LOW);
  button4state = digitalRead(pIN);   digitalWrite(pClock, HIGH);   delayMicroseconds(5);   digitalWrite(pClock, LOW);
  button5state = digitalRead(pIN);   digitalWrite(pClock, HIGH);   delayMicroseconds(5);   digitalWrite(pClock, LOW);
  button6state = digitalRead(pIN);   digitalWrite(pClock, HIGH);   delayMicroseconds(5);   digitalWrite(pClock, LOW);
  button7state = digitalRead(pIN);   digitalWrite(pClock, HIGH);   delayMicroseconds(5);   digitalWrite(pClock, LOW);
  button8state = digitalRead(pIN);   digitalWrite(pClock, HIGH);   delayMicroseconds(5);   digitalWrite(pClock, LOW);
}

WHAT IS HAPPENING?:
     What happens is that you need to set the latch pin to LOW and hold it LOW for a short time and then set the latch pin HIGH again.  This causes the shift register to record the state of all the parallel lines and keeps it in memory.  Next, the clock pin needs to be pulsed from LOW to HIGH and do eight digital reads in order to get each bit of the shift register's memory.  In my example I just simply assigned each digital read to a different variable.
    You could also use a FOR loop and use some bit shifting to shift (<<) each read into a buffer variable.  Later, the buffered data could be AND'ed with an appropriate bit mask to check what the state of each button was.  The example code on the Arduino Playground does something very similar to this idea.

EXAMPLE IDEAS:
     The following is a picture of the test circuit that I used.  I used 4.7k pull-down resistors on the button outputs and a 470 ohm resistor on each parallel input.  I have included the code for this example below the picture.  Enjoy!  And if would like to comment on this article or want to discuss this shift register then please comment below.

 
 
 
References:
Datasheets:

Arduino Playground - ShiftRegSN74HC165N
 

4 comments:

  1. I have a couple of these SN74HC165 that I would like to use for output. Can you tell me more about the circuit wiring?

    ReplyDelete
  2. These chips are for input. They allow you to use multiple inputs (such as buttons) while only needing a few I/O lines from your microprocessor. You have a data line, clock line and a latch. When you "latch" it, the shift register records the current state of all the buttons connected to it. Afterwards, you read the data line and then pulse the clock line for each of the 8 buttons (or more if you use daisy-chaining.)

    ReplyDelete
  3. Dropbox link to the code isn't available anymore. I'm stuck with wiring. All seems ok, but only eight button works and in sends all buttons states to 1.
    I'm using pull-up 10k resistors and no resistors on parralel input (can't understand, why do you need them anyway).
    Is there any comfortable way to get in touch with you, except this blog?
    Thanks.

    ReplyDelete
    Replies
    1. Thanks for letting me know! I have fixed the link. It now points to a .zip file that has 4 different versions of the code. Each version handles the actions differently. You can gather part of my email address from my blog URL. (Spambots are evil nowadays.) I am at yahoo though.

      Delete

Keep it clean. :)