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.
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.
In this picture we see the actual connections on a breadboard. Everything runs on the power from the USB powered board.
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.
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 * https://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
HISTORY
For more information write to: d.cuartielles [at] arduino.cc