DEV Community

Cover image for [Elixir/Nerves] Seven-segment LED, shift register and SPI interface
Masatoshi Nishiguchi
Masatoshi Nishiguchi

Posted on

[Elixir/Nerves] Seven-segment LED, shift register and SPI interface

I enjoy Elixir programming for my Raspberry Pis using Nerves IoT framework. This is my study note about controlling a seven-segment LED with a shift register through SPI interface from my Nerves-powered Raspberry Pi.

When I was doing experiments with a character LCD display with serial interface, I learned many boards like Adafruit i2c/SPI LCD backpack has shift registers or I/O expanders built in so that we do not do the tedius work of physically wiring many I/O pins. All I need was just connect a few wires for i2c/SPI.

Today, I want to wire an 8-bit shift register by myself. I use one digit seven-segment LED display, which has eight LEDs internally. From my Raspberry Pi, I will control the seven-segment display though the SPI interface.

Seven-segment LED display

According to Wikipedia:

A seven-segment display is a form of electronic display device for displaying decimal numerals that is an alternative to the more complex dot matrix displays.

There are two types of seven-segment LED display:

  • Common-Cathode
  • Common-Anode

We need to use a resistor for GND or VCC in accordance with the forward current value in the product's data sheet just like we would for basic LEDs.

Common-Cathode (CC) display

Common-Anode (CA) display

SN74HC595

SN74HC595 is an 8-bit shift register, which can be used as a serial-to-parallel converter to send signals to the display. From our controller device, we serially send eight bits of data through one signal pin over to the shift register. Then the shift register can output it from eight pins at once.

Pin Description
QA-QH 8-bit parallel data output pins
QH' serial output that can be connected to SER of another 74HC595
SRCLR (Shift Register Clear) negative logic pin; should be kept at HIGH.
SRCLK (Shift Register Clock) For each clock pulse, data in the shift register moves by one bit.
RCLK (Register Clock) For each clock pulse. data in the shift register moves into memory register.
OE (Output Enable Input) negative logic pin; should be kept at LOW.
SER (Serial Data Input) The data is entered serially through this pin, one bit a time.

The Arduino website a nice tutorial on 74HC595 Shift Register.

SPI

According to Wikipedia:

The Serial Peripheral Interface (SPI) is a synchronous serial communication interface specification used for short-distance communication, primarily in embedded systems.

I use Circuits.SPI library, which allows me to send a byte at a time

To me, the advantage of using SPI for a shift register is that SPI abstracts away the connection between the controller device and the shift register. All I need is just to send a byte using SPI library. Without SPI, I would have to write code to send one bit after another and then send a signal to trigger the output for each iteration.

Demo

Hardware

Software

Pinouts

74HC595 Raspberry Pi Seven-segment display
QB (Output) - B
QC (Output) - C
QD (Output) - D
QE (Output) - E
QF (Output) - F
QG (Output) - G
QH (Output) - DP
GND (Ground) GND (Ground) -
QH' (Output) - -
SRCLR (Shift Register Clear Input) 3.3V -
SRCLK (Serial Clock Input) SPI SCLK (Clock) -
RCLK (Register Clock Input) SPI CE (Chip Enable) -
OE (Output Enable Input) GND (Ground) -
SER (Serial Data Input) SPI COPI (Controller Out Peripheral In) -
QA (Output) - A
VCC (Power) 3.3V -

SN74HC595 top view

seven-segment-wiring

pi-spi-wiring

Programming

The seven-segment display has seven segments plus dot, a total of eight LEDs. We will specify which segment we want to be on/off by sending a byte (8 bits). Depending on the display type, a high bit (1) can mean "on" or "off" state. In my case, since I use a common-cathode display, a high bit represents the "on" state. Assuming the pin assignment is as stated earlier, the following list maps numbers to eight bits for a common-cathode display.

shape DpGFEDCBA hex
0 00111111 0x3f
1 00000110 0x06
2 01011011 0x5b
3 01001111 0x4f
4 01100110 0x66
5 01101101 0x6d
6 01111101 0x7d
7 00000111 0x07
8 01111111 0x7f
9 01101111 0x6f
A 01110111 0x77
B 01111100 0x7c
C 00111001 0x39
D 01011110 0x5e
E 01111001 0x79
F 01110001 0x71

With a common-anode display, the on/off state above would be inverted. For example, 11000000 would represent the "0" shape.

Here is the Elixir code that I wrote. I ssh into my Raspberry Pi and run that program from the Interactive Elixir shell (iex).

Circuits.SPI.bus_names()
# ["spidev0.0", "spidev0.1"]

{:ok, ref} = Circuits.SPI.open("spidev0.0")
# {:ok, #Reference<0.50134155.268828678.71837>}

# Show "0" on the display.
Circuits.SPI.transfer(ref, <<0x3f>>)

# A function that repeats displaying from "0" to "9".
count_fn = fn(count_fn) ->
  digits = [0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f]
  digits |> Enum.each(fn x ->
    Circuits.SPI.transfer(ref, <<x>>)
    Process.sleep(500)
  end)

  count_fn.(count_fn)
end

# Call the function.
count_fn.(count_fn)
Enter fullscreen mode Exit fullscreen mode

One mistake I made

I forgot to use a 220ohm resistor for the common cathode. I re-wire with a 220ohm resistor without turning off the device, which broke the LED closest to the pin I was working on.

That's it.

seven-segment-counting

Links

Top comments (0)