7 Segment LED Displays 102 -- Using a Shift Register

7 Segment LED Displays 102 -- Using a Shift Register © GPL3+

Driving a Single Digit 7 Segment LED Display requires 8 of an Arduino's 20 or so I/O pins. Using a 74HC595 shift register only requires 3.

  • 1 comment
  • 28 respects

Components and supplies

Ard nano
Arduino Nano R3
74HC595 Shift Register
Adafruit industries ada239 image 75px
Solderless Breadboard Full Size
11026 02
Jumper wires (generic)
Single Digit 7 Segment LED Display
Any Single Digit 7 Segment LED Display should work
08377 02 l
Resistor 330 ohm

Apps and online services

About this project


This tutorial assumes you are somewhat familiar with 7 Segment LED Displays and builds upon the 7 Segment LED Displays 101 -- How to Make One Work tutorial. To complete this tutorial, you will need the pinout for the 7 Segment LED Display you are using. If you do not have this information, please see the previous tutorial.

Adding one or more shift registers to your project will conserve the number of Arduino compatible I/O pins required to drive your 7 Segment LED Displays and can significantly reduce the power needed for multiple digit displays.

Project Construction

Place one breadboard above the other as shown in the Frizing diagram below. Some breadboards have matching slots and tabs that can be used to lock them together, but this is not essential.

Arduino Uno or Nano Development Board

A 5VDC Arduino Uno or Nano with the ATMega328 microprocessor can safely power this project, driving the 74HC595 Shift Register and Toplite 5161BS 7 Segment LED Display used to develop this tutorial. Any other Single Digit 7 Segment LED Display should be safe to use as long as total current does not exceed 200mA. Leave the development board powered off during project construction.

Connect the 5V pin of the development board to the top power rail of the upper breadboard. Then connect a jumper from that power rail to the bottom power rail of the lower breadboard. Wires connected to the power rails are shown in red. Now connect grounds from the development board to to top and bottom ground rails of the upper breadboard. Wires connected to the ground rails are black.

74HC595 Shift Register

The 74HC595 Shift Register is an integrated circuit (IC) component with a definite notch or dimple at one end. Place the 74HC595 on the upper breadboard with the notch to your left so that the two rows of pins are connected to the breadboard on opposite sides of the center horizontal divide. Any printing on the top of the 74HC595 should appear upright when the IC has been plugged into the breadboard as shown in the above Fritzing diagram.

IC pins are commonly numbered counterclockwise starting with pin 1, which is located to the left or below the dot or notch at one end. The 74HC595 follows this convention. Connect jumpers (shown in red) from the top power rail of the upper breadboard to pins 10 (MR) and 16 (Vcc) of the 74HC595. Pin 16 supplies 5VDC power to the Shift Register and holding Pin 10 (MR) HIGH with 5V prevents the register from clearing.

Connect jumpers (shown in black) from pins 8 (GND) and 13 (OE) to the bottom and top ground rails respectively of the upper breadboard. Pin 8 is the 74HC595 Ground pin and by grounding pin 13, it is held LOW to enable output from the Shift Register.

We will be using pins 4, 7 and 8 on an Arduino compatible Uno or Nano microprocessor development board, although any of the other available I/O pins could be used, if you prefer. The reason I use pins 4, 7 and 8 for shift registers is that these pins don't have any properties other than Digital I/O, so by selecting them, I can reserve the more versatile pins for other uses like interrupts, PWM or various serial and buss communication protocols.

Connect the Arduino compatible development board to the 74HC595 as follows:

  • Arduino pin 4 to 74HC595 pin 14 (DS) Serial Data input with a blue wire
  • Arduino pin 7 to 74HC595 pin 12 (ST_CP) Latch pin with a green wire
  • Arduino pin 8 to 74HC595 pin 11 ( SH_CP) Clock pin with a yellow wire

7 Segment LED Display (single digit)

