Sometimes, we need to add LCD with the project while the micro-controller itself has limited free pins for LCD. In that case, we can use shift registers to interface LCD with a micro-controller. After reading this article, you’ll be able to do that yourself. It’s easy! So let’s start Interfacing 16×2 LCD with 74HC595.

Disclaimer: Electricity is always dangerous. Proper skill is required to work with electricity. Do work at your own risk. The author will not be responsible for any misuse or harmful act or any mistake you make. The contents of this website are unique and copyright protected. Kindly don’t do any nonsensical act copying and claiming it as yours. Most of the articles published here are kept as open-source to help you. Take the knowledge for free and use it, but if you are interested you can buy the ready resources offered here. If you need any help or guide feel free to comment below, the author will try to help you. Thanks.

How to interface LCD?

LCD is very common in the electronics arena. Among lots of LCDs, the 16×2 one is the most common one. Technically, most of us know this type of LCD as HD44780 based LCD. Here HD44780 is the interface IC. But in common or people know it in an easy way as 16×2 LCD.

20X4 LCD
HD44780 based 16×2 LCD

Pin configuration:

LCD pinout
PIC configuration of HD44780 based LCD

As you see, we have 10 pins for the LCD interface in 8bit mode and 6 for 4bit mode. 8bit mode is not so used in common, 4bit mode is most used. So we need at least 6pins free to interface LCD with our micro-controller.

If the MCU has free pins, that’s fine. But if not then? Yes, then we can use Shift registers to extend some pins!

What is 74HC595 shift register?

In digital circuits, a shift register is a cascade of flip flops, sharing the same clock, in which the output of each flip-flop is connected to the “data” input of the next flip-flop in the chain, resulting in a circuit that shifts by one position the “bit array” stored in it, “shifting in” the data present at its input and ‘shifting out’ the last bit in the array, at each transition of the clock input. _Wiki.

To know more about shift registers, please visit the wiki page here.

You may find this project helpful: How to remove noise/garbage from the HD44780 LCD display

Shift registers are different in type. The most common ones are

  1. Serial in-parallel out
  2. Parallel in – Serial out

There are many types of shift registers, which can not be explained in short articles. Please do some research on this issue over the internet.

About 74HC595 Shift Register:

74HC595 is a serial into parallel-out with latch triggered tri-state shift register. This 16pin shift register is very common in use with a micro-controller as a port extender.

74hc595 shift register
74HC595 shift register
74hc595 shift register
DIP package

This SIPO shift register has a data input pin (A) where data can be loaded which is controlled by the shift clock. Then one latch clock shifts these data to its output pins according to the 8bit data pattern given serially at the data pin. Output Enable pin (!OE) is active low to enable output of that shift register. And the reset pin is also active low, connecting this reset pin to VDD will keep the operation going on. When we need more outputs, we just connect shift registers in cascade mode. For this, there is a data output (serial data out) pin. This pin will be then connected to the data input pin of the next shift register.

So how to connect Shift register with LCD?

Here is the solution. We can follow this circuit diagram for 4bit mode.

Interfacing 16x2 LCD with 74HC595
Circuit diagram

Here, shift register 74HC595 or 74LS595 can be used. Both are ok for this project.

MikroC Coding:

#include"_595_LCD.h"

unsigned char txt[]="mithun060@gmail_";

void main()
{
  TRISIO=0x00;
  GPIO=0x00;
  LCD_init();

  while(1)
  {
     LCD_clear_home();
     LCD_goto(1,1);
     LCD_putstr("HC595 LCD TEST"); //for direct string
     Delay_ms(3000);
     LCD_clear_home();
     LCD_goto(1, 1);
     LCD_putstr(txt); //for string from character array
     LCD_goto(2,1);
     LCD_putstr(".com");
     Delay_ms(3000);

  }
}

Here a header file is used to simplify the coding. This header file can be modified and implemented to other similar micro-controllers.

The header file:

#define clear_display                           0x01
#define goto_home                               0x02

#define cursor_direction_inc                    (0x04 | 0x02)
#define cursor_direction_dec                    (0x04 | 0x00)
#define display_shift                           (0x04 | 0x01)
#define display_no_shift                        (0x04 | 0x00)

#define display_on                              (0x08 | 0x04)
#define display_off                             (0x08 | 0x02)
#define cursor_on                               (0x08 | 0x02)
#define cursor_off                              (0x08 | 0x00)
#define blink_on                                (0x08 | 0x01)
#define blink_off                               (0x08 | 0x00)

#define _8_pin_interface                        (0x20 | 0x10)
#define _4_pin_interface                        (0x20 | 0x00)
#define _2_row_display                          (0x20 | 0x08)
#define _1_row_display                          (0x20 | 0x00)
#define _5x10_dots                              (0x20 | 0x40)
#define _5x7_dots                               (0x20 | 0x00)

#define dly                                     1

