Go Down

Topic: ShiftRegLCD lib (LiquidCrystal 3-wire replacement) (Read 8 times) previous topic - next topic


May 24, 2009, 10:09 pm Last Edit: May 25, 2009, 04:24 am by raron Reason: 1

I managed to put together a library for connecting a LCD with 3 wires from an Arduino. It is basically the same as the LiquidCrystal library, which it is pretty much based on (almost verbatim  :P )  It's just tweaked to work with a shift register. I used 74LS164, since that's what I had. It's not a fancy shiftregister (no tristate nor latching etc.), so I kept the Enable-pin on the Arduino. Thus using three pins from the Arduino. Basically any shiftregister should do.

I'm pretty new to the Arduino, but I have dabbled a little in both electronics and C++ before. But not much, this is the first class or library I've written for C++. Or very C++ like language.

The Morse-tutorial was great, as well as looking into the LiquidCrystal library. It's still a couple of things that seems strange to me in that one, but I finally got the inheritance - I think. The this->write(b); isn't too intuitive. But I think I get it, "this" points to the library who inherits the print-library, and so the write()-function that is used is from that library (LiquidCrystal::write(), for instance). The write() function needs to be declared "virtual" in the header file for this to work.
And there is a strange way of assigning the class instance's global variables in the constructor, the _enable_pin(enable) before the curly parenthesis (I didn't get it to work like that in my version, but I followed the Morse tutorial for that instead).

Since I had an old HD44780 LCD display, I wanted to connect it to the Arduino. Like most of us it seems, so this might be a bit like reinventing the wheel for the n'th time. But I hope this might be useful for some anyway. Plus I learned a bit about classes and libraries in C++  :)

A bit crude, as there is no reading of the busy flag from the LCD. I am however playing with the idea of implementing that while still using the same three connections from the Arduino. That will require some more external circuitry however, and I'm not sure when I will start tinkering with that, so for now I thought I'd share this one.

It does seem a bit sensible to how it starts. For instance, it usually starts well after uploading a sketch, but by pressing the reset-button on the Arduino, it seems to be neccessary to hold the reset-button down for about a second or so. Strange, and not always reliable.

It seems some have 4-line LCD-displays with (I think) common data pins (D0 - D7), and two enable-pins. There should be no problem making two instances of ShiftRegLCD objects with the same data and clock-pins, but with different enable pins, thus using 4 pins on the Arduino.

Btw, the official library starts the LCD in 2-line mode (stating erroneously it is 1 line in the comments, but no biggie). It works nice for my 1 line 32 character LCD, so I kept it that way.

As I had to use one bit for the RS signal, and didn't have any 9-bit shiftregisters handy, I use the LCD's in 4-bit mode. Seems fast enough for most purposes, but wastes 3 outputs on the shiftregister (for now). RW on the LCD is grounded, only writing-to is supported in this.

Of course if anyone wants to improve or alter upon this they are welcome to. After all, the official library is licenced under a Creative Commons Attribution-ShareAlike 3.0 License. I couldn't find that particular license on google code pages, so I used GNU GPLv3, and hope that is similar enough.

Project homepage: http://code.google.com/p/arduinoshiftreglcd/

If anyone wants to know, this is how I connected my LCD. (I know I should probably used a potmeter for the contrast setting, V5 on the LCD. But it works). Of course it doesn't matter which pins from the Arduino one use. I used pins 8, 12 and 13 here. Also, the one I have tested this with, is a Bare Bones Board with Atmega328 at 16 MHz. But I think it should work with an atmega168 at the same speed or slower without any modifications.

(I know, I mixed block schematics with pinout for the 74xx164)


Indeed reinventing the wheel it might be ( http://www.arduino.cc/playground/Code/LCD3wires ) but I think a version with 74XX164 and a hand drawn schematics adds a lot of cuteness factor to it. You might consider adding info to that page in the playground. Sharing the code on sites like RapidShare might make it inaccessible in few weeks. You might consider hosting in at some public code repository  service like github (http://github.com/) or google code (http://code.google.com/projecthosting/).
Thank you for your work and sharing it!


Thanks for your tip! I was unsure about where to host it. Modified the first post to reflect the changes now.

Not sure how cute a 74xx164 is :P As for the handdrawing I didn't have any electronics CAD installed that worked well enough, and when I found I resorted to GIMP and really badly hand-mouse-drawn lines to "fix" the schematics I captured, I used the pen and paper instead  :)

I did see the LCD3wires you linked to, but not before making this one. However as far as I can see that one doesn't use the print-library functions. So I posted my version as well.


Jul 23, 2009, 10:50 am Last Edit: Jul 23, 2009, 10:53 am by raron Reason: 1
Updated ShiftRegLCD library  :)