The particular display used in this tutorial is a TopLite 5161BS with a Common Anode. In order to make this tutorial as general as possible, I will refer to the Display pins by their individual segments (A-G and Dp). Some displays are pinned out the same as the 5161BS, but many are not and others may be of the Common Cathode variety. Do not literally follow the Fritzing project diagram when connecting your display to the 74HC595 shift register. If you are not sure what display pins go to which segments, now would be a good time to review my previous tutorial.

After you have mapped your displays pins to the above segment map, make the following connections:

  • 74HC595 pin 15 (Q0) to unused breadboard column next to 74HC595 pin 1 (orange wire)
  • From the jumper wire you just installed make a connection to the Display pin corresponding to Segment A using a 330 Ohm resistor. Any resistor value between 180 Ohm to 1,000 Ohm should work as the idea is to protect the Display Segment LED by restricting current.

Using 330 Ohm resistors and jumpers, connect the remaining Display Segments:

  • 74HC595 pin 1 (Q1) to resistor then jumper to Display pin for Segment B
  • 74HC595 pin 2(Q2) to resistor then jumper to Display pin for Segment C
  • 74HC595 pin 3(Q3) to resistor then jumper to Display pin for Segment D
  • 74HC595 pin 4(Q4) to resistor then jumper to Display pin for Segment E
  • 74HC595 pin 5(Q5) to resistor then jumper to Display pin for Segment F
  • 74HC595 pin 6(Q6) to resistor then jumper to Display pin for Segment G
  • 74HC595 pin 7(Q7) to resistor then jumper to Display pin for Segment Dp

The last step of the construction phase of this project is to connect a common pin on the Display to either the power or ground rail on the breadboard. If you have a Common Anode Display, use a red jumper to the power rail, otherwise connect a Common Cathode Display to the ground rail using a black jumper. Double check your work and leave the development board powered off.

Programming the Arduino IDE Sketch

The sketch is organized into four main sections; Global Declarations, Setup, and the main Loop followed by two User Defined Functions.

Global Declarations

  • Constant Integers are given the descriptive labels dataPin, latchPin and clockPin and assigned the values 4, 7 and 8 respectively. If you are using different pin assignments on your project development board, change the values accordingly.
  • A Constant Char (single character) labeled common, is given either the value 'a' for Common Anode Displays or 'c' for Common Cathode. As written, the Sketch is set up for Common Anode Displays. If your Display is of the Common Cathode type, comment out or delete the Common Anode declaration line and uncomment the Common Cathode line. In most cases, this will be the only change necessary for the Sketch to run correctly.
  • A Boolean Variable, decPt, is initialized as true. This variable is used to indicate if the Decimal Point Segment (Dp) is to be lit.


The Setup code block merely initializes the development project board pins associated with the constant values of dataPin, latchPin and clockPin for OUTPUT.


The Loop code block repeats endlessly until power is shut off or a project component fails or is disconnected.

Every time the Loop begins, the value of the Global variable, decPt, is either true or false. Whatever the value happens to be, it is changed from true to false or vice versa so that the Display's Decimal Point segment is only lit on every other pass through the Loop.

A for loop code block then runs 16 times, incrementing the value of the local integer variable, i, from 0 to 15. Each value of i, is passed to the User Defined Function, myfnNumToBits which returns the local byte value, bits, an eight bit representation of all the Display Segments needed to represent the Hexadecimal value of the variable i.

If decPt is true, the value of bits is modified by setting the Least Significant Bit (LSB) to 1 using the Bitwise OR operator.

The User Defined Function, myfnUpdateDisplay is called with the variable, bits, as an argument. When the Display has been updated by the myfnUpdateDisplay function, the program waits for 1/2 second before incrementing the value of i and repeating the for loop until the value of i is greater than 15; then the whole Loop code block starts over.

User Defined Function

myfnUpdateDisplay is called from the for loop within the Loop code block with a byte argument. Each of the 8 bits in the byte represents one of the Display segments from A to Dp.

For Common Cathode Displays, if a bit value is 1, the associated segment is to be lit, otherwise the bit is 0 and the segment is turned off. The bits need to be reversed for Common Anode displays, so all 8 bit values in the byte are flipped if the Global variable, common equals 'a', changing 1s to 0s and 0s to 1s using the BitWise XOR (^) operator with a B11111111 bit mask.

