Driving 7-segment Displays with 74HC595

A seven-segment display is a LED module composed of 8 LEDs. 7 of the LEDs are for segments of one digit (shown as A to G below) and the other LED is for the decimal point (shown as DP below).

Depending on it's a common-anode or a common-cathode module, its schematic can be represented as:

A common-anode seven-segment display

or

A common-cathode seven-segment display

As a consequence, an intuitive way to control a seven-segment display is to use 8 GPIOs to connect to A, B, C, D, E, F, G and DP signal pins and control each pin as turning on/off an ordinary LED. Therefore the display can show any desired pattern composed of all those 8 segments.

Use P7 to P14 to control a common-anode seven-segment display

Different combinations of possible displayed segments

Using a shift register to reduce pin usage

In the above example, 8 GPIO pins are needed to drive a single seven-segment display. Though it's intuitive, this circuit setup is very pin-consuming. Assuming the case where a four-digit display is needed, this setup means a total 32 (8 pins x 4 digits) pins are required to control the display. It's usually not feasible for a development board to provide so many GPIOs and it also introduces huge complexity in the circuit setup. To solve this issue, a shift register chip can be used to reduce the necessary pin numbers for controlling a seven-segment display. In the following sections, the 74HC595 shift register chip would be used as an example. In the first part, we'll show how to simply use 3 GPIOs to control one seven-segment display by using a shift register. And based on this configuration, an example for how to extend it to control 4 seven-segment displays, by still using one shift register, is also introduced.

74HC595 shift register

For saving the pin number for controlling a seven-segment display, a shift register is used as a serial-to-parallel converter to send signals to the display. That is, we serially send 8 bits of data, which represents the way we want to turn on the display, by one signal pin into the shift register and the register can output the corresponding data pattern to its 8 output pins at once (parallel).

Signal pins we need to take care about when using a 74HC595 are (please refer to its datasheet for pin names):

Input pins

  • 1 input data pin (DS)

  • 1 clock pin for input data (SHCP)

  • 1 clock pin for output data (STCP)

Output pins

  • 8 data pins (Q0 ~ Q7)

Control pins

  • 1 output enable pin (OE)

  • 1 data reset pin (MR)

And next we'll show the circuit connection for using it.

Driving one seven-segment display with 74HC595

In the circuit below, LinkIt 7697 connects to the input pins of 74HC595 with orange wires and the output pins of 74HC595 are with blue wires.

We use this sketch file to show hexadecimal digits (0 ~ 9 and a ~ f) repeatedly on a common-anode seven-segment display:

//
// Use one 74HC595 to control a common-anode seven-segment display
//

// pin 11 of 74HC595 (SHCP)
const int bit_clock_pin = 16;
// pin 12 of 74HC595 (STCP)
const int digit_clock_pin = 15;
// pin 14 of 74HC595 (DS)
const int data_pin = 14;

// digit pattern for a 7-segment display
const byte digit_pattern[16] =
{
  B00111111,  // 0
  B00000110,  // 1
  B01011011,  // 2
  B01001111,  // 3
  B01100110,  // 4
  B01101101,  // 5
  B01111101,  // 6
  B00000111,  // 7
  B01111111,  // 8
  B01101111,  // 9
  B01110111,  // A
  B01111100,  // b
  B00111001,  // C
  B01011110,  // d
  B01111001,  // E
  B01110001   // F
};

unsigned int counter = 0;

void setup()
{
  pinMode(data_pin, OUTPUT);
  pinMode(bit_clock_pin, OUTPUT);
  pinMode(digit_clock_pin, OUTPUT);  
}
 
void update_one_digit(int data)
{
  int i;
  byte pattern;
  
  // get the digit pattern to be updated
  pattern = digit_pattern[data];

  // turn off the output of 74HC595
  digitalWrite(digit_clock_pin, LOW);
  
  // update data pattern to be outputed from 74HC595
  // because it's a common anode LED, the pattern needs to be inverted
  shiftOut(data_pin, bit_clock_pin, MSBFIRST, ~pattern);
  
  // turn on the output of 74HC595
  digitalWrite(digit_clock_pin, HIGH);
}

void loop()
{ 
  int i;
  unsigned int digit_base;
  
  counter++;
  
  digit_base = 16;

  // get the value to be displayed and update one digit
  update_one_digit(counter % digit_base);
  
  delay(500);
}

Explanation

  • Digit patterns are pre-defined in the digit_pattern array, which indicates what segment needs to be turned on for composing one digit.

  • shiftOut() API is called to serially send the data pattern to the shift register. Note: because a common-anode seven-segment display is used here, the data pattern needs to be inverted (~pattern) for correctly showing the digit. If you're using a common-cathode display, the pattern doesn't need to be inverted (and of course, the circuit needs to be adjusted accordingly).

  • digit_clock_pin is the signal we use to control the STCP pin of the 74HC595. It enables / disables the output of the shift register.

This example shows how to use 3 (instead of 8) pins on LinkIt 7697 to drive one seven-segment display with a shift register. In general, if there are N digits needed to be driven, 3N signal pins and N shift registers are necessary. In the next section, we'll show another technique to simply use one shift register to drive a four-digit seven-segment display module.

Driving four seven-segment display with one 74HC595