Link: http://code.google.com/p/arduinoshiftreglcd/

After some time away (exactly two months it seems), I have started fiddling with the 'duino and my LCD again.

I spotted the improved library from LadyAda http://web.alfredstate.edu/weimandn/arduino/LiquidCrystal_library/LiquidCrystal_index.html, which included a proper initialization timing sequence. After much fiddling tonight I have included most if not all of those functions (although not tested them all).

And now it seems really stable and initializing the display every time so far!

I also fixed the generation of the (eight) custom characters, which now works. Examples of usage are included.

Of course the LCD must be connected as indicated, via a shift register. At least now there are more pins freed on the Arduino to do other things than displaying info.

I have so far only tested this on my 1-line 32 character LCD. A curious little fact is that if I initialize it as a two-line display, one can see the upper part of line 2 below line one. I only have the 8 pixel tall characters, it doesn't seem to have the 10 pixel ones, and also it doesn't have lowercase letters (They are changed to some greek letters instead).

Comments, tips etc are welcome. Experiences with other types of LCD's also.

If it works well enough, maybe someone would add it to the Playground as suggested above?


Jul 26, 2009, 12:03 am Last Edit: Jul 26, 2009, 12:06 am by mircho Reason: 1
I did make it to work with 2 wires. Here is the description how to do it (I am NOT the original author!):
I did small adjustments to your lib though:
Bit 8 - enable
Bit 7 - reset
the next 4 bits are the data bits sent. I think we can provide a library that can work with either 2 or 3 wires. Do you think it's better to reduce it to using only two wires, and provide a library for only that?



That was pretty cool!

My first thought is if this method is reliable - I can see the Enable-line being pulled high while transfering data to the shiftregister, dependent on what data is on the shiftregister and what data is being sent.

I am unsure about the speed of the shiftOut-function though, and how fast the LCD would react to the enable-signal.

That diode-AND "gate" is pretty clever. There are still two more output pins on the shiftregister, maybe if we used the same technique and AND'ed three carefully chosen outputs to the Enable-line, we could diminish the possibility of a false enable-signal? If, of course, that is a problem. Off the top of my head I can imagine spreading the three outputs between the 4 data lines, to avoid a false enable. But I haven't thought this through.. nor have I tested the method yet.

As for the library, if it turns out to be reliable with only two wires, why not? The schematics is simple enough, only 1 (or three?) diodes and a resistor in addition to the shiftregister.

BTW, I really messed up the comments (especially the URL's) in my updated library, thats for staying up late and publishing too early:p I had to fix it (also renamed a function), but its no functional change.


Well the accidental enable is avoided in two ways - the enable bit is the last one - QH. Reset is QG. Actual bits are QC, QD, QE, QF. Every time you start outputting data you have to clear the register by shifting out a zero byte. That can be reduced to only shifting out 6 zero bits.
So far I did not notice any problems when sending commands or data to the LCD - it works, and because of ladyada's timing additions everything is far more reliable than before. I even feel the LCD as more responsive.


I assume by "reset" you mean the RS signal - Register Select?

Anyway, I couldn't get this to work, the display got all garbled. Even with the clearing of the shift register before each write, and the Enable bit at last position (QH). Admittingly I had the RS as the first bit in the beginning, then modifying it so that I could write the last bit (that is QA - first position) as a zero, but it was still no go. Oh, and I dicovered my idea of several enable-diode-AND-"gates" was not really worth mentioning..

What value did you use for the resistor? I used 6.8 k. Also could you post the relevant bits (no pun:p) of code? Particularly the parts to write to the shiftregister?

Btw I also see from the link you gave, he had a better way of using 3 wires with a shiftregister. One that used all 8 bits for data to the LCD. Would make for a little faster display. http://www.scienceprog.com/connect-lcd-to-atmega-using-3-wires/.

But, of course, two wires would be the coolest. If only I could get it to work... (and I -was- happy with using three in 4-bit mode :P)


Jul 26, 2009, 06:58 pm Last Edit: Jul 26, 2009, 06:59 pm by mircho Reason: 1
You are right - I mean RS line - Register Select.
Well as you control the google code repository now I can email you the lib and you can look at it. We can start using the svn part of the repository and have the lib there instead as attached archives. What do you think? Give me an email address (you can send me a private message).
At the beginning I had all kinds of garbage showing on the display. The schematics I linked mentions a zener and at the beginning I used the first zener I had in my parts bin. The resistor is 0.8K. Later I found out that my zener had such reverse breakdown voltage that the AND gate just did not work. So I just used a normal 1n4004 and it worked like a charm. Of course I did all the time adjustments to the software so I could not be 100% sure if it was not a cumulative error :).


