Control LEDs with Explorer HAT Pro and an 8-bit shift register

This intermediate tutorial will show you how to use Explorer HAT Pro to control 8 LEDs (or even more...) from just 3 output pins. Because Explorer HAT Pro has just 4 output pins, normally, you would be able to control only 4 LEDs, but the 8-bit shift register is a cunning little bit of kit. The wiring here is a bit of a logistical nightmare, but hopefully with the wiring diagram you'll manage.

8-bit shift registers for dummies

In very simple terms, the 8-bit shift register has a series of 8 on/off switches that can hold the values 0 (off) or 1 (on). These 8 bits make 1 byte and can encode integer values up to 255 in binary. Each of these 8 bits are filled up one-by-one and shifted along each time a new one is filled, hence the name shift register. There are two latch pins that lock in these bits, the shift register clock (SRCLK) and the storage register clock (RCLK), as well as a serial (SER) pin that sets each bit on or off.

Each of the 8 bits controls one output pin, and we'll use these 8 output pins to control our 8 LEDs. This method of controlling multiple output pins with only a few input pins is known as serial-in-parallel-out (SIPO) as the information is passed in serially (the 8 bits) and then sent out in parallel (the states of the 8 output pins are updated at the same time).

There's a slight complication with using Explorer HAT Pro to control the shift register, in that we need to be able to set the output pins to high or low, and the Explorer HAT's output pins get pulled to ground (low) when they are switched on rather than high. Fortunately, there's an easy solution - pull-up resistors - which will pull the output pins to high when they are off, meaning that off is on and on is off. These are simple to connect up, we just connect the three input pins of the shift register up to three of the Explorer HAT Pro's output pins and also connect each of these to the 5V supply from Explorer HAT pro via a 10 kΩ resistor.

Setting the hardware up

We need quite a few things to set this all up:

  • A Raspberry Pi
  • Explorer HAT Pro
  • 74HC595 8-bit shift register
  • 8 5mm LEDs
  • 8 470 Ω resistors
  • 3 10 kΩ resistors
  • A mini breadboard or 400 point (half-size) breadboard
  • A bunch of jumper leads

Note that you can get all of this, with the exception of the Raspberry Pi, Explorer HAT and mini breadboard, in the Explorer HAT Pro parts kit.

I've set this up a couple of different ways. In the wiring diagram below, I've put the LEDs and voltage-limiting resistors on one mini breadboard and the shift register and pull-up resistors on the mini breadboard on Explorer HAT Pro. You can, and I have, put everything on the same mini breadboard, but the wiring is a complete nightmare! If you want everything on the same breadboard, then I'd suggest using a larger half-size breadboard.

Here's the wiring diagram.

Explorer HAT shift register

I connected the shift register clock (SRCLK) pin to output one on Explorer HAT pro, the storage register clock (RCLK) pin to output two and the serial (SER) pin to output three, but this doesn't matter as long as you specify the pins correctly in the Python code.

Setting the software up

I've created a new plugins module, in my fork of the Explorer HAT Python library, that contains a ShiftRegister class with methods for toggling the pins on or off and a few different patterns to use with LEDs.

Here's how to clone and install my fork:

curl https://get.pimoroni.com/i2c | bash
sudo apt-get install python-smbus
git clone https://github.com/sandyjmacdonald/explorer-hat.git
cd explorer-hat/library
sudo python setup.py install

I'll explain below how to use the ShiftRegister class and how it works, but if you're impatient, or just want to make sure that you've connected it all up correctly, then you can start an interactive Python prompt by typing python and pressing return. Type the following to run a demo of the ShiftRegister class:

from explorerhat import plugins

shiftreg = plugins.ShiftRegister()
shiftreg.demo()

This should blink all 8 LEDs on and off 5 times, run along the line of LEDs 5 times, alternately blink the odd and even LEDs 5 times and run back and forth along the line of LEDs 5 times.

How it works and how to use the ShiftRegister class

Here's the basic function from the ShiftRegister class that toggles a pin on or off:

import explorerhat

srclk = explorerhat.output.one
rclk = explorerhat.output.two
ser = explorerhat.output.three