When it comes to display more than one digit, more seven-segment displays are needed. According to the example above, N-digit display needs N shift registers and 3N control pins from a development board. Here we use a commonly seen four-digit seven-segment display module to demonstrate how to drive four digits by still using one shift register.

The schematic of the display module is shown as below:

It's a common-anode four-digit seven-segment display. And we connect it with a 74HC595 and LinkIt 7697 as:

Similar to the previous example, LinkIt 7697 connects to the input pins of 74HC595 with orange wires and the output pins of 74HC595 are with blue wires. Moreover, four control pins (yellow wires) are needed from LinkIt 7697 to turn on / off each digit in the module. We use the sketch below to drive the display and it will show numbers counting increasingly as in the video:

Sketch file

//
// Use one 74HC595 to control a 12-pin common-anode 4-digit seven-segment display with fast scanning
// the display: http://www.icshop.com.tw/product_info.php/products_id/19357
//

#define DELAY_FACTOR  (100)
#define NUM_OF_DIGITS (4)

// 4 display on/off pin (for the common anode/cathode)
const int control_pins[NUM_OF_DIGITS] = {17, 5, 4, 3};
// pin 11 of 74HC595 (SHCP)
const int bit_clock_pin = 16;
// pin 12 of 74HC595 (STCP)
const int digit_clock_pin = 15;
// pin 14 of 74HC595 (DS)
const int data_pin = 14;

// digit pattern for a 7-segment display
const byte digit_pattern[16] =
{
  B00111111,  // 0
  B00000110,  // 1
  B01011011,  // 2
  B01001111,  // 3
  B01100110,  // 4
  B01101101,  // 5
  B01111101,  // 6
  B00000111,  // 7
  B01111111,  // 8
  B01101111,  // 9
  B01110111,  // A
  B01111100,  // b
  B00111001,  // C
  B01011110,  // d
  B01111001,  // E
  B01110001   // F
};

int digit_data[NUM_OF_DIGITS] = {0};
int scan_position = 0;

unsigned int counter = 0;

void setup()
{
  int i;

  // set related pins as output pins
  for (i = 0; i < NUM_OF_DIGITS; i++)
  {
    pinMode(control_pins[i], OUTPUT);
  }

  pinMode(data_pin, OUTPUT);
  pinMode(bit_clock_pin, OUTPUT);
  pinMode(digit_clock_pin, OUTPUT);  
}
 
void update_one_digit()
{
  int i;
  byte pattern;
  
  // turn off all digit
  for (i = 0; i < NUM_OF_DIGITS; i++)
  {
    digitalWrite(control_pins[i], LOW);
  }

  // get the digit pattern of the position to be updated
  pattern = digit_pattern[digit_data[scan_position]];

  // turn off the output of 74HC595
  digitalWrite(digit_clock_pin, LOW);
  
  // update data pattern to be outputed from 74HC595
  // because it's a common anode LED, the pattern needs to be inverted
  shiftOut(data_pin, bit_clock_pin, MSBFIRST, ~pattern);
  
  // turn on the output of 74HC595
  digitalWrite(digit_clock_pin, HIGH);

  // turn on the digit to be updated in this round
  digitalWrite(control_pins[scan_position], HIGH);

  // go to next update position
  scan_position++;
  
  if (scan_position >= NUM_OF_DIGITS)
  {
    scan_position = 0; 
  }
}

void loop()
{ 
  int i;
  unsigned int number;
  unsigned int digit_base;
  
  counter++;
  
  // get the value to be displayed
  number = counter / DELAY_FACTOR;

  digit_base = 10;

  // get every values in each position of those 4 digits based on "digit_base"
  //
  // digit_base should be <= 16
  //
  // for example, if digit_base := 2, binary values will be shown. If digit_base := 16, hexidecimal values will be shown
  //
  for (i = 0; i < NUM_OF_DIGITS; i++)
  {
    digit_data[i] = number % digit_base;
    number /= digit_base;
  }

  // update one digit
  update_one_digit();
  
  delay(4);
}

Explanation

  • How to drive 4 displays with still one shift register? Persistence of vision is utilized and this sketch rapidly updates one digit in every loop() routine.

  • The on / off switch of each digit is controlled through the control_pins array.

  • When the pattern is correctly set through the shift register, the sketch then turn on that digit by setting control_pins[scan_position] to HIGH.

  • Each loop() routine only updates one digit. In order to make the persistence of vision take effects, the loop() routine needs to be executed frequently.

As a result, you can simply use one shift register to drive 4 digits. Comparing to the original 8-GPIO-for-one-digit method, now only 7 control pins (instead of 32) from LinkIt 7697 are needed for driving 4 digits. This saves lots of control pins needed and reduces the circuit layout complexity.

Summary

Seven-segment displays are commonly used in different areas to display numerical information for user interaction. So it's worth understanding how to drive them correctly and efficiently. In this tutorial, we introduced three ways to drive the seven-segment display:

  1. Intuitive LED on / off mechanism.

  2. Using one shift register to drive one digit.

  3. Utilizing the effect of persistence of vision to drive a 4-digit display with one shift register.

This gives the fundamental concept about how to drive a seven-segment display and the idea about using a shift register as a serial-to-parallel converter. Also, the technique to utilize persistence of vision is introduced. In another tutorial, we will show how to control a 8-digit seven-segment display module with LinkIt 7697, by using a dedicated seven-segment display driving IC MAX7219.

Last updated