Thanks, I finally got it working  :) All I did was changing the resistor to 1k!

I'm pretty new to code repositories and svn, all I know is that svn is some sort of version control making it easier to collaborate on projects? I'll priv you my mail in a moment.

I have a slightly different setup than you, as my RS pin is on shift register pin#1 (QB). The reason is just that I'm getting into making PCB's at the moment, and jumped at making a breadbord-LCD-friendly PCB a little early. I didn't want to scrap it, so I modified it as described in the above post. No biggie, but that's why I have that setup instead.

The way I'm defing two pins at the moment is simply to define the enable-pin the same pin number as the datapin. I might change it somewhat, at least add a constructor for two pins only. What do you think? This way it's optional to use two or three wires, depending on the connection.

My display displays 32 characters in approximately 20 ms, versus approx 15 ms before. Not really a big deal.


I did similar changes to the library. The current constructors will make it harder to provide one that is for the particular case of 2 wire interface. I use a big value for the enable pin (100) to mark that the enable will be the same as data pin.
I also either removed the delays or made them shorter.
According to what I came up with, and the two articles about MCU two wire interface to HD44780 with 74HC164 shift register the only limitation would be to set QA of the SR to 0 (or not to use it) on every shift (this is to prevent accidental enable while shifting in new values).
Now we have to clean up the code and provide better schematics.


Aug 12, 2009, 12:42 pm Last Edit: Aug 12, 2009, 12:43 pm by o0Mouse0o Reason: 1
After building the two wire version  with a surface mount 74HC164 on a 4X20 LCD I realised the code only accommodates a 1 line display.
Line 0 works well and that rolls over into line 2 but obviously cant get text to appear on lines 1 and 3. :-/  I've tried using begin() but it appears to not be used.

Has anybody got it to work for a 4 line display? or am I missing something obvious?
It would be a shame to undo all the work soldering it together :(


Aug 12, 2009, 03:03 pm Last Edit: Aug 12, 2009, 03:09 pm by raron Reason: 1
I don't have any 4-line displays, but as I have understood it, they have two separate enable lines and common D0-D7 data inputs? (damn now I got a new idea for a simple improvement!) I don't know if that's the case with your display though.

The HD44780 datasheet doeesn't really support more than 2 lines for a display. The library as of now conforms to that (even if you set more than 2 lines it will be 2).

The simple improvement I thought of just now, is that it could use two diode-AND-gates at the two MSB-bits of the shiftregister, which could go to their separate enable-input of the LCD, thus still using 2 outputs for a 4-line LCD.

For the moment, if your display have 2 enable inputs, you can use the library in 3-wire mode (without the diode-AND gate), and make 2 instances of the shiftRegLCD objects, which uses the same data and clock pins, but different enable pins. Thus using 4 outputs from the Arduino. I haven't tested this but it should work. So you would write to display lines 1 and 2 using one object, like

   srlcd.print("Using enable pin 1");

and write on line 3 and 4 with another srlcd object:

   srlcd2.print("Using enable pin 2");

Of course after making two instances of the objects:

   ShiftRegLCD srlcd(12,13,8);
   ShiftRegLCD srlcd2(12,13,9); // same data and clock, different enable

Hope it helps. I'm not sure when I will update the library, but I can try to do it soon-ish. In which case you'd need to rewire your nice SMD shiftregister a bit (litterally a bit position lower in fact :P) , and add another diode and resistor (But details will be posted later).


Definitely one enable input. The data-sheet is not helpful in giving information about addressing the four lines or the memory map layout of the displayed characters.
I've also looked up other data sheets for 20x4 displays and the ones I found also had a single enable input.
If its any help lines 0 and 2 go clear when initialised and lines 1 and 3 are blank so I guess they are not initialising?
When I get time later on I'll look up 40x2 displays in case this one is a 40x2 'folded in half'.


I've done research on 4 lines displays and I think that the solution was a simple modification in the initialization routines of the library. But as I don't have any 4 line displays I did not even try to code the changes.

Go Up