def toggle_pin(pin, state):
    rclk.on()
    for p in range(8):
        srclk.on()
        if p == pin:
            if state == 1:
                ser.off()
            else:
                ser.on()
        else:
            if state == 1:
                ser.on()
            else:
                ser.off()
        srclk.off()
    rclk.off()

So, if you want to toggle on LED 1 (remember that indices begin from 0 in Python, so pin 1 is actually pin 0) you would simply use toggle_pin(0, 1). Note that the state variable uses 0 for off and 1 for on in this function.

We'll break down how the function works.

Outside our function, we import the explorerhat library and define our srclk, rclk and ser pins.

The toggle_pin function takes two variables - pin and state - that define the pin we want to toggle and whether to toggle it off or on (0 or 1 respectively).

Remember that the pull-up resistors reverse what is happening with the output pins, so when it says on in the function, that's actually off and vice versa.

We toggle the storage register clock pin, rclk, off to begin with rclk.on().

Then for each output pin, for p in range(8):, we first toggle the shift register clock, srclk, off with srclk.on().

Then we check whether it's the pin we want to toggle on or off with if p == pin:. If it is, we check whether to toggle it on with if state == 1: and switch the serial pin, ser, on with ser.off(), otherwise we switch it off with ser.on().

We toggle the shift register clock, srclk, on.

We then go through the remainder of the eight pins, doing the same as we did above - toggling the shift register clock off, checking whether it's the pin we want to toggle on or off and then toggling the serial pin accordingly, and toggling the shift register clock on each time.

Finally, we toggle the storage register clock pin, rclk, on, to shift out all of the bits we stored.

So, that's how the basic function to toggle a single output pin on or off works. Obviously, if we wanted to toggle several pins simultaneously, this function wouldn't do, because if we toggle one pin on, it assumes we want to toggle all of the others off.

To toggle all of the pins on or off, we'd just have the same function, with the same for p in range(8): loop, but exclude the if p == pin: and else, as follows:

def toggle_all(self, state):
    rclk.on()
    for p in range(8):
        srclk.on()
        if state == 1:
            ser.off()
        else:
            ser.on()
        srclk.off()
    rclk.off()

In the Explorer HAT pro Python plugins module that I've written, there's a ShiftRegister class that can be used to control the shift register with a number of methods of the class (they're just functions that belong to the class). This allows us to create objects assigned to a variable, e.g. shiftreg = plugins.ShiftRegister(), and then run the methods within the class, like the demo method, with shiftreg.demo().

Other methods of the ShiftRegister class

Here's the full list of methods available so far in the ShiftRegister class:

shiftreg.toggle_pin()   # Toggle a single pin
shiftreg.toggle_all()   # Toggle all of the pins
shiftreg.toggle_odd()   # Toggle the odd numbered pins
shiftreg.toggle_even()  # Toggle the even numbered pins
shiftreg.chase()        # Toggle all the pins sequentially in one direction
shiftreg.scan()         # Toggle all the pins sequentially back and forth
shiftreg.demo()         # Runs all of the above

It's simple to add your own method to the ShiftRegister class. You just need to remember a few things. First, it needs to be within the ShiftRegister class, i.e. indented a level further in than the first line of the class, where it says class ShiftRegister:. Next, it looks just like a normal Python function, in that it begins with def method_name():, except that you must always pass self as the first argument like so: def method_name(self, arg1, arg2):. You need to pass self even if you're not passing any other arguments in, as I have in the previous example.

As long as you follow the pattern I showed above to set the pins - toggle the storage register clock off then for each pin, toggle the shift register clock off, the serial pin on or off and the shift register clock on, and finally toggle the storage register clock back on - then the world is your lobster (or oyster, or whatever)!

Taking it further

It's possible to daisy-chain the 8-bit shift register chips together to drive even more LEDs from the same 3 output pins. You'd just connect up the last output pin of one chip to the serial input pin of the second chip and connect up the other two input pins, the storage register clock and the shift register clock, from the two chips, so that they switch on and off at the same time.

I won't show you how to do that here, and you'd have to modify the code to do it, but I encourage you to give it a try!

That's all folks!

Search above to find more great tutorials and guides.

Plasma 2040

Swathe everything in rainbows with this all-in-one, USB-C powered controller for WS2812/Neopixel and APA102/Dotstar addressable LED strip.