0% found this document useful (0 votes)
366 views26 pages

Arduino Shift Registers: 74HC595 & 74HC165

The document discusses using shift registers to expand the input/output capabilities of an Arduino. It describes how shift registers work, the different types (serial in parallel out, parallel in serial out), and provides examples of the 74HC595 and 74HC165 shift registers. It then shows how to connect a 74HC595 to an Arduino in order to control 8 LEDs using only 3 Arduino pins, expanding its digital output without using additional pins.

Uploaded by

chafic WEISS
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
366 views26 pages

Arduino Shift Registers: 74HC595 & 74HC165

The document discusses using shift registers to expand the input/output capabilities of an Arduino. It describes how shift registers work, the different types (serial in parallel out, parallel in serial out), and provides examples of the 74HC595 and 74HC165 shift registers. It then shows how to connect a 74HC595 to an Arduino in order to control 8 LEDs using only 3 Arduino pins, expanding its digital output without using additional pins.

Uploaded by

chafic WEISS
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

Shift Registers – 74HC595 & 74HC165 with Arduino

I’ve got a few shifty characters with me today but don’t worry, I’ll show you how to
control them and expand the capabilities of your Arduino. And, as a bonus, we’ll
build a fancy LED light display.

Introduction
Today we will work with a couple of basic electronics “building blocks”, shift
registers.  These handy devices are used for all sorts of purposes like data conversion,
buffering and storage, but today we will be seeing how they can also be used to
expand the number of digital I/O ports on an Arduino or other microcontrollers.
By learning to use shift registers you’ll be adding another handy tool to your
designers’ toolkit.

Expand your Arduino


Arduino’s have a number of digital I/O ports already, in fact, the Arduino Mega 250
boasts 54 digital I/O pins plus another 16 analog inputs that can double as digital I/O
pins.  So with 70 potential I/O pins you don’t usually have a need for more.
But sometimes you actually do need more.
Take the familiar “LED Cube”. A cube with a 4x4x4 dimension would require 64
LEDs, within the capability of an Arduino Mega 2560 if you “borrow” a few analog
pins.  But you’re nearly at the limit.

1
If you wanted to expand to a 5x5x5 cube then you’re out of luck, you’ll need 125
LEDs for that and you can’t control them individually with one Arduino.
Even a 4x4x4 cube using standard (i.e. non-addressable) RGB LEDs would put you
past the limit.
There are many ways to solve these issues, including running the LEDs ina matrix or
using a shift register. The shift register will allow you to address a large number of
LEDs using only a few Arduino I/O pins.
There are other times when you have a lot of sensors, displays or other I/O devices
and can’t spare a lot of pins for LEDs or switches, but you need a multi-LED display
or a small keypad. Again shift registers can come to the rescue.
 Let’s examine these handy devices.
Shift Registers
Shift Registers are sequential logic circuits that are used for the conversion, storage or
transfer of binary data.

These devices are used to convert between serial and parallel data. They can be used
in data communications circuits as well as memory and buffer circuits.  Many
complex electronic circuits, such as microprocessors and microcontrollers, use shift
registers internally.
Types of Shift Registers
Shift registers deal with both serial and parallel data on both their inputs and outputs
and they can convert between these formats.
There are four basic types of shift registers:

2
Serial In – Parallel Out

The Serial In – Parallel


Out (SIPO) shift
register converts serial
data to parallel data. It
is used in
communications and to
drive multiple output
ports using serial data.

Parallel In – Serial Out

The Parallel In – Serial


Out (PISO) shift
register converts
parallel data to serial
data. It is used in
communications and to
convert multiple input
ports to serial data.

Parallel In – Parallel Out & Serial In – Serial Out


You might find these two strange. Why would you want a shift register that outputs
data in the same format that it was input?

The answer is that this can be used as a buffer, to hold data for a specific number of
clock cycles. The shift registers we are using today both employ similar buffers to
hold data on tehi=r inputs and outputs so it doesn’t change while the register is being
shifted through.

3
How Shift Registers work
Internally shift registers consist of a number of basic logic gates, many arranged as
“flip flops”.
If you aren’t familiar with a flip-flop it is a basic electronic circuit that can act to hold
the value of data from its input.  It is a fundamental building block and is used
everywhere, including in many forms of memory circuitry.

A Serial In – Parallel Out, or SIPO, register uses a series of flip-flops, one for each bit
on the parallel output. The illustrations here show a 4-bit device.

As the first bit of serial data is clocked in it is stored in the flip-flop and appears on its
output.

4
The next bit of data pushes the original bit over to the next flip-flop.

This process continues as the serial data is clocked in. Note that the flip-flop only
updates the input value when it is clocked.

5
Finally when all the data is clocked in the parallel output can be read. In most shift
registers an extra buffer holds the parallel data and doesn’t change it until all the dat
ais clocked in.
A PISO, or Parallel In – Serial Out shift register is constructed as follows

The “MUX” section of this diagram actually consists of a number of discrete logic
gates, and they serve to feed the data into their associated flip-flop at the correct time.
This is important as a PISO shift register needs to clock each bit of the parallel data
individually. This means that the data on the parallel input can’t change while it is
being read, again most practical designs employ a buffer to hold the parallel data.

6
Cascading Shift Registers
A shift register is cataloged by the number of bits it handles, the ones shown in the
previous illustrations were 4-bit registers and both of the shift registers that we will be
using today are 8-bit devices.
If you need to increase the amount of parallel data you can handle with a shift register
you can cascade it with another shift register.  So two 8-bit shift registers can support
16-bits, add another one for 24-bits, etc.
You don’t need additional connections to the microcontroller to cascade shift
registers, so it’s a great way to drive a lot of LEDs or read a lot of switches without
using up a lot of ports.
74HC575 & 74HC165 Shift Registers
We will be using two very common and easily obtained shift registers today, the
74HC595 SIPO and 74HC165 PISO. Let’s take a closer look at these chips.
74HC595 – 8-bit Serial In – Parallel Out
The 74HC575 is an 8-stage serial shift register that also has an internal storage
register. The storage register buffers the output data and can be clocked independently
of the shift register. This prevents the data from changing while it is being loaded.
The 74HC595 has a “3-state” output. This means that the pins on the parallel data
output can be at three different states.
 LOW
 HIGH
 OFF
The OFF state is a high-impedance state that effectively disconnects the output of the
chip. This technique allows several 3-state chips to drive the same bus, with only one
of them active at any given time.
The pinout of the 74HC575 in the DIP package is illustrated here:

7
The serial data is input on the DS pin (pin 14). You can use the Q7’ pin to cascade
these devices to increase the number of parallel outputs you can control.
The Output Enable (pin 13) controls the 3-state bus, if it is LOW then the output bus
is enabled.
74HC165 – 8-bit Parallel In – Serial Out
The 74HC165 is an 8-bit parallel-load shift register which has a serial output. It has
complementary outputs, one of which can be tied to another 74HC165 to cascade
them.
This device is used for parallel to serial data conversion and has the following pinout:

As with the 74HC595, this is a very common integrated circuit and you should have
no trouble obtaining it at almost any electronics supplier.

8
Extra Output Ports with the 74HC595
We will begin our experiments with the 74HC595 SIPO (Serial In – Parallel Out) shift
register.
The 74HC595 allows us to expand the number of digital I/O ports on our Arduino. In
these experiments, we will be using it to drive some LEDs, which we will control
using an Arduino.
Arduino & 74HC595 Hookup
Here is how we will be hooking up the 74HC595 to an Arduino and to eight LEDs.

Note the addition of a decoupling capacitor, across the power supply, this is a good
idea when working with TTL chips like the 74HC595. I used a 100uf capacitor but
any value from 10uf upwards will work just fine. Make sure that you observe the
polarity of the capacitor.
On my breadboard, I replaced the eight dropping resistors with an 8×2 220-ohm
resistor array. This is a convenient component to have when you need a lot of
identical resistors.  Of course, you may use discrete resistors if you don’t have an
array.
There are a lot of wires here so double-check your wiring. You may test the LED-
dropping resistor combos by wiring them first and then applying 5 volts to the
resistor, if it is wired correctly you’ll light the LED. Repeat the test for all eight
resistor-LED pairs. Do this before you wire up the 74HC595 and the Arduino.
Once it is all wired up you can move forward and write some code to make it all
work.

