Arduino, 74HC595 Shift Register, and a 7-Segment LED Display

So I’ve recently started tinkering with Arduino. Arduino is a pretty easy to use open-source microcontroller. And it’s cheap!

Being a novice I decided to work through a book called Beginning Arduino by Michael McRoberts. I’m up to Chapter 7 and it’s now talking about multiplexing and LED dot-matrix displays, so I wanted to have a tinker. Not having a dot-matrix display to hand I decided to see what I could come up with myself. I had purchased a Sparkfun Beginner Parts Kit (KIT-10003) and a SparkFun Inventor’s Kit (RTL-10339), which meant I had a small 7-segment LED display (common anode) and a 74HC595 Shift Register IC.

I gave up trying to work out the maximum current I could source (or sink) with the 74HC595 — different sources quoted different values — so to be on the safe side, and to make the project a little more interesting, I decided to write some Arduino code that would only allow one segment in the display to be illuminated at once, but that would cycle between the segments so quickly it would look like they were all on at once. This gave me a chance to look at multiplexing and bitwise operations.

Segments for my display (and this is pretty much universally adopted) are identified by the letters A to G (+ DP, or DecimalPoint), as indicated in the following diagram:

                         A
                        ---
                    F / G / B
                      ---
                  E /   / C
                    ---  * DP
                     D

The pinout for my display is shown in the crude diagram below:

    Common anode (+) pins: 3 & 8
                             o
                             |
               +---+---+---+-+-+---+---+---+   [+]
               |   |   |   |   |   |   |   |
           /   V   V   V   V   V   V   V   V
       LEDs    -   -   -   -   -   -   -   -
           \   |   |   |   |   |   |   |   |
               |   |   |   |   |   |   |   |
               o   o   o   o   o   o   o   o   [-]
          Pin: 7   6   4   2   1   9   10  5
      Segment: A   B   C   D   E   F   G   DP

So in order to display the number “4″ we need to illuminate segments B, C, F & G, or connect pins 6, 4, 9 and 10 on the LED display to LOW:

                       . . .
                      /   /
                      ---
                    .   /
                   . . .

Rather conveniently, a byte is made up of eight bits, so I can use a byte to describe the state of each of these 7 segments (8, if we include the decimal point) for any given character or symbol I might want to display.

The character “4″, shown above, can be described in this binary notation as “0b01100110″:

    LED Segment:  A B C D E F G DP
         On/Off:  0 1 1 0 0 1 1 0

A description of which segments need to be on for each digit, in this binary form, is held in the “numbers” array. This array holds the digits 0 to 9, and A to F.

As discussed, to display the number “4″ we need to illuminate segments B, C, F & G. However, there is a risk that running four LEDs with the 74HC595 could mean too much current is drawn. We’re working at 3.3v, and have a 220 ohm resistor on the cathode, so this should limit the current to about 15 mA. This is safe for the shift register to sink, but sharing this across 4 LEDs would make them pretty dim. So this is where multiplexing comes in!

The code below works out which segments need to be illuminated to display or character, and sequentially lights them up one by one. Only one LED segment is ever on at a time, but the sequence runs so quickly that it looks like all the segments are on at once.

So enough of the theory, and on to the code!

Wire it up

First, the wiring diagram. The wiring is described in the code comments below if you find it hard to follow this diagram.

Grab the code

Download the source code: _7SegCounterMultiplexer.pde (this is a slightly longer version of the code below — it has more annotations & comments).

/*
  7-Segment LED counter, multiplexing using 74HC595 8-bit shift
  register.

  Displays a digit by illuminating each individual segment that makes
  it up on the display sequentially, rather than illuminating each
  segment at once. This is done very quickly (multiplexing) to give
  the illusion that all the nesersary segments are illuminated at
  once. This is because the 74HC595 can’t source or sink that much
  current, and lighting all segments for the digit ‘8′ at once for
  example could require too much current and damage the chip.

  Connections

    Vcc = 3.3v on Arduino

    Arduino pin 5 => 74HC595 pin 12
    Arduino pin 6 => 74HC595 pin 14
    Arduino pin 7 => 74HC595 pin 11

    74HC595 pin 1  (Q1)   => LED Pin 6  (B)
    74HC595 pin 2  (Q2)   => LED Pin 4  (C)
    74HC595 pin 3  (Q3)   => LED Pin 2  (D)
    74HC595 pin 4  (Q4)   => LED Pin 1  (E)
    74HC595 pin 5  (Q5)   => LED Pin 9  (F)
    74HC595 pin 6  (Q6)   => LED Pin 10 (G)
    74HC595 pin 7  (Q7)   => LED Pin 5  (DP)
    74HC595 pin 8  (GND)  => Ground
    74HC595 pin 9  (Q7S)  => Not connected
    74HC595 pin 10 (MR)   => Vcc (High)
    74HC595 pin 11 (SHCP) => Arduino pin 7
    74HC595 pin 12 (STCP) => Arduino pin 5
    74HC595 pin 13 (OE)   => Ground (Low)
    74HC595 pin 14 (DS)   => Arduino pin 6
    74HC595 pin 15 (Q0)   => LED Pin 7  (A)
    74HC595 pin 16 (Vcc)  => Vcc

    LED pin 3 or 8 => 220 Ohm resistor => Vcc

    Created 6 Nov 2011
    by Mark Sweeting - www.sweeting.org/mark
 */

const int latchPin = 5;  // Pin connected to Pin 12 of 74HC595 (Latch)
const int dataPin  = 6;  // Pin connected to Pin 14 of 74HC595 (Data)
const int clockPin = 7;  // Pin connected to Pin 11 of 74HC595 (Clock)

unsigned long t1;
unsigned long t2;
int i = 0;

// Describe each digit in terms of display segments
// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F
const byte numbers[16] = {
                    0b11111100,
                    0b01100000,
                    0b11011010,
                    0b11110010,
                    0b01100110,
                    0b10110110,
                    0b10111110,
                    0b11100000,
                    0b11111110,
                    0b11100110,
                    0b11101110,
                    0b00111110,
                    0b10011100,
                    0b01111010,
                    0b10011110,
                    0b10001110
};

void setup()
{

  // initialisation time
  t1 = millis();

  //set pins to output 
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
}

void loop()
{
    // update digit every two seconds
    t2 = millis();
    if(t2 - t1 > 2000)
    {
      i++;
      t1 = t2;
      if(i > 15) { i = 0; }
    }
    // display the current digit
    show(numbers[i]);
}

void show( byte number)
{
  // Use a loop and a bitwise AND to move over each bit that makes up
  // the seven segment display (from left to right, A => G), and check
  // to see if it should be on or not
  for(int j = 0; j <= 7; j++)
  {
    byte toWrite = number & (0b10000000 >> j); 

    // If all bits are 0 then no point writing it to the shift register,
    // so break out and move on to next segment.
    if(!toWrite) { continue; }

    // Otherwise shift it into the register
    shiftIt(toWrite);
  }
}

void shiftIt (byte data)
{
    // Set latchPin LOW while clocking these 8 bits in to the register
    digitalWrite(latchPin, LOW);

    for (int k=0; k <= 7; k++)
    {
      // clockPin LOW prior to sending a bit
      digitalWrite(clockPin, LOW); 

      // Note that in our case, we need to set pinState to 0 (LOW) for
      // “On” as the 74HC595 is sinking current when using a common
      // anode display. If you want to use a common cathode display then
      // switch this around.
      if ( data & (1 << k) )
      {
        digitalWrite(dataPin, LOW); // turn “On”
      }
      else
      {
        digitalWrite(dataPin, HIGH); // turn “Off”
      }

      // and clock the bit in
      digitalWrite(clockPin, HIGH);
    }

    //stop shifting out data
    digitalWrite(clockPin, LOW); 

    //set latchPin to high to lock and send data
    digitalWrite(latchPin, HIGH);

    // put delay here if you want to see the multiplexing in action!
    //delay(100);
}

So how does it work?

Hopefully the code is documented pretty well. However there are a few bits that could be expanded on further perhaps. First, the function show(). It takes a whole byte as an argument (called “number”, which in hindsight may not be the best name to choose…), and remember that these bytes describe each segment that should be on (or off) in the 7 segment display.

So this function moves over each segment in the LED display (A to G, plus the decimal point), and works out if the segment should be off or on in order to display the chosen number. For example, to decide if segment “B” should be illuminated when displaying the digit “6″, we perform a bitwise AND with their two byte values:

    "6" is 0b10111110 and Segment B is represented by the 2nd bit from
    the left  You can see it's value is Off.

    The Bitwise AND operation results in the following:

       10111110  first operand
     & 01000000  second operand
       --------
       00000000  outcome of bitwise AND: all bits are Off.

In this example, Segment B isn’t needed to display the digit “6″ so we jump on to the next segment: Segment C:

       10111110  first operand -- "6"
     & 00100000  second operand -- Third bit, Segment C
       --------
       00100000  outcome of bitwise AND: Third bit is On.

In this case we need to turn Segment C on, so we call shiftIt(00100000) and pass in a byte that tells us to turn on the third segment on the display. shiftIt needs to clock in all 8 bits, even though only one of them will be on. I’m not about to explain how Shift Registers work — check out the Arduino site for a good explanation and lots of code samples — however I should point out that we need to set a bit LOW when we want to turn an LED segment on, because we’re using the 74HC595 to sink current rather than source it because our display has a common anode.

So there you have it.

There are probably better ways to display digits on an LED, but it’s an interesting technique none the less.

Sociable:These icons link to social bookmarking sites where readers can share and discover new web pages.
  • del.icio.us
  • digg
  • Furl
  • NewsVine
  • Reddit
  • YahooMyWeb

Leave a Reply