Shift register (output)

The 74HC595: an 8-bit serial-in/serial or parallel-out shift register with a storage register and 3-state outputs.

If higher load is required there is also the TPIC6C595 (e.g., for driving LEDs), or it should be paired with for example ULN2803 or similar. For multiple inputs see the 74HC165.

Figure 1: Pin-out 74HC595.

The basic usage is to serially transfer a byte from a microcontroller to the IC. When latched the byte will then in parallel be available on output pins QA-QH (Q0-Q7).

Hereby we can increase the number of available pins from 3 (data pin, clock, latch pins) to 8. Since the IC can be daisy-chained we can even increase the number of output pins.

Wiring is simple:

  • Pin 16 (VCC): Voltage 5V
  • Pin 14 (SER): Data input
  • Pin 13 (OE): GND (Output-enable, active low)
  • Pin 12 (STCLK): Store clock/latch pin
  • Pin 11 (SHCLK): Shift clock pin
  • Pin 10 (SRCLR): 5V (master reset)
  • Pin 15,1,…7: Output pims
  • Pin 8 (GND): GND

When the SHCLK goes high register is shifted and first bit will be set to value of SER. When STCLK (Latch) is pulled high the output pins QA-QH will be updated.

A simple AVR-C example (here for attiny13)

#include <util/delay.h>
#include <avr/io.h>

#define DATA_PORT		PORTB
#define DATA_DDR		DDRB

#define DATA    PB0      // Data pin (DS) pin location
#define CLOCK   PB2      // Shift Clock (SH_CP) pin location
#define LATCH   PB1      // Store Clock (ST_CP) pin location

#define HC595DataHigh() (DATA_PORT|=(1<<DATA))
#define HC595DataLow()  (DATA_PORT&=(~(1<<DATA)))
void HC595Pulse() { // Pulse the Shift Clock
  DATA_PORT|=(1<<CLOCK);    // HIGH
  DATA_PORT&=(~(1<<CLOCK)); // LOW
}
void HC595Latch() { // Pulse the Store Clock
  DATA_PORT|=(1<<LATCH);    // HIGH
  _delay_ms(1);
  DATA_PORT&=(~(1<<LATCH)); // LOW
  _delay_ms(1);
}

void HC595Write(uint8_t data) {
  //Send each 8 bits serially
  //Order is MSB first
  for(uint8_t i=0;i<8;i++) {
    //Output the data on DS line according to the Value of MSB
    if(data & 0b10000000) {
      HC595DataHigh(); //MSB is 1 so output high
    } else {
      HC595DataLow(); //MSB is 0 so output high
    }
    HC595Pulse();  //Pulse the Clock line
    data=data<<1;  //Now bring next bit at MSB position
  }
  //Now all 8 bits have been transferred to shift register
  //Move them to output latch at one
  HC595Latch();
}
void HC595Init() { // Initialize HC595
  // Make the Data(DS), Shift clock (SH_CP), Store Clock (ST_CP) lines output
  DATA_DDR|=((1<<DATA)|(1<<CLOCK)|(1<<LATCH));
}

uint8_t led_pattern[8]={0b10000001,
		      0b11000011,
		      0b11100111,
		      0b11111111,
		      0b01111110,
		      0b00111100,
		      0b00011000,
		      0b00000000};

int main(void) {
  HC595Init();
  HC595Write(0b00000000);
  _delay_ms(100);

  while (1) {
    for (unsigned i=0; i<8; i++) {
      HC595Write(led_pattern[8-i]);
      _delay_ms(100);
    }
    for (unsigned i=0; i<8; i++) {
    HC595Write(led_pattern[i]);
    _delay_ms(100);
    }
  }
}

Arduino example with

  • Pin 14 (SER) attached to D2
  • Pin 12 (STCLK) attached to D3
  • Pin 11 (SHCLK) attached to D4

Here two shift registers are daisy-chained by wiring pin 9 (QH’) of the first register to the SER/DATA pin of the second register. All other pins should be wired identically.

// Mux (output:74HC495, input:74HC165)
// Author: Klaus Holst, 2019

const unsigned dataPin = 2;  // Data pin (DS/SER) of 74HC595
const unsigned latchPin = 3; // Store clock (ST_CP/RCLK)   of 74HC595
const unsigned clockPin = 4; // Shift-clock (SH_CP/SRCLK) of 74HC595

void setup() {
  // Serial.begin(115200);
  // Serial.println("Log start:\n");
  pinMode(LED_BUILTIN,  OUTPUT);
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
}

// Send 1 to the first shift register, and numbers from 0 to 64 to the second.
void send() {
  for (unsigned i=0; i<64; i++) {
    digitalWrite(latchPin, LOW); // ground latchPin and hold low for as long as you are transmitting
    // shiftOut(dataPin, clockPin, bitOrder, value)
    // bitOrder: MSBFIRST or LSBFIRST. (Most Significant Bit First, or, Least Significant Bit First).
    // value: type byte
    shiftOut(dataPin, clockPin, MSBFIRST, i); // Input B, 8bits
    shiftOut(dataPin, clockPin, MSBFIRST, 1); // Input A, 8bits
    delay(100);
    digitalWrite(latchPin, HIGH); //return the latch pin high to signal chip that it no longer needs to listen for information
  }
}

void loop() {
  send();
}