LCD display with 74164

Interfacing Arduino 74164 Serial Shift Register Driving LCD Display

by Lewis Loflin

Here we will explore how to connect Arduino to a 2 line by 16 character LCD display. The electrical connections are shown above. I have avoided user supplied libraries because changes in the Arduino compiler means some of them don't work. The other point being how to write one's own code and get a better understanding of the electronics and how a micro-controller really operate. This will enable the student or hobbyist to connect other similar devices or learn how to connect new devices.

The code will allow one to display characters, strings, integers, and floats on the LCD display. Some of the code was borrowed from the following projects minus the GPIO expander and the use of a 74164 code for Arduino.

Download the complete code for this demo: arduino4a.txt.

About the 74164 Shift register and the LCD Display

Demo to shift byte into 74HC164 to operate LCD display. In the case of the Hd44780 type display Q1-Q7 of the 74164 connects to D0-D7 LCD.

The 74HC164 has three inputs:

  • Input A-B (pins 1, 2) is for data. they can be tied together or the one not used tied to +Vcc
  • Clock pin 8 data is serially shifted in and out of the 8-bit register during the positive going transition of clock pulse.
  • Clear (pin 9) is independent of the clock and accomplished by a low level at the clear input. Can connect to Vcc.

As far as LSB first or MSB bit first is up to software and electrical connections on the output. LCD pin 6 (E), HIGH to LOW transition will clock info into display. Select command or data with RS. RS set to 0 is command, 1 is data. R/W goes to ground. LCD command codes are shown below.

#define Bit_out 12 // Pin 1-2 Sn74164
#define CLK 11 // Pin 9 Sn74164
#define RS 7  // Pin 4 LCD
#define E 8  // Pin 6 LCD

#define Line1 0x80  // location LCD row 0 col 0 or line 1 LCD
#define Line2 0x80 + 0x40  // location row 1 col 0 or line 2 LCD

void setup() {
  pinMode(Bit_out, OUTPUT);
  pinMode(CLK, OUTPUT);
  pinMode(RS, OUTPUT);
  pinMode(E, OUTPUT);

  digitalWrite(CLK, LOW); 
  digitalWrite(RS, LOW); // LCD in command mode default
  digitalWrite(E, HIGH);

  initLCD(); // see below


void loop() {
  // below simply prints "Hello World!" on line 1
  //  char String1[] = "Hello world!\n";
  //  typeln(String1, Line1);

  int val = analogRead(0); // get value from 0-1023 from pot
  char myString2[] = "Pot VAL =";
  int index = sizeof(myString2);
  typeln(myString2, Line1);
  typeInt(val, Line1 + index); 

  // change a float to ASCII
  // dtostrf(floatVar, X, Y, charBuf);
  // X is min String Width Inc Decimal Point
  // Y is num Vars After Decimal point
  float myFloat  = 3.1415926;
  char myBuffer[16];
  dtostrf(myFloat, 5, 4, myBuffer);
  typeln("PI = ", Line2);
  typeln(myBuffer, Line2 + 5);


} // end loop

// location is place on LCD display. 
void typeInt(int k, int location)   {
  char array1[10];
  itoa(k, array1, 10); // int to string
  typeln(array1, location);

void typeChar(byte val)   {
  digitalWrite(RS, HIGH);
  digitalWrite(RS, LOW);

void writeCommand(byte val)   {

  ssrWrite(val); // send byte to 74164
  digitalWrite(RS, LOW); // make sure RS in Com mode

// Below we pass a pointer to array1[0].
void typeln(char *s, int location)   {
  writeCommand(location); // where to begin 
  while (*s)  typeChar(*(s++));
}  // end typeln

// inverts state of pin, delays, then reverts state back
void    pulseOut(byte x)   {
  byte z = digitalRead(x);
  z = !z; // reverse state
  digitalWrite(x, z);
  z = !z; // return to original state
  digitalWrite(x, z);
} // end pulsout()

To shift LSB out first:
 byte  temp = val & B00000001; 
 if (temp == 0x01) digitalWrite(Bit_out, HIGH); 
 else digitalWrite(Bit_out, LOW); 
 val = val >> 1; // shift one place right

void ssrWrite(byte val)  {  // shift data to 74164
  for (int j=1; j<=8; j++)  {   // shift out MSB first
    byte  temp = val & B10000000; // MSB out first
    if (temp == 0x80) digitalWrite(Bit_out, HIGH); 
    else digitalWrite(Bit_out, LOW); 
    val = val << 1; // shift one place left
  }  // next j
}  // end byteWrite

Hd44780 display commands:
 0x0f = initiate display cursor on blinking
 0x0c = initiate display cursor off
 0x01 = clear display fills display with spaces (0x20).
 0x02 = HOME returns to line one first character
 0x38 = 2 lines X 16 char 8 bits mode. Defaults to 1 line mode.
 0x10 = cursor left
 0x14 = cursor right
 0x18 = Shifts entire display left
 0x1c = Shifts entire display right 
 One can also go to a specific location.
 writeCommand(0x80); // begin on 1st line
 writeCommand(0x80 + 0x40); // begin on 2nd line 
 writeCommand(0x38); // setup for 2 lines
 writeCommand(0x0F); // blinking cursor
 writeCommand(0x02); // home
 writeCommand(0x01); // clear

void initLCD(void)   {

  writeCommand(0x38); // setup for 2 lines
  writeCommand(0x0F); // blinking cursor
  writeCommand(0x01); // clear
  writeCommand(0x02); // home

void ClearDisplay(void)   {
  writeCommand(0x01); // clear
  writeCommand(0x02); // home

Added June 7, 2013:

You Tube Arduino Microcontroller Video Series March 2012: