3-wire, 8-bit LCD Interface

Back in the olden days, when men were men and floppy disks were huge, we programmed the first microprocessors in assembly language – and we liked it that way.  Now that I’m retired I decided to revisit those days of yore and play around with the inexpensive PIC microcontrollers.  If you’ve done any research on them you know that you need a cheap programmer and the free MPLAB X IDE software to get going.  I’m not going to cover all of that because there is plenty of information out on the web.  There is also a lot of information on getting started with assembly language programming so I won’t go into detail on that either.  What I will do in this series of posts is to provide some simple hardware and software projects you can build.  Mostly they don’t have any particular stand alone value but they might serve as building blocks for your ideas.  Besides, sometimes the real fun is just in making something work.

In this first episode I will show you how to interface to the common 1602 LCD display.  Ok, so there are also a million versions of these out on the web but this one really is different.  The most straightforward interface is the 8-bit parallel one but that requires a ton of I/O lines from your microcontroller.  You can reduce the line count by four if you do the 4-bit parallel interface but the software complexity (and memory usage) goes up.  There are also a couple of different serial interfaces like I2C or using a shift register but each has its own drawbacks.   Many of the serial interfaces just do 4-bit data to the LCD or they require  four I/O lines or two shift registers to do an 8-bit serial interface.  The interface I use requires a single shift register but only requires three lines from the microcontroller for a full 8-bit interface.  That means that you can actually use one of those 8-pin PICs (like the 12F683) and still have a couple of I/O lines left for sensor inputs.  The secret lies in using a simple hardware trick and a simple software trick.  So let’s get started.


The diagram of the pin connections between the shift register, the PIC, and the 1602 LCD are shown below.

 PIC LCD Interface

As you can see in the diagram, the shift register is the venerable 74HC164.  Most of the shift register/LCD interfaces on the web seem to use the 74HC595 but that requires an extra clock cycle to get the shifted bits into the latch outputs.  The 74HC164 (or any version of the ‘164 you can find) is still widely available so it’s not like I’m using an obsolete part.  The trick I mentioned is to use the PIC I/O port that clocks the shift register to also do the LCD mode select (data/instruction mode).  The software to handle that is also pretty simple and only adds a couple of instructions.

If you have looked at LCD interfaces on the web, you know that pretty much no one tries to read data back out of the LCD so we can just tie the R/W line to ground (write mode).  You have probably also seen that the contrast control is wired to either a two resistor voltage divider (between +5V and ground) or to a 5k to 20k potentiometer.  I use a 5k pot just because I have a ton of them salvaged from an old TV video alignment board.  Other than that, there shouldn’t be any mystery as to how to connect the pins.


One of the reasons I like assembly language for microcontrollers is because I like to talk directly to the hardware.  Once you understand that controlling the hardware is mostly just reading and writing to memory locations (called registers), the instructions start to make sense.  The instruction set is also pretty small so it doesn’t take much time to sort through them.  The hard part, if you are used to higher level languages, is that it takes a bit of getting used to the fact that simple constructs like IF-THEN-ELSE need to be built from several assembly instructions.  And math can be a nightmare so simple logic-based projects are usually best.  But, hey, isn’t challenge always part of the fun?

The software link is listed below.  While it is targeted for the 12F683, it is easily ported to bigger versions of the PIC.  Personally, I’ve used it with both the 16F688 and the 16F627.  Mostly it requires changing names like TRISIO to TRISA, and GPIO to PORTA.  You will also need to change the line that identifies the PIC version (LIST=) and the INCLUDE file but those are intuitive changes.  The __CONFIG line may also need tweaking just because one or two of the labels used are spelled differently in some of the INCLUDE files.

The LCD_Init routine adheres pretty much to the specified initialization sequence for the 1602 chip.  The two Test_Code routines output the phrase “HELLO” on line one of the LCD and “CAROL” on line two of the LCD.  It originally said “HELLO WORLD” but my wife was not impressed so I changed it to use her name.  She still wasn’t impressed but I got points for trying.  The software trick I mentioned earlier is in the Send_Byte routine.  I use the fact that the shift register clocks on a low to high edge and that the Clock line has been left in the high state after the last bit was clocked in.  A memory location Reg_Select has been previously set to either 0 or 1 depending on whether or not the byte being sent is a command or data.  If it is a command, then the Clock line is set low before enabling the LCD.  A short pulse on the LCD Enable line clocks the shift register byte into the LCD.  Well, that’s it for this post.  Check out my other projects.