8-bit shift register driving a 7-segment common anode display. Very early prototype.

I decided to send one of my good friends in Germany an Arduino starter kit for his birthday. Instead of the usual birthday card, I thought that it could be cool to have a single 7-segment LED pre-wired to the Arduino so it can display something like “Happy Birthday!” as soon as he plugs it in.

Since I didn’t want to break in his brand new starter kit, I decided to use one of my spare Proto Shields and a bunch of other spare parts (1 x 74HC595 8-bit Shift Register, 8 x 220 Ω resistors, 1 x  7-segment common anode display) and started building a circuit that is very similar to the one in theArduino ShiftOut Tutorial.

The main difference is that due to the common anode display, we’re dealing with an active-low circuit as opposed to an active-high circuit as described in the tutorial. That basically means that everything works exactly “the other way round”, meaning that we have to wire the individual cathodes to the output of the shift-register and send a low-bit in order to activate an LED segment of the display and a high-bit to deactivate it.
To make the transition between the individual 7-segment characters more visually pleasing, I also wired the display’s anode to one of the Arduino’s analog pins. This allows me to control the brightness of the 7-segment display via PWM.

8-bit shift register driving a 7-segment common anode display. Final proto-shield version.

The code example is pretty straight forward: it cycles through the  128-characters of the 7-segment character set, inverts the bits (remember the cathodes of the LEDs are connected to the 74HC595) and shifts them out to the register using Arduino’s built-in shiftOut() function. Between each character, it fades the display’s brightness down to 0% and than back up to 100% using analogWrite().

There’s a good article on 7-segment display character representations at Wikipedia, but I decided to use the 7-segment character set (which is pretty nice, btw) from Eli McIlveen. He was nice enough to put it in the public domain. The really nice thing about his character set is, that the character positions in the array match their ASCII representation: for example A can be found at ledCharSet['A'], B at ledCharSet['B'] and so on. That way it was really a no-brainer to display my “Happy Birthday” message. Here’s the source code and wiring diagrams:

/* Example code for driving a single 7-segment display with
 a 74HC595 8-bit shift register

 The code cycles through the the entire 7-segment character
 set that was written by Eli McIlveen:

 (http://www.forgeryleague.com/lab/entry/arduino_7_segment_output/)

 In case of a COMMON ANODE display the bytes need to be inverted
 as shown in the loop() function: bitsToSend = bitsToSend ^ B11111111

 Hardware:

 * 74HC595 shift register attached to pins 2, 3, and 4 of the Arduino,
   as detailed below.

 * Pins to connect to common-cathode LED display via a 74HC595:
   DP-15, A-1, B-2, C-3, D-4, E-5, F-6, G-7 (shiftOut using LSBFIRST)
   Or:
   DP-7, A-6, B-5, C-4, D-3, E-2, F-1, G-15 (shiftOut using MSBFIRST)

 Created 12 October 2010
 by Ole Weidner (http://www.oleweidner.com/?p=434)
 */

const byte ledCharSet[128] =
{
  	// 00-0F: Hex digits
  	B01111110, B00110000, B01101101, B01111001,	// 0123
  	B00110011, B01011011, B01011111, B01110000,	// 4567
  	B01111111, B01111011, B01110111, B00011111,	// 89AB
  	B01001110, B00111101, B01001111, B01000111,	// CDEF

  	// 10-1F: Figure-8 drawing (8-character cycle)
  	B01000000, B00100000, B00000001, B00000100,	// 1-segment
  	B00001000, B00010000, B00000001, B00000010,

  	B01100000, B00100001, B00000101, B00001100,	// 2-segment
  	B00011000, B00010001, B00000011, B01000010,

  	// 20-2F: Punctuation (barely recognizable!)
    	B00000000, B10100000, B00100010, B00111111,	//  !"#
    	B01011010, B01001001, B00000111, B00000010,	// $%&'
    	B01001110, B01111000, B01100011, B00110001,	// ()*+
    	B00010000, B00000001, B10000000, B00100101,	// ,-./

    	// 30-3F: Decimal digits (alternate) and more punctuation
    	B01111110, B00110000, B01101101, B01111001,	// 0123
    	B00110011, B01011011, B00011111, B01110010,	// 4567
    	B01111111, B01110011, B01001000, B01010000,	// 89:;
    	B00001101, B00001001, B00011001, B11100000,	// <=>?

    	// 40-5F: Capital letters and punctuation
    	B01101110, B01110111, B00011111, B01001110,	// @ABC
    	B01111100, B01001111, B01000111, B01011110,	// DEFG
    	B00110111, B00000110, B00111100, B01010111,	// HIJK
    	B00001110, B01110110, B00010101, B01111110,	// LMNO

    	B01100111, B01110011, B01000110, B01011011,	// PQRS
    	B01110000, B00111110, B00111110, B00101011,	// TUVW
    	B01110101, B00111011, B01101101, B01001110,	// XYZ[
    	B00010011, B01111000, B01100010, B00001000,	// \]^_

    	// 60-7F: Lowercase letters and punctuation
    	B01100000, B01111101, B00011111, B00001101,	// `abc
    	B00111101, B01101111, B01000111, B01111011,	// defg
    	B00010111, B00010000, B00011000, B00101111,	// hijk
    	B00001100, B01010101, B01101010, B00011101,	// lmno

    	B01100111, B01110011, B00000101, B00010011,	// pqrs
    	B00001111, B00011100, B00100011, B01011101,	// tuvw
    	B01101100, B00111011, B00100101, B01000011,	// xyz{
    	B00110110, B01100001, B01000000, B11111111	// |}~
};

//// Pin connected to latch pin (ST_CP) of 74HC595
const int latchPin = 8;
//// Pin connected to clock pin (SH_CP) of 74HC595
const int clockPin = 12;
//// Pin connected to Data in (DS) of 74HC595
const int dataPin  = 11;
//// Pin connected to display's common annode
const int faderPin = 10;

/////////////////////////////////////////////////////////////////////////////////
//
void setup()
{
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin,  OUTPUT);
  pinMode(faderPin, OUTPUT);
}

/////////////////////////////////////////////////////////////////////////////////
//
void loop()
{
  for(int i=0; i <= 128; ++i)
  {
    byte bitsToSend = ledCharSet[i];

    // invert bitmas - we're using a common ANODE display.
    // for common cathode, comment out the following line.
    bitsToSend = bitsToSend ^ B11111111; 

    // turn off the output so the pins don't light up
    // while you're shifting bits:
    digitalWrite(latchPin, LOW);

    // shift the bits out:
    shiftOut(dataPin, clockPin, MSBFIRST, bitsToSend);

    // turn on the output so the LEDs can light up:
    digitalWrite(latchPin, HIGH);

    fadeInOut();
  }
}

/////////////////////////////////////////////////////////////////////////////////
//
void fadeInOut()
{
  for(int i = 0; i < 255; ++i)
  {
    analogWrite(faderPin, i);
    delay(1);
  }
  for(int i = 255; i > 0; --i)
  {
    analogWrite(faderPin, i);
    delay(1);
  }
}

Download Source Code: SevenSeg_CommonAnnode_74HC595.pde