9
Arduino shiftOut() Function
There are a couple of ways to “talk” to a shift register with an Arduino. One way is to
use the SPI bus, which would allow you to make use of existing libraries to simplify
writing code.
Another way is to use any standard I/O pins on the Arduino to create a clock and to
exchange serial data. This is the method we will employ to work with the 74HC595
shift register.
Arduino provides a shiftOut() function to simplify moving data on a serial connection.
It can take a byte value and output it in a serial format in sync with a clock pulse on
another pin. You can choose to output the data in two directions.
 MSB First – The Most Significant Bit first. So the binary number 10110010
will output a bit at a time starting with “101”, or from left to right.
 LSB First  – The Least Significant Bit first.  In this case, the binary number
10110010 will output a bit at a time starting with “010”, or from right to left.
We will make use of this function in our sketch.
Arduino & 74HC595 Sketch
Our sketch is pretty simple. The shiftOut function takes care of sending our data to the
shift register and of creating a clock signal.
74HC595 Shift Register Demonstration
1 /*
2   74HC595 Shift Register Demonstration 1
3   [Link]
4   Count in Binary and display on 8 LEDs
5  
6   Modified from "Hello World" example by Carlyn Maw,Tom Igoe and David A. Mellis
7  
8   DroneBot Workshop 2020
9   [Link]
10 */
11  
12 // Define Connections to 74HC595
13  
14 // ST_CP pin 12
15 const int latchPin = 10;
16 // SH_CP pin 11
17 const int clockPin = 11;
18 // DS pin 14
19 const int dataPin = 12;
20  
21 void setup ()
22 {
23   // Setup pins as Outputs
24   pinMode(latchPin, OUTPUT);
25   pinMode(clockPin, OUTPUT);
26   pinMode(dataPin, OUTPUT);
27 }
28  
29 void loop() {
30   // Count from 0 to 255 and display in binary
31  
32   for (int numberToDisplay = 0; numberToDisplay < 256; numberToDisplay++) {
33  
34     // ST_CP LOW to keep LEDs from changing while reading serial data
35     digitalWrite(latchPin, LOW);

10
36  
37     // Shift out the bits
38     shiftOut(dataPin, clockPin, MSBFIRST, numberToDisplay);
39  
40     // ST_CP HIGH change LEDs
41     digitalWrite(latchPin, HIGH);
42  
43     delay(500);
44   }
45 }

This sketch is just an adaptation of one that Arduino provides in their excellent lesson
on using the 74HC595 with the Arduino. It uses the eight LEDs as the display for a
binary counter.
We begin by assigning variable names to the pins connected to the 74HC595. All of
these pins are then set up as outputs.  We then move on to the Loop.
We use a for-next loop to count from 0 to 255, incrementing by one. On each
increment, we write the counter value out to the shift register. The latch pin is used to
hold the data until we are ready so that the display doesn’t flicker as the shift register
is being loaded.
After a half-second delay, the next number is loaded.

The result is that the LEDs display a binary count from 0 to 255. 
You can experiment with the code and manipulate some values and observe the effect
on the LEDs. Try changing the MSBFIRST parameter in the shiftOut statement
to LSBFIRST and see what happens.
It’s a simple way to understand basic shift register operation.
Driving 7-Segment Displays
Another use for the 74HC575 is to drive a 7-segment LED display. You can use it to
red=uce the number of connections to one display, or you can cascade multiple
74HC595s to drive several displays.

11
7-Segment LED Displays
A typical 7-segment LED display layout is shown here:

Note that there are actually eight LED elements in a “7-Segment” display, the eighth
LED is used as a decimal point. In some displays, this may be substituted with a
colon.
LED displays are available in two configurations:
 Common Anode – All the LEDs are connected with a common Anode
(positive) connection.
 Common Cathode – All the LEDs are connected with a common Cathode
(negative) connection.
Both display types use the same pinout, so it is very important to know what type you
have. A good way to tell (other than referencing the display part number) is to use a
multimeter on the “diode test” function. When connected with the proper polarity it
can be used to light the LED elements.
The Common Cathode display is more common and is the type we will be using for
our experiment.
74HC595 7-Segment Display Hookup
As the Common Cathode 7-segment LED display is really just eight LEDs connected
to a common cathode( (negative) terminal it is no different than the eight LEDs we
used in our first experiment.  So we can use the exact same circuit to hook it up.

12
Use the chart in the hookup diagram to connect the display pins to the dropping
resistors. The COM pin (the Common Cathode) is connected to the Arduino’s
Ground. Note that the display will have two COM pins, you only need to connect one.
Once you have that all hooked up you can test it by running the previous sketch,
which should test all the LED segments including the decimal point.
But to actually display something coherent we will need a different sketch.
74HC595 7-Segment Display Sketch
Here is the sketch we will use to test out our 7-segment display.
74HC595 Shift Register with 7-segment LED display

1 /*
2   74HC595 Shift Register with 7-segment LED display
3   [Link]
4   Count in hex from 0-F and display on 7-segment Common Cathode LED display
5  
6   DroneBot Workshop 2020
7   [Link]
8 */
9  
10 // Define Connections to 74HC595
11  
12 // ST_CP pin 12
13 const int latchPin = 10;
14 // SH_CP pin 11
15 const int clockPin = 11;
16 // DS pin 14
17 const int dataPin = 12;
18  
19 // Patterns for characters 0,1,2,3,4,5,6,7,8,9,A,b,C,d,E,F
20 int datArray[16] = {B11111100, B01100000, B11011010, B11110010, B01100110, B10110110, B10111110,
21 B11100000, B11111110, B11110110, B11101110, B00111110, B10011100, B01111010, B10011110,
22 B10001110};
23  
24 void setup ()
25 {
26   // Setup pins as Outputs

13
  pinMode(latchPin, OUTPUT);
27   pinMode(clockPin, OUTPUT);
28   pinMode(dataPin, OUTPUT);
29 }
30 void loop()
31 {
32   // Count from 0 to 15
33   for (int num = 0; num < 16; num++)
34   {
35     // ST_CP LOW to keep LEDs from changing while reading serial data
36     digitalWrite(latchPin, LOW);
37  
38     // Shift out the bits
39     shiftOut(dataPin, clockPin, MSBFIRST, datArray[num]);
40  
41     // ST_CP HIGH change LEDs
42     digitalWrite(latchPin, HIGH);
43  
44     delay(1000);
45   }
}

This sketch has many similarities to the previous one, which isn’t surprising when you
consider that it does pretty well the same thing.
We start again by defining our connections to the 74HC595. 
Then we create an array with 16 elements, each one representing the pattern for a
character to display on the 7-segment LED. 
The elements are written in binary and it makes it simple to understand how they
work. Within the binary byte, each bit represents one of the LED segments. From
MSB to LSB (left to right) they represent the following segments in the display:
a – b – c – d – e – f – g – DP 
When the bit is set to “1” the LED segne=nt is on, a “0” means it is off.
The array is ordered so element 0 is the character for “0”. Element 1 is the character
for “1” etc. It is in hexadecimal so element 15 is “F”.
Look at the array elements and you’ll see the pattern.
Once again in Setup, we set our connections as outputs and then move onto the Loop.
Again we use a counter, only this time ist is between 0 and 15. We will display these
values as they are counted on the LED display in Hexadecimal format.
We step through the array one element at a time, using shiftOut to send the element
data to the shift register.

14
Load up the code and observe the display. If everything is connected correctly you’ll
see it count from 0 to F and then repeat.
Extra Input Ports with the 74HC165
Now that we have seen how to add output ports with a shift register it’s time to do the
opposite and add some inputs. For that job, we will use the 74HC165.
We will use the 74HC165 shift register along with eight momentary-contact
pushbutton switches. The shift register will take the 8 inputs from the switch and send
them to the Arduino as serial data.
Arduino shiftIn() Function
Once again Arduino has a dedicated function for receiving serial data. 
The shiftIn() function shifts serial data in one byte at a time. It can be set to take the
MSB or LSB first. It is often used with a shift register like the 74HC165 or
the CD4021BE.
As with its cousin the shiftOut function the shiftIn function also supplies a clock
signal to synchronize the data transmission.
Arduino & 74HC165 Hookup
The inputs of the 74HC165 need to be pulled down LOW to prevent false readings, so
in addition to our eight pushbutton switches we will also need eight pulldown
resistors. I used 10k resistors, but any value from 4.7k to 27k will work fine.

15
Once again I used a 100uf decoupling capacitor, make sure you observe the polarity
when connecting this.
Once you have it all hooked up we can focus on the sketch we will be using to make
this work.
Arduino & 74HC165 Sketch
Our sketch is very simple, as all it does is read the status of the pushbuttons and
display the results on the serial monitor.  But that’s really all you need to do to
understand how to get data from your pushbuttons and the 74HC165.
74HC165 Shift Register Demonstration

1 /*
2   74HC165 Shift Register Demonstration 1
3   [Link]
4   Read from 8 switches and display values on serial monitor
5  
6   DroneBot Workshop 2020
7   [Link]
8 */
9  
10 // Define Connections to 74HC165
11  
12 // PL pin 1
13 int load = 7;
14 // CE pin 15
15 int clockEnablePin = 4;
16 // Q7 pin 7
17 int dataIn = 5;
18 // CP pin 2
19 int clockIn = 6;
20  
21 void setup()
22 {
23  
24   // Setup Serial Monitor
25   [Link](9600);
26  

16
27   // Setup 74HC165 connections
28   pinMode(load, OUTPUT);
29   pinMode(clockEnablePin, OUTPUT);
30   pinMode(clockIn, OUTPUT);
31   pinMode(dataIn, INPUT);
32 }
33  
34 void loop()
35 {
36  
37   // Write pulse to load pin
38   digitalWrite(load, LOW);
39   delayMicroseconds(5);
40   digitalWrite(load, HIGH);
41   delayMicroseconds(5);
42  
43   // Get data from 74HC165
44   digitalWrite(clockIn, HIGH);
45   digitalWrite(clockEnablePin, LOW);
46   byte incoming = shiftIn(dataIn, clockIn, LSBFIRST);
47   digitalWrite(clockEnablePin, HIGH);
48  
49   // Print to serial monitor
50   [Link]("Pin States:\r\n");
51   [Link](incoming, BIN);
52   delay(200);
53 }

The sketch starts out like all of our previous sketches, defining the four connections to
the IC. 
In the Setup, we initialize the serial monitor and then set the connections up as
required.
In the Loop, we first write a pulse to the load pin, which will have it load the data
from its parallel input into a buffer to be worked on.
Next, we set up the 74HC165 to prepare to send data and then use the shiftIn function
to get that data, LSB (Least Significant Bit) first.  We finish by taking the clock pin
HIGH, signifying we are done.
Finally, we print the result to the serial monitor.
Load the sketch, open your serial monitor and observe the output. Right away you’ll
notice something.

17
The data is all held HIGH on the output, the opposite of what is wired on the board.
Pressing a pushbutton will cause it to read LOW, even though that is the opposite of
what is really happening.
This is because we are using the complementary output from the 74HC165. Our data
is inverted.
I’ll show you in a later sketch how to turn it back the right way around.  Keep on
reading!
The example we just used has many practical applications, one of the obvious ones is
as a keypad (although there are better ways to make a large keypad).  For a project
that requires a lot of switches, it is a useful design technique.
One great application of this circuit is to use it with DIP switches or jumpers, ones
that are only occasionally set. You can use the 74NC165 to reduce the number of
connections required to read an 8-position DIP switch, and just read it in the Setup
routine so it is only read when the device is powered on or reset.
Using the 74HC595 and 74HC165 Together
Of course, it would be a shame to have wired up all of those LEDs and switches
without going the extra step to connect them together! So let’s do exactly that.
74HC595 and 74HC165 Hookup
If you built each of the demonstrations on its own solderless breadboard as I did then
hooking both of them together is very simple.

18
Disconnect the Arduino from its breadboard on one of the demonstrations, it doesn’t
really matter which one. Leave the connections on the breadboard so that you can
reconnect them to the other Arduino. You can connect the 5-volt and Ground
connections to the other breadboards power rails.
When you are done try running the previous sketches on the Arduino, everything
should still work. If something doesn’t work then check your wiring, something might
have become disconnected when you joined the projects – there are a lot of wires
here!
Once you have everything tested it’s time to look at a sketch to use both the 74HC165
and 74HC595 together.
74HC595 and 74HC165 Sketch 1 – Boring!
As our demo is essentially two demos fused together our sketch is pretty well the
same thing. You’ll see a lot of similarities between this sketch and the previous ones,
and it’s no accident – some of it is literally cut and paste!
The purpose of the sketch is to simply use the LEDs to display the status of the
pushbuttons. Really boring, and a complete waste of a microcontroller and some shift
registers, but as a demonstration, it works well. I promise we’ll move on to something
more exciting after this!
74HC595 & 74HC165 Shift Register Demonstration
1 /*
2   74HC595 & 74HC165 Shift Register Demonstration
3   [Link]
4   Input for 8 pushbuttons using 74HC165
5   Output to 0 LEDs using 74HC595
6  
7   DroneBot Workshop 2020
8   [Link]
9 */
10  

19
11 // Define Connections to 74HC165
12  
13 // PL pin 1
14 int load = 7;
15 // CE pin 15
16 int clockEnablePin = 4;
17 // Q7 pin 7
18 int dataIn = 5;
19 // CP pin 2
20 int clockIn = 6;
21  
22 // Define Connections to 74HC595
23  
24 // ST_CP pin 12
25 const int latchPin = 10;
26 // SH_CP pin 11
27 const int clockPin = 11;
28 // DS pin 14
29 const int dataPin = 12;
30  
31 void setup () {
32  
33   // Setup Serial Monitor
34   [Link](9600);
35  
36   // 74HC165 pins
37   pinMode(load, OUTPUT);
38   pinMode(clockEnablePin, OUTPUT);
39   pinMode(clockIn, OUTPUT);
40   pinMode(dataIn, INPUT);
41  
42   // 74HC595 pins
43   pinMode(latchPin, OUTPUT);
44   pinMode(clockPin, OUTPUT);
45   pinMode(dataPin, OUTPUT);
46  
47 }
48  
49  
50 void loop() {
51  
52   // Read Switches
53  
54   // Write pulse to load pin
55   digitalWrite(load, LOW);
56   delayMicroseconds(5);
57   digitalWrite(load, HIGH);
58   delayMicroseconds(5);
59  
60   // Get data from 74HC165
61   digitalWrite(clockIn, HIGH);
62   digitalWrite(clockEnablePin, LOW);
63   byte incoming = shiftIn(dataIn, clockIn, LSBFIRST);
64   digitalWrite(clockEnablePin, HIGH);
65  
66   // Print to serial monitor
67   [Link]("Pin States:\r\n");
68   [Link](incoming, BIN);
69  
70  
71   // Write to LEDs
72  
73   // ST_CP LOW to keep LEDs from changing while reading serial data
74   digitalWrite(latchPin, LOW);
75  
76   // Shift out the bits
77   shiftOut(dataPin, clockPin, LSBFIRST, ~incoming);

20
78  
79   // ST_CP HIGH change LEDs
80   digitalWrite(latchPin, HIGH);
81  
82   delay(500);
83  
84 }

We stare by once again defining pin connections to both integrated circuits.  And in
the Setup, we initialize the serial monitor and set the connections up as required.
The Loop starts with the same routine we used earlier to read the pushbutton values
from the 74HC165.  Again we insert the data into an 8-bit byte called “incoming” and
display its value on the serial monitor.
Next, we use the same code we used earlier to write the data to the 74HC595. But we
make one change to the date we send to the shift register.
Remember, our data from the switch is inverted. If we send it to the 74HC595 it will
work, but the LEDs will all be on, except where we have pressed a pushbutton.
To invert the date we use the “~” symbol in front of the “incoming” variable when we
use it in the shiftOut  function. The tilde (squiggly) symbol inverts the binary data,
turning every zero into a one and vice versa.  Exactly what we need to do.
You’ll also notice that one thing we do differently from the earlier 74HC595 sketch is
we send the data LSB first. This matches how we receive it from the pushbuttons.
Sending it MSB first would work, but the LED display would be reversed.
Load it up and try it out. 

Thrilling, isn’t it? 


OK, it really isn’t, but it does show how you can take parallel data (the switch inputs),
convert it to serial with a shift register, send it to an Arduino, send it back out to a
second shift register and convert it back into parallel again (the LED outputs). And
that’s sort of thrilling.

21
If you aren’t completely thrilled then don’t worry, we can do other things now that we
have eight switches and eight LEDs.
74HC595 and 74HC165 Sketch 2 – Exciting!
To add some excitement to our demo let’s use the eight switches to select LED light
flashing patterns. As we have eight switches we can select eight patterns.
Here is how we will do it:
74HC595 & 74HC165 Shift Register Demonstration 2
1 /*
2   74HC595 & 74HC165 Shift Register Demonstration 2
3   [Link]
4   Input from 8 pushbuttons using 74HC165
5   Output to 8 LEDs using 74HC595
6   
7   Select LED pattern using pushbuttons
8   
9   DroneBot Workshop 2020
10   [Link]
11 */
12 // Define Connections to 74HC165
13  
14 // PL pin 1
15 int load = 7;  
16 // CE pin 15      
17 int clockEnablePin = 4;  
18 // Q7 pin 7  
19 int dataIn = 5;  
20 // CP pin 2  
21 int clockIn = 6;    
22  
23 // Define Connections to 74HC595
24  
25 // ST_CP pin 12
26 const int latchPin = 10;
27 // SH_CP pin 11
28 const int clockPin = 11;
29 // DS pin 14
30 const int dataPin = 12;
31  
32 // Define data array
33 int datArray[8];
34  
35 void setup () {
36   
37 // Setup Serial Monitor
38 [Link](9600);
39   
40 // 74HC165 pins
41 pinMode(load, OUTPUT);
42 pinMode(clockEnablePin, OUTPUT);
43 pinMode(clockIn, OUTPUT);
44 pinMode(dataIn, INPUT);
45  
46 // 74HC595 pins
47 pinMode(latchPin,OUTPUT);
48 pinMode(clockPin,OUTPUT);
49 pinMode(dataPin,OUTPUT);
50  
51 }
52  
53  
54 void loop() {

22
55  
56 // Read Switches      
57  
58 // Write pulse to load pin
59 digitalWrite(load,LOW);
60 delayMicroseconds(5);
61 digitalWrite(load,HIGH);
62 delayMicroseconds(5);
63  
64 // Get data from 74HC165
65 digitalWrite(clockIn,HIGH);
66 digitalWrite(clockEnablePin,LOW);
67 byte incoming = shiftIn(dataIn, clockIn, LSBFIRST);
68 digitalWrite(clockEnablePin,HIGH);
69  
70 // Print to serial monitor
71 [Link]("Pin States:\r\n");
72 [Link](incoming, BIN);
73  
74 // Setup array for LED pattern
75  
76 switch (incoming) {
77  
78   case B11111110:
79   
80     datArray[0] = B11111111;
81     datArray[1] = B01111110;
82     datArray[2] = B10111101;
83     datArray[3] = B11011011;
84     datArray[4] = B11100111;
85     datArray[5] = B11011011;
86     datArray[6] = B10111101;
87     datArray[7] = B01111110;
88   
89     break;
90   
91   case B11111101:
92   
93     datArray[0] = B00000001;
94     datArray[1] = B00000010;
95     datArray[2] = B00000100;
96     datArray[3] = B00001000;
97     datArray[4] = B00010000;
98     datArray[5] = B00100000;
99     datArray[6] = B01000000;
100     datArray[7] = B10000000;
101   
102     break;
103   
104   case B11111011:
105   
106     datArray[0] = B10000001;
107     datArray[1] = B01000010;
108     datArray[2] = B00100100;
109     datArray[3] = B00011000;
110     datArray[4] = B00000000;
111     datArray[5] = B00100100;
112     datArray[6] = B01000010;
113     datArray[7] = B10000001;
114   
115     break;
116  
117
118   case B11110111:
119   
120     datArray[0] = B10101010;
121

23
122     datArray[1] = B01010101;
123     datArray[2] = B10101010;
124     datArray[3] = B01010101;
125     datArray[4] = B10101010;
126     datArray[5] = B01010101;
127     datArray[6] = B10101010;
128     datArray[7] = B01010101;
129   
130     break;
131  
132
133   case B11101111:
134   
135     datArray[0] = B10000000;
136     datArray[1] = B00000001;
137     datArray[2] = B01000000;
138     datArray[3] = B00000010;
139     datArray[4] = B00100000;
140     datArray[5] = B00000100;
141     datArray[6] = B00010000;
142     datArray[7] = B00001000;
143   
144     break;
145  
146   case B11011111:
147   
148     datArray[0] = B11000000;
149     datArray[1] = B01100000;
150     datArray[2] = B00110000;
151     datArray[3] = B00011000;
152     datArray[4] = B00001100;
153     datArray[5] = B00000110;
154     datArray[6] = B00000011;
155     datArray[7] = B10000001;
156   
157     break;
158  
159 case B10111111:
160   
161     datArray[0] = B11100000;
162     datArray[1] = B01110000;
163     datArray[2] = B00111000;
164     datArray[3] = B00011100;
165     datArray[4] = B00001110;
166     datArray[5] = B00000111;
167     datArray[6] = B10000011;
168     datArray[7] = B11000001;
169   
170     break;
171  
172 case B01111111:
173   
174     datArray[0] = B10001000;
175     datArray[1] = B01000100;
176     datArray[2] = B00100010;
177     datArray[3] = B00010001;
178     datArray[4] = B10001000;
179     datArray[5] = B01000100;
180     datArray[6] = B00100010;
181     datArray[7] = B00010001;
182   
183     break;
184     
185   default:
186  
187     break;
188

24
 
189   }
190  
191 // Write to LEDs
192  
193 // Count from 0 to 7
194   for(int num = 0; num < 8; num++)
195   {
196     // ST_CP LOW to keep LEDs from changing while reading serial data
197     digitalWrite(latchPin, LOW);
198     
199     // Shift out the bits
200     shiftOut(dataPin,clockPin,MSBFIRST,datArray[num]);
201  
202     // ST_CP HIGH change LEDs
203     digitalWrite(latchPin, HIGH);
204     
205     delay(200);
206   }
207  
}

As you can see I’ve once again borrowed coded from all of the previous demos. In
fact, there is really only one thing different about this sketch, and that’s the switch-
case statement that allows you to select the LED patterns.
We use the ”incoming” byte, which holds the switch values, as the switch for the
statement. Then we have eight cases, one for each switch press. You could probably
add more if you wanted to allow for pressing two buttons simultaneously, but eight
was enough for me!
In each case section, we populate the datArray array with LED patterns, written in
binary so they are easy to see. In each byte, a “1” represents an LED that is
illuminated, whereas “0” indicates the LED is off. 
I used eight elements in the array to make it easier, but you can increase this to any
number you like. Just change the number in the array definition and in the for-next
loop that cycles through the array elements.
I set the delay between pattern changes to 200ms, but you can change that. Even
better, try putting the delay as a variable in each case evaluation, so you can make the
patterns run at different speeds.
 

25
The sketch runs as advertised, and it’s actually a lot of fun to watch. 
You could improve on the sketch by cascading the 74HC595 to add more LEDs. You
could also make the speed variable by adding a potentiometer to one of the analog
inputs and using it to set the delay time.  And the enable input on the 74HC595 can be
driven with PWM to change LED intensity, which you could control with a second
potentiometer.
You could even add some MOSFETs to drive larger LEDs and make your own
marquis!
A simple demo with lots of potential.
Conclusion
Shift registers may be elementary building blocks that might seem out of place aside
microcontrollers and other more capable chips, but they still can perform important
functions in a modern design. They can be very useful if you need to add extra inputs
or outputs to your project, they are inexpensive and easy to use.
Nothing shifty about that!
 

26

You might also like