The Arduino compatible development board latchPin is set LOW before the bits are being sent into the 74HC595's registers. Then the shiftOut(dataPin, clockPin, LSBFIRST, byte) function is called to transfer the bits. Finally, latchPin is set HIGH and the Display should show the appropriate alphanumeric character.

Program control is then returned to the for loop inside the Loop code block.


This User Defined Function acts as a lookup table, accepting a number from 0 to 15 and returns a byte where the bits are a map for the hexadecimal alphanumeric character to be displayed. If an unexpected number is received, three vertical bars will be displayed. A more detailed explanation of myfnNumToBits can be found in the previous tutorial, 7 Segment LED Displays 101 -- How to Make one Work.

The Smoke Test

Check the project wiring one last time before powering up the Arduino compatible development board and uploading the Sketch from the Code section of this tutorial.


Simple example of using Shift Register with a Single Digit Seven Segment LED Display
/*  SevenSegmentLEDdisplay102a.ino
 *   2017-02-20
 *   Mel Lester Jr.
 *  Simple example of using Shift Register with a
 *  Single Digit Seven Segment LED Display
// Globals
const int dataPin = 4;  // blue wire to 74HC595 pin 14
const int latchPin = 7; // green to 74HC595 pin 12
const int clockPin = 8; // yellow to 74HC595 pin 11

/* uncomment one of the following lines that describes your display
 *  and comment out the line that does not describe your display */
const char common = 'a';    // common anode
//const char common = 'c';    // common cathode

bool decPt = true;  // decimal point display flag
void setup() {
  // initialize I/O pins
  pinMode(dataPin, OUTPUT);
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);

void loop() {
  decPt = !decPt; // display decimal point every other pass through loop

  // generate characters to display for hexidecimal numbers 0 to F
  for (int i = 0; i <= 15; i++) {
    byte bits = myfnNumToBits(i) ;
    if (decPt) {
      bits = bits | B00000001;  // add decimal point if needed
    myfnUpdateDisplay(bits);    // display alphanumeric digit
    delay(500);                 // pause for 1/2 second

void myfnUpdateDisplay(byte eightBits) {
  if (common == 'a') {                  // using a common anonde display?
    eightBits = eightBits ^ B11111111;  // then flip all bits using XOR 
  digitalWrite(latchPin, LOW);  // prepare shift register for data
  shiftOut(dataPin, clockPin, LSBFIRST, eightBits); // send data
  digitalWrite(latchPin, HIGH); // update display

byte myfnNumToBits(int someNumber) {
  switch (someNumber) {
    case 0:
      return B11111100;
    case 1:
      return B01100000;
    case 2:
      return B11011010;
    case 3:
      return B11110010;
    case 4:
      return B01100110;
    case 5:
      return B10110110;
    case 6:
      return B10111110;
    case 7:
      return B11100000;
    case 8:
      return B11111110;
    case 9:
      return B11110110;
    case 10:
      return B11101110; // Hexidecimal A
    case 11:
      return B00111110; // Hexidecimal B
    case 12:
      return B10011100; // Hexidecimal C or use for Centigrade
    case 13:
      return B01111010; // Hexidecimal D
    case 14:
      return B10011110; // Hexidecimal E
    case 15:
      return B10001110; // Hexidecimal F or use for Fahrenheit
      return B10010010; // Error condition, displays three vertical bars


Similar projects you might like

4 Wire LCD Control with BL and Contrast Using Shift Register

Project showcase by Mike Kowalski

  • 11 respects

74HC595 Shift Register Tutorial | Arduino with 7 segment

Project tutorial by Common9899 and Akarsh Agarwal

  • 5 respects

Shift Register Tutorial

Project tutorial by mdraber

  • 4 respects

Digital Clock with Arduino, RTC and Shift Register 74HC595

Project showcase by LAGSILVA

  • 98 respects

Bluetooth control led with lcd led status display real time.

Project tutorial by Youssef Sabaa

  • 59 respects

Displaying Sensor Values on LCD

by Wimpie van den Berg

  • 73 respects
Add projectSign up / Login