© Warren Gay 2017

Warren Gay, Custom Raspberry Pi Interfaces, 10.1007/978-1-4842-2406-9_10

10. More Pi Outputs with 74HC595

Warren Gay

(1)St Catharines, Ontario, Canada

Like input GPIOs in Chapter 9, the application designer may require more GPIO outputs. Because this 74HC595 part is a member of the “HC” logic family, it is able to operate with a VCC ranging from 2.0 to 6.0 volts. This is perfect for operating under the 3.3V Raspberry Pi and costs less than a dollar at digikey.com. Figure 10-1 illustrates a chip that I’ve used.

A432417_1_En_10_Fig1_HTML.jpg
Figure 10-1. 74HC595 serial in, parallel out shift register

Note that the HCT family is designed for TTL input levels. I focus on the HC devices in this chapter because the device must interface to the CMOS-based Raspberry Pi.

74HC165 Pinout

Figure 10-2 provides a schematic pinout for the 74HC595 chip. Once again, different manufacturers use different labels for the various pins.

A432417_1_En_10_Fig2_HTML.gif
Figure 10-2. 74HC595 pinout

Table 10-1 documents the pins, the schematic labels, the NXP labels (not shown in Figure 10-2), and the pin functions for this chip.

Table 10-1. 74HC595 Pins and Functions

Pin

Schematic Label

NXP Label

Function

11

SCLK

SHCP

Shift clock

14

SDA

DS

Shift (in) data

12

LATCH

STCP

Latch (clock pulse)

10

RST

MR

(Master) reset

13

OE

OE

Output enable

15

Q0

Q0

Output Q0 (least significant bit)

7

Q7

Q7

Output Q7 (most significant bit)

9

Q7S

Q7S

Serial data output (for chaining)

Function Table

Table 10-2 is an adaptation of the NXP-provided table, except that it uses the labels provided by the EAGLE software in Figure 10-2. In addition to the legend provided in Chapter 9’s Figure 9-3, there are two new symbols: NC, which means “No Change,” and Z, which means “high impedance” (essentially disconnected from the circuit).

Table 10-2. Function Table for 74HC595

Controls

Input

Output

SCLK

STCP

OE

MR

DS

Q7S

Qn

X

X

L

L

L

L

NC

X

ʿ

L

L

L

L

L

X

X

H

L

L

L

Z

ʿ

X

L

H

D

Q6S

NC

X

ʿ

L

X

X

NC

QnS

ʿ

ʿ

L

X

X

Q6S

Qns

When the MR (reset) signal goes low (in the first line of the table), you can see that there are no changes on the outputs (Qn = NC), but it does clear the internal shift register. This is true whether the OE (output enable) signal is active or not (lines 2 and 3).

Line 3 shows you, however, that when the OE signal is inactive (high), the shift register outputs Q0 through Q7 (Qn) go into a high impedance (Z) state. In other words, these outputs become disconnected from the circuit that they are wired to.

Line 4 applies when MR is inactive (H), OE is active (L), and the signal SCLK (ʿ) goes from low to high. Here I used “D” to indicate a data bit is copied into the shift register bit Q0 (as ON Semiconductor does). The remaining shift registers’ cells are shifted to the next position. This results in the Q7 bit being replaced with the prior state of Q6. Note that the parallel latched outputs Q0 through Q7 remain unchanged (NC).

While OE remains active (L) in line 5, the rising signal STCP (ʿ) causes the shift register bits to appear externally at Q0 through Q7. This latching operation has no effect on the internal shift register contents, which is why output Q7S shows no change (NC).

The last line of the function table indicates that you can shift a data bit into the internal shift register and simultaneously latch that result so that it is externally visible. This can save a little bit of time in the output cycle.

Breadboard Experiment

Figure 10-3 illustrates the breadboard circuit for the 74HC595 chip. In this arrangement, you hardwire the OE pin to ground. This means that the outputs Q0 through Q7 will always be enabled. The clock pulses are wired to GPIO#5 as in the previous chapter. The LATCH signal is active when there is a low to high transition.

A432417_1_En_10_Fig3_HTML.gif
Figure 10-3. Breadboard circuit for 74HC595 output

You can take advantage of the /PL line as used in Chapter 9. Sharing that GPIO is possible because the input 74HC165 loads data while this line is low. The output 74HC595 will latch its outputs when the signal goes from low to high. You can, of course, use a different GPIO for this purpose if your application demands it. I’ll discuss GPIO sharing in more detail later.

Finally, you need GPIO #24 for passing data into the 74HC595 shift register from the Pi. You can use different GPIO assignments, but this is what the supplied source code will use for this experiment.

Lastly, this experiment ties the RST input to the +3.3V supply. This reset input is active low, so you tie it high so that it doesn’t become active for this experiment.

Unlike the 74HC165 input chip, you have no remaining inputs to wire to ground or the supply. CMOS outputs can be left without connections.

In the subdirectory hc595, you will find the Makefile and program hc595.cpp. Change to that directory and type make.

$ cd ./hc595
$ make
g++ -c -std=c++11 -Wall -Wno-deprecated -Wno-narrowing -I. -I/usr/local/include/librpi2 -g -O0 hc595.cpp -o hc595.o
g++ hc595.o -o ./hc595 -L/home/pi/rpi2016/hc595/..//lib -lrpi2 -lrt -lm
sudo chown root ./hc595
sudo chmod u+s ./hc595

Once again, note that the program hc595 has been given setuid permission so that you won’t need to run it with sudo. Root permission is required to access the GPIO registers directly. Listing 10-1 shows the program area of interest.

Listing 10-1. Program hc595.cpp
008 #include "gpio.hpp"
009
010 static int hc595_latch      = 16;  // Outputs
011 static int hc595_sclk = 5;
012 static int hc595_sda = 24;
013
014 static unsigned usecs = 1;
015 static GPIO gpio;
016
017 static void
018 nap() {
019   usleep(usecs);
020 }
021
022 static void
023 hc595_write(unsigned data) {
024   unsigned b, temp = data;
025
026   gpio.write(hc595_sclk,0);             // SCLK = low
027   gpio.write(hc595_latch,0);            // LATCH = low
028   nap();
029
030   for ( int x=0; x<8; ++x ) {
031         b = !!(temp & 0x80);            // b = d7 (msb first)
032          temp <<= 1;
033          gpio.write(hc595_sda,b);       // SDA = data bit
034          nap();                         // Wait
035          gpio.write(hc595_sclk,1);      // SCLK low -> high
036          nap();
037          gpio.write(hc595_sclk,0);      // Complete clock pulse
038          nap();
039    }
040    gpio.write(hc595_latch,1);           // Latch data to outputs
041    nap();
042    printf("Wrote %02X to 74HC595\n",data);
043 }

The main program (not shown) configures the GPIOs as outputs. If no command-line arguments are given, a call is made to hc595_write(0xD5) to transmit that bit pattern to the output chip. If other command-line parameters are provided, those values are written instead.

The hc595_write() routine starts by making sure that the SCK and LATCH signals are set to the low level (lines 026 and 027), followed by a delay. Line 024 has copied the data value into variable temp for use in the loop.

In the for loop of lines 030 to 039, this temp value is sampled at bit 7 and stored in variable b. The double !! operator just converts a nonzero result (in b) into the value 1 and otherwise to the value 0. Then line 032 shifts the variable temp one position to the left for the next loop iteration.

Line 033 writes the data bit value in b out to GPIO hc595_sda (GPIO #24). This establishes the high or low value to be shifted into the output register. Line 034 delays so that the signal transitions don’t happen too fast for the chip. Line 035 raises the clock signal (SCLK) from low to high. This will clock the data bit into the output chip. Line 037 returns the clock signal low again after a delay.

After all eight bits of data are shifted into the output chip, the LATCH signal is activated in line 040. Recall that it is the transition from low to high that makes the shift register chip’s output available on the chip output pins (Q0 through Q7). There is one more delay following this operation so that if the output routine gets called back to back, sufficient time will exist between signal changes.

Experiment Run

The schematic in Figure 10-3 did not have anything shown connected to the outputs Q0 through Q7. The experiment can be run without any connections if you have a DMM to measure the output levels with. Simply take a meter reading, and if the value is a high level, note a 1 bit.

If you want a visual indication, you can attach LEDs with a dropping resistor in series. Depending upon the manufacturer, the absolute maximum output of each pin is 25mA (Fairchild). The chip is further limited by its maximum power dissipation, when every output is driving full current. The Fairchild datasheet indicates 600mW as the absolute maximum power dissipation. If you limit each output to a maximum of 22mA, you just fit within that parameter. $$ 22\; m A\; x\;8\; pins\; x\;3.3\; volts=580\; m W $$

Most LEDs will light with considerably less than this. Google LED voltage drop and you will find that many red LEDs will require about 1.8 volts. Taking this into account, you can compute the dropping resistor required.
$$ {R}_{LED}=\frac{V_{CC}-{V}_{LED}}{I_{LED}} $$

Assuming a modest current of 10mA for the LED and substituting allows you to compute the series dropping resistor. $$ {R}_{LED}=\frac{3.3\; V-1.8\; V}{10\; mA}=150\;\varOmega $$

Figure 10-4 illustrates, in schematic form, the circuit necessary to attach to the output pins for Q0 through Q7. If you don’t mind moving the Dupont wires around, you can get by with just one LED.

A432417_1_En_10_Fig4_HTML.gif
Figure 10-4. LED hookup with series dropping resistor

Running the program with no command-line arguments will output the hexadecimal value of D5.

$ ./hc595
Wrote D5 to 74HC595

The hc595 program reports the value written to the 74HC595 chip. With this hex value (11010101 in binary), you should observe the following parallel data output:

  • Q7 is high.

  • Q6 is high.

  • Q5 is low.

  • Q4 is high.

  • Q3 is low.

  • Q2 is high.

  • Q1 is low.

  • Q0 is high.

Obviously, if you measure something else, then something is incorrect.

Input and Output

Let’s now look at combining the output 74HC595 with the input 74HC165 chips, using shared GPIO lines. Figure 10-5 illustrates the schematic circuit. IC1 is the 74HC595 that I’ve been discussing in this chapter, while IC2 is the added 74HC165 chip that was examined in Chapter 9.

A432417_1_En_10_Fig5_HTML.gif
Figure 10-5. Combined output with input breadboard circuit

In this experiment, you’ve connected the outputs Q0 through Q7 to the inputs A through H of the 74HC165 chip. By doing this, your software should be able to output a value and then read it back as verification. The chip enable (INH) of IC2 has been wired to ground, since there is no need to select a chip. As before, the unused input SER of IC2 has also been tied to ground to eliminate any floating inputs.

The circuit shares GPIO #5 and GPIO #16 with both chips. GPIO #5 supplies the clock pulse, while GPIO #16 supplies the LD signal for IC2 and the LATCH symbol for IC1. The unshared GPIOs include #23 used for reading data, while GPIO #24 is used to supply data to IC1.

Listing 10-2 shows the interesting aspects of the code. Lines 010 to 013 allocate the GPIOs being used. Pin gpio_qh is the serial data in from the 74HC165, while gpio_sda is the serial data going out to the 74HC595. The gpio_latch and gpio_sclk lines are shared between the two chips.

Listing 10-2. Program hc165_595.cpp
010 static int gpio_qh          = 23;  // Input
011 static int gpio_latch       = 16;  // Outputs
012 static int gpio_sclk        = 5;
013 static int gpio_sda         = 24;
014
015 static unsigned usecs = 1;
016 static GPIO gpio;
017
018 static void
019 nap() {
020   usleep(usecs);
021 }
022
023 static unsigned
024 io(unsigned data) {
025   unsigned b, ib, temp = data;
026   unsigned idata = 0u;
027
028   gpio.write(gpio_sclk,0);             // SCLK = low
029   nap();
030
031   for ( int x=0; x<8; ++x ) {
032         ib = gpio.read(gpio_qh);       // Read 74HC165 QH output
033         idata = (idata << 1) | ib;     // Collect input bits
034
035         b = !!(temp & 0x80);           // Set b to output data bit
036         temp <<= 1;
037
038         gpio.write(gpio_sda,b);        // write data bit
039         nap();                         // Wait
040          gpio.write(gpio_sclk,1);      // SCLK low -> high (shift data)
041         nap();
042         gpio.write(gpio_sclk,0);       // Complete clock pulse
043         nap();
044   }
045   gpio.write(gpio_latch,0);            // Set new inputs
046   nap();
047   gpio.write(gpio_latch,1);            // Latch data to outputs
048   nap();
049   printf("Read %02X, Wrote %02X\n",idata,data);
050
051   return idata;
052 }

The function io() has been written to send and receive data. The data sent out is manipulated in temporary variable temp in lines 035 and 036. The data being read is accumulated in temporary variable idata in lines 032 and 033. At the conclusion, the values read and written are reported in line 049.

The main program invokes io() with values ranging from 0x00 through 0xFF and then the two additional values 0x00 and 0x01.

$ ./hc165_595
Read 01, Wrote 00
Read 02, Wrote 01
Read 00, Wrote 02
Read 01, Wrote 03
Read 02, Wrote 04
Read 03, Wrote 05
Read 04, Wrote 06
...snip...
Read FB, Wrote FD
Read FC, Wrote FE
Read FD, Wrote FF
Read FE, Wrote 00
Read FF, Wrote 01

The first value read (and reported) should be disregarded. It is reporting the current value in the shift register, which may be garbage the first time around. The second value also should be disregarded since this will represent the uninitialized value of the output register, as you will see.

Looking at the general pattern, you can see that the input values are two cycles behind what was last written. Here’s an example:

Read FC, Wrote FE

Here you can observe that the read value was hexadecimal FC, while the currently written value is FE. The reason for this is subtle. Let’s break down the operations involved.

  1. The LD signal of the 74HC165 goes low to capture its inputs, which is wired to the 74HC595 outputs Q0 through Q7.

  2. When the LD signal returns high, the 74HC165 shift register holds 0xFC to send back to the Pi (this was the current 74HC595 output value).

  3. However, in step 2, a low to high transition clocks in the new outputs for the 74HC595 outputs (which the 74HC165 chip has not yet seen).

  4. The clock line shifts in eight more bits to the output IC1 chip, while the Pi reads the captured data in IC2.

Consequently, the Pi will read 0xFC, while just having written out 0xFE. The output value 0xFE will not be seen on the IC1 outputs until the next cycle’s step 2. These details can get confusing. Figure 10-6 illustrates my own breadboard experiment.

A432417_1_En_10_Fig6_HTML.gif
Figure 10-6. 74HC595 and 74HC165 breadboard experiment

Additional Outputs

Additional outputs can be had by adding another 74HC595 chip. Figure 10-7 shows the schematic for doing so. The SDA and LATCH signals are attached in parallel, and IC2’s data input comes from IC1’s output Q7S (pin 9).

A432417_1_En_10_Fig7_HTML.jpg
Figure 10-7. Two 74HC595 chips used for 16-bit output

Profit and Loss

The breadboard experiment in Figure 10-5 was a demonstration of eight outputs and eight inputs. These required four GPIO pins to manage it. This is a 400 percent improvement in GPIO ports. The cost, however, is the extra time required to shift in/out the data. The Figure 10-5 experiment illustrated that the total time was reduced by performing input and output simultaneously.

Summary

This chapter demonstrated how you can easily add GPIO outputs to your Pi for the cost of about $1. Even more outputs can be had with additional chips. Finally, you exercised both input and output chips simultaneously to gain 16 I/O pins using only four allocated GPIO ports.

Beyond the Pi’s GPIO ports used, the 74HC165 and 74HC595 chips required no software configuration, making them simple to use. The next chapter will introduce another way to add I/O pins to your Pi. But this will require software configuration.