#define LCD_SDI   GP1_bit //pin declearations
#define LCD_SCK   GP0_bit
#define LCD_LCK   GP2_bit

#define LCD_SDI_Direction   TRISIO1_bit
#define LCD_SCK_Direction   TRISIO0_bit
#define LCD_LCK_Direction   TRISIO2_bit

unsigned char data_value;

void SIPO();
void LCD_init();
void LCD_command(unsigned char value);
void LCD_send_data(unsigned char value);
void LCD_4bit_send(unsigned char lcd_data);
void LCD_putstr(char *lcd_string);
void LCD_putchar(char char_data);
void LCD_clear_home();
void LCD_goto(unsigned char x_pos, unsigned char y_pos);


void SIPO()
{
    unsigned char clk = 8;
    unsigned char temp = 0;

    temp = data_value;
    LCD_LCK = 0;
    while(clk > 0)
    {
        LCD_SDI = ((temp & 0x80) >> 0x07);
        LCD_SCK = 1;
        temp <<= 1;
        LCD_SCK = 0;
        clk--;
    }
    LCD_LCK = 1;
}


void LCD_init()
{
    unsigned char t = 0x0A;
    data_value = 0x08;
    SIPO();
    while(t > 0x00)
    {
      Delay_ms(dly);
      t--;
    };

    data_value = 0x30;
    SIPO();

    data_value |= 0x08;
    SIPO();
    Delay_ms(dly);
    data_value &= 0xF7;
    SIPO();
    Delay_ms(dly);

    data_value = 0x30;
    SIPO();

    data_value |= 0x08;
    SIPO();
    Delay_ms(dly);
    data_value &= 0xF7;
    SIPO();
    Delay_ms(dly);

    data_value = 0x30;
    SIPO();

    data_value |= 0x08;
    SIPO();
    Delay_ms(dly);
    data_value &= 0xF7;
    SIPO();
    Delay_ms(dly);

    data_value = 0x20;
    SIPO();

    data_value |= 0x08;
    SIPO();
    Delay_ms(dly);
    data_value &= 0xF7;
    SIPO();
    Delay_ms(dly);

    LCD_command(_4_pin_interface | _2_row_display | _5x7_dots);
    LCD_command(display_on | cursor_off | blink_off);
    LCD_command(clear_display);
    LCD_command(cursor_direction_inc | display_no_shift);
}


void LCD_command(unsigned char value)
{
    data_value &= 0xFB;
    SIPO();
    LCD_4bit_send(value);
}


void LCD_send_data(unsigned char value)
{
    data_value |= 0x04;
    SIPO();
    LCD_4bit_send(value);
}


void LCD_4bit_send(unsigned char lcd_data)
{
    unsigned char temp = 0x00;

    temp = (lcd_data & 0xF0);
    data_value &= 0x0F;
    data_value |= temp;
    SIPO();

    data_value |= 0x08;
    SIPO();
    Delay_ms(dly);
    data_value &= 0xF7;
    SIPO();
    Delay_ms(dly);

    temp = (lcd_data & 0x0F);
    temp <<= 0x04;
    data_value &= 0x0F;
    data_value |= temp;
    SIPO();

    data_value |= 0x08;
    SIPO();
    Delay_ms(dly);
    data_value &= 0xF7;
    SIPO();
    Delay_ms(dly);
}


void LCD_putstr(char *lcd_string)
{
    while (*lcd_string != '\0')
    {
        LCD_send_data(*lcd_string);
        lcd_string++;
    };
}


void LCD_putchar(char char_data)
{
    LCD_send_data(char_data);
}


void LCD_clear_home()
{
    LCD_command(clear_display);
    LCD_command(goto_home);
}


void LCD_goto(unsigned char y_pos,unsigned char x_pos)
{

    if((y_pos-1) == 0)
    {
        LCD_command(0x80 | (x_pos-1));
    }
    else
    {
        LCD_command(0x80 | 0x40 | (x_pos-1));
    }
}

Simulation result:

Simulation on Proteus

Conclusion:

As you see, we have interfaced 16×2 LCD with PIC12F675 using the 74HC595 Shift register. This concept and the code can be used with any similar micro-controller. Using like this is also known as 3 wite LCD and very useful for many circuits where free pins are limited.

Loading

JLCPCB – Only $2 for PCB Prototype (Any Color)

24 Hours fast turnaround, Excellent quality & Unbeatable prices

$18 Welcome Bonus for new registrations Now!!! https://jlcpcb.com


Check this out: 5 coolest multimeters you can buy


MKDas

I'm Mithun from Bangladesh. Electronics is my passion, love to work with electronics. This is my personal blog. Besides my regular works, I write some articles here. Most of them are open-source and everything is presented in the easiest way so that anyone can understand and learn it. Thanks.

2 Comments

Joy · November 27, 2020 at 3:42 pm

Dear sir, Please make a video how to create mikro c pro Header file and add main program.

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *