Interfacing 74HC595 Serial Shift Register with PIC Microcontroller

Published  June 18, 2018   5
Interfacing 74HC595 Serial Shift Register with PIC Microcontroller

There are possibilities in embedded design where you do not have enough I/O pins available in your microcontroller. That can be due to any reason, may be your application needs multiple LEDs or you want to use multiple 7-segment displays, but you don’t have required I/O pins in your microcontroller. Here comes a perfect component, shift register. Shift register accepts serial data and give parallel output. It’s requires only 3 pins to connect with your microcontroller and you will get more than 8 Output pins from it. One of the popular shift register is 74HC595. It has 8 bit storage register and 8 bit shift register. Learn more about shift registers here.

You will provide serial data to the shift register and it will be latched on the storage register and then the storage register will control the 8 outputs. If you want more output just add another shift register. By cascading two shift registers, you will get additional 8 outputs, total 16bit output.

 

Shift Register 74HC595:

Here is the pin out diagram of the 74HC595 as per the datasheet-

74HC595 Serial Shift Register IC Pinout

 

HC595 has 16pins; if we see the datasheet we will understand the pin functions-

74HC595 IC Pin descriptions

 

The QA to QH, from pin numbers 1 to 7 and 15 used as 8 bit output from the shift register, where as the pin 14 is used for receiving the serial data. There is also truth table about how to use other pins and avail other functions of the shift register.

74HC595 IC Truth Table

 

When we write the code for interfacing the 74HC595, we will apply this truth table for getting the desired outputs.

Now, we will interface 74HC595 with PIC16F877A and control 8 LEDs. We have interfaced 74HC595 shift register with other microcontrollers:

 

Components Required:

  1. PIC16F877A
  2. 2pcs 33pF ceramic disc capacitors
  3. 20Mhz Crystal
  4. 4.7k resistor
  5. 8pcs LEDs
  6. 1k resistor -1 pc (8 pcs 1k resistors required if separate resistors on each leds needed)
  7. 74HC595 ic
  8. 5V wall adapter
  9. PIC programming environment
  10. Breadboard and wires

 

Circuit Diagram:

Circuit diagram for Interfacing 74HC595 Serial Shift Register with PIC Microcontroller

 

In circuit diagram, we have connected the serial data pin; clock and strobe (latch) pin on microcontroller’s RB0, RB1 and RB2 pin respectively. Here we have used one resistor for 8 LEDs. As per the truth table, we enabled output by connecting the pin 13 of 74HC595 to ground. The QH pin is left open as we will not cascade another 74HC595 with it. We disabled the clear input flag by connecting pin 10 of the shift register with VCC.

The Crystal oscillator is connected on the OSC pins of the microcontroller. PIC16F877A do not have any internal oscillator. In this project we will light up the led one by one from Q0 to Q7 using shift regitster.

We have constructed the circuit in a breadboard-

Circuit Hardware for Interfacing 74HC595 Serial Shift Register with PIC Microcontroller

 

Code Explanation:

Complete code for controlling LEDs with shift register is given at the end of article. As always, we need to set the configuration bits in the PIC microcontroller.

#pragma config FOSC = HS        // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = ON       // Brown-out Reset Enable bit (BOR enabled)
#pragma config LVP = OFF         // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3/PGM pin has PGM function; low-voltage programming enabled)
#pragma config CPD = OFF        // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF        // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)

 

After that we declared the crystal frequency which is required for the delay and the pin-out declaration for 74HC595.

#include <xc.h>
/*
 Hardware related definition
 */
#define _XTAL_FREQ 20000000 //Crystal Frequency, used in delay
#define DATA_595 PORTBbits.RB0
#define STROBE_595 PORTBbits.RB1
#define CLK_595 PORTBbits.RB2

 

Next we declared system_init() function to initialize the pin direction.

void system_init(void){
    TRISB = 0x00;   
    }

 

We created the clock pulse and latch pulse using two different functions

/*
 *This function will enable the Clock.
 */
void clock(void){
    CLK_595 = 1;
    __delay_us(500);
    CLK_595 = 0;
    __delay_us(500);
}

and

/*
 *This function will strobe and enable the output trigger.
 */

void strobe(void){
    STROBE_595 = 1;
    __delay_us(500);
    STROBE_595 = 0;
    } 

 

After this two functions we declared the data_submit(unsigned int data) function to submit serial data to the 74HC595.

void data_submit(unsigned int data){
    for (int i=0 ; i<8 ; i++){
        DATA_595 = (data >> i) & 0x01;
        clock();
    }
    strobe(); // Data finally submitted 
}

 

In this function we accept 8bit data and send each bit using two bitwise operators left shift and AND operator. We first shift the data one by one and find out the exact bit whether it is 0 or 1 using AND operator with 0x01. Each data is stored by the clock pulse and final data output done using the latch or strobe pulse. In this process the data output will be MSB (Most Significant Bit) first.

 

In the main function we submitted the binary and made the output pins high one by one.

    system_init(); // System getting ready    
    while(1){
        data_submit(0b00000000);
        __delay_ms(200);
        data_submit(0b10000000);
        __delay_ms(200);
        data_submit(0b01000000);
        __delay_ms(200);
        data_submit(0b00100000);
        __delay_ms(200);
        data_submit(0b00010000);
        __delay_ms(200);
        data_submit(0b00001000);
        __delay_ms(200);        
        data_submit(0b00000100);
        __delay_ms(200);
        data_submit(0b00000010);
        __delay_ms(200);
        data_submit(0b00000001);
        __delay_ms(200);
        data_submit(0xFF);        
        __delay_ms(200);
     }
    return;
    }

 

That is how a shift register can be used to get more free I/O pins in any microcontroller for connecting more sensors.

Code

/*
 * File:   main.c
 * Author: Sourav Gupta
 * By:- circuitdigest.com
 * Created on May 30, 2018, 2:26 PM
 */

// PIC16F877A Configuration Bit Settings

// 'C' source line config statements

// CONFIG
#pragma config FOSC = HS        // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = ON       // Brown-out Reset Enable bit (BOR enabled)
#pragma config LVP = OFF         // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3/PGM pin has PGM function; low-voltage programming enabled)
#pragma config CPD = OFF        // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF        // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)

 

#include <xc.h>
/*
 Hardware related definition
 */
#define _XTAL_FREQ 20000000 //Crystal Frequency, used in delay
#define DATA_595 PORTBbits.RB0
#define STROBE_595 PORTBbits.RB1
#define CLK_595 PORTBbits.RB2
#define LED PORTBbits.RB3

/*
 Other Specific definition
 */
void system_init(void);

/*
 *This function will enable the Clock.
 */
void clock(void){
    CLK_595 = 1;
    __delay_us(500);
    CLK_595 = 0;
    __delay_us(500);
}

/*
 *This function will strobe and enable the output trigger.
 */

void strobe(void){
    STROBE_595 = 1;
    __delay_us(500);
    STROBE_595 = 0;
    }

/*
 * This function will send the data to shift register
 */
void data_submit(unsigned int data){
    for (int i=0 ; i<8 ; i++){
        DATA_595 = (data >> i) & 0x01;
        clock();
    }
    strobe(); // Data finally submitted 
}

void main(void) {
    system_init(); // System getting ready    
    while(1){
        data_submit(0b00000000);
        __delay_ms(200);
        data_submit(0b10000000);
        __delay_ms(200);
        data_submit(0b01000000);
        __delay_ms(200);
        data_submit(0b00100000);
        __delay_ms(200);
        data_submit(0b00010000);
        __delay_ms(200);
        data_submit(0b00001000);
        __delay_ms(200);        
        data_submit(0b00000100);
        __delay_ms(200);
        data_submit(0b00000010);
        __delay_ms(200);
        data_submit(0b00000001);
        __delay_ms(200);
        data_submit(0xFF);        
        __delay_ms(200);
     }
    return;
    }
    
/*
 This Function is for system initialisations.
 */

void system_init(void){
    TRISB = 0x00;   
    }

Video

Have any question realated to this Article?

Ask Our Community Members

Comments

Submitted by Laci on Mon, 06/18/2018 - 20:33

Permalink

Hi!
I made almost the same today but with CD4094 and a little bit different parsing. I have to use MSB first method to display ok.
You first shift left with 0 so the first 'anding' and sending is the LSB. Maybe I didn't get it right. Can you explain it?

Submitted by Anne Kleijheeg on Sat, 08/04/2018 - 19:41

Permalink

This code is working fine if I use one shift register.
I thought it would be easy to change the code when I want to use multiple shift register.
Can you give a clue how to use multiple registers.