3 wires interface for LCD display

This post is based on the work made previously by tomek in wiring LCD displays using 4 bits. The basic idea is to group the 7 pins that are needed to drive the LCD in only 3 using a shift register. This is a cheap alternative to serial LCDs.


Figure 1: schematic by Philip Warner

The schematic shows that wiring the LCD is a simple operation. It has been drawn in a way that makes it possible to develop this as part of a single sided PCB including a variable resistor to control the LCD's contrast. Note that the pin-out of the LCD module may differ slightly from the pin-out depicted; some LCD modules have pins 15 and 16 on the left side, before pin 1.


Figure 2: wiring the components

In this picture we see the actual connections on a breadboard. Everything runs on the power from the USB powered board.

NewLiquidCrystal Code

As part of the Arduino Miniconf at linux.conf.au 2012, freetronics released the pebble v2 with identical Shift Register wiring than this page, and Attendee Marc MERLIN wrote a NewLiquidCrystal driver for this hardware: http://marc.merlins.org/perso/arduino/post_2012-01-23_LiquidCrystal-driver-support-LCD3Wire-hardware-_pebble-and-others_.html

This driver should work for all LCD3Wires based hardware, and was based on the excellent work from Francisco Malpartida who modified the original LiquidCrystal library to provide support for different hardware drivers. His work is available here: https://bitbucket.org/fmalpartida/new-liquidcrystal/wiki/Home . This is the work Marc based his driver on to provide full LiquidCrystal support to LCD3Wires hardware by writing LiquidCrystal_SR_LCD3.cpp.


Figure 3: Pebble v2 with 20x4 LCD via shift register driven via LiquidCrystal_SR_LCD3

Original (obsolete) code

Below is the original code originally written to talk to this hardware setup. It does not work out of the box with arduino 1.0, and the library is much less featureful than LiquidCrystal. It is left here for historical purposes.

The code below includes a couple of functions that will print integer numbers to the LCD, as well as single characters.

Also available is a library: Attach:LCD3WireLibrary.zip. To remain command-compatible with the LCD4BitLibrary, this library does not contain the number-formatting code which is included in the code below.

An updated version of the library (Attach:LCD3WireLibrary.0.2.zip) inherits from the Print class, giving an improved print() function.

Note: these libraries aren't compatible with IDE 1.0 - you will get compiling errors.

To get the original version working on IDE 1.0 you have to copy/paste WConstants.h and wiring.h from IDE 0023 into arduino-1.0\hardware\arduino\cores\arduino

To get the 0.2 version working on IDE 1.0 do the same thing as above and then make the following changes in the LCD3WireLibrary.h and LCD3WireLibrary.cpp files:

In the header file change "virtual void write(uint8_t);" to "virtual size_t write(uint8_t);"

In the C++ file change "void LCD3Wire::write(uint8_t value)" to "inline size_t LCD3Wire::write(uint8_t value)"

/* LCD display with 3 wires
 * ------------------------
 *
 * based on previous examples by Tomek. 
 * This program will use shiftout to send 
 * data to a shift register with strobe that 
 * will transfer the serial into parallel data
 *
 * the pin-out for LCD displays is standard and there is plenty
 * of documentation to be found on the internet.
 *
 * (cleft) 2007 Dojodave for K3 and SADI
 * http://www.arduino.cc
 *
 */

// pins to be used on Arduino
int led = 13;
int count = 0;
int Dout = 11;
int STR = 12;
int CLK = 10;

// the Qx in the order they are connected on the chip
int DI = 1;
int RW = 2;
int Enable = 3;
int DB[] = {
  7, 6, 5, 4};

void LcdInit() {
  delay(100);
  // initialize LCD after a short pause
  // needed by the LCD's controller

  /////////// 4 pin initialization
  LcdCommandWrite(0x03); // function set:
  // 4 pin initialization
  delay(64);
  LcdCommandWrite(0x03); // function set:
  // 4 pin initialization
  delay(50);
  LcdCommandWrite(0x03); // function set:
  // 4 pin initialization
  delay(50);
  LcdCommandWrite(0x02); // function set:
  // 4 pin initialization
  delay(50);
  LcdCommandWrite(0x2C); // function set:
  // 4-bit interface, 1 display lines, 5x7 font
  /////////// end of 4 pin initialization 

  delay(20);
  LcdCommandWrite(0x06); // entry mode set:
  // increment automatically, no display shift
  delay(20);
  LcdCommandWrite(0x0E); // display control:
  // turn display on, cursor on, no blinking
  delay(20);
  // clear display, set cursor position to zero
  LcdCommandWrite(0x01); 
  delay(100);

  LcdCommandWrite(0x80); // display control:
  delay(20);
}

void sendByteOut(int value) {
  shiftOut(Dout, CLK, LSBFIRST, value);
  digitalWrite(STR, HIGH);
  delayMicroseconds(10);
  digitalWrite(STR,LOW);
}

void LcdCommandWrite(int value) {
  int i = 0;
  int value1 = 0;
  int control = 0; // stores DI and RW
  digitalWrite(STR,LOW); // set the strobe LOW
  control = value >> 8; // get the control signals DI and RW
  control <<= 5; // shift the control signals to the left
  value1 = value;
  value1 >>= 4; //send the first 4 databits (from 8) 
  value1 |= control; // set the control values
  value1 &= 239; // set Enable LOW
  sendByteOut(value1);
  value1 |= 16; // Set Enable HIGH
  sendByteOut(value1);
  value1 &= 239; // set Enable LOW
  sendByteOut(value1);

  delay(1);

  value &= 15; // set HByte to zero 
  value |= control; // set the control values
  value &= 239; // set Enable LOW
  sendByteOut(value);
  value |= 16; // Set Enable HIGH
  sendByteOut(value);
  value &= 239; // set Enable LOW
  sendByteOut(value);
}

void LcdDataWrite(int value) {
  int i = 0;
  int value1 = 0;
  digitalWrite(STR,LOW); // set the strobe LOW
  value1 =value;
  value1 >>= 4; //send the first 4 databits (from 8) 
  value1 |= 64; // set DI HIGH
  value1 &= 223; // set RW LOW
  value1 &= 239; // set Enable LOW
  sendByteOut(value1);
  value1 |= 16; // Set Enable HIGH
  sendByteOut(value1);
  value1 &= 239; // set Enable LOW
  sendByteOut(value1);

  delay(1);

  value &= 15; // set HByte to zero 
  value |= 64; // set DI HIGH
  value &= 223; // set RW LOW
  value &= 239; // set Enable LOW
  sendByteOut(value);
  value |= 16; // Set Enable HIGH
  sendByteOut(value);
  value &= 239; // set Enable LOW
  sendByteOut(value);
}

// efficient way of multiplying numbers by themselves
int pow(int base, int expo) {
  int temp = 1;
  for (int c = 1; c <= expo; c++) {
    temp *= base;
  }
  return temp;
}

// checks out how many digits there are in a number
int estimateDigits(int nr) {
  int dec = 10;
  int temp = 1;
  int div = nr/dec;
  while (div > 0) {
    dec *= 10;
    div = nr/dec;
    temp++;
  }
  return temp;
}

// shows numbers on the display
void LcdNumberWrite(int nr) {
  int digits = estimateDigits(nr);
  LcdNumberWrite(nr, digits);
}

// this function help us to write numbers 
// with more than one digit
void LcdNumberWrite(int nr, int digits) {
  for (int i = digits-1; i >= 0; i--) {
    int dec = pow(10,i);
    int div = nr/dec;
    LcdDataWrite(div+48); 
    if (div > 0) {
      nr -= div*dec; 
    }
  }
}

void setup (void) {
  int i = 0;
  for (i=CLK; i <= STR; i++) {
    pinMode(i,OUTPUT);
  }
  LcdInit();
  LcdCommandWrite(0x0F); //  cursor blink
  delay(10);
}

void loop (void) {
  LcdCommandWrite(0x02); // set cursor position to zero
  delay(10);

  // Write the message
  //like this
  LcdDataWrite('L');
  LcdDataWrite('c');
  LcdDataWrite('d');

  //or like this
  int wrote[] = {
    'D', 'i', 's', 'p', 'l', 'a', 'y', ' '  };
  for ( count = 0; count<=7; count++) {
    LcdDataWrite(wrote[count]);
  } 

  LcdDataWrite('w');
  LcdDataWrite('i');
  LcdDataWrite('t');
  LcdDataWrite('h');
  LcdDataWrite(' ');

  // and Numbers over 9 easily like this
  LcdNumberWrite(3);
  LcdDataWrite(' ');

  LcdDataWrite('P');
  LcdDataWrite('i');
  LcdDataWrite('n');
  LcdDataWrite('s');

  delay(3000);
}


TODO

  • migrate all the commands to a library format --> 20080310 library by Aldo Hoeben
  • redo the schematics and pictures --> 20080310 new schematic by Philip Warner

HISTORY

  • 2012/01/26: new support library based on NewLiquidCrystal by Marc MERLIN
  • 2011/06/21: new library version with improved print() function --> by Paul Cunnane
  • old schematic LCD3wiresSchematic.jpg

For more information write to: d.cuartielles [at] arduino.cc

Share