Site hosted by Angelfire.com: Build your free website today!

A 2-Bit Interface For Character LCDs

The vast majority of character LCD displays contain an Hitachi HD44780 LCD controller (or equivalent) chip. As a result, writing a program to display characters to such a display is a more-or-less standard action. Most microcontroller languages include driver software for these handy displays.

In nearly every case, these character LCD displays are accessed via a 14-pin or a 16-pin connector. The first 14 pins of a 16-pin character are the same as the 14 pins of a 14-pin model. When the extra two pins are needed, they simply provide a source of power for a backlight facility in the LCD module. The backlight can make the display glow, producing its own light. For purposes of most of this discussion, I will dispense with the two extra pins and just consider the common 14-pin portion.

The 14 pins have the following assignments:

  1. Ground
  2. +5V power supply
  3. Contrast control
  4. Register Select
  5. Read/Write
  6. Enable
  7. D0 data bit
  8. D1 data bit
  9. D2 data bit
  10. D3 data bit
  11. D4 data bit
  12. D5 data bit
  13. D6 data bit
  14. D7 data bit

A microcontroller causes the LCD module to present characters on the display by writing the ASCII codes for the characters to the LCD module.

The Read/Write signal on pin 5 can be used to cause data to flow not only into the LCD module, but also from the LCD module back to the microcontroller. Very often hobbyists dispense with this reverse flow direction. As a result, they simply ground the Read/Write signal on the LCD module pin 5. That means that all data flows from the microcontroller to the LCD and never the reverse. This reduces the number of needed I/O pins of the microcontroller by one and simplifies the driver software.

Ground on pin 1 and +5 Volts on pin 2 of the module provide operating power to the LCD module.

The contrast control signal is an analog control signal supplied to the LCD module on pin 3. It determines how strongly the liquid crystal pixels are driven. In some applications, the contrast control pin may simply be grounded but this often results in very dark displays, sometimes to the point of causing the display to be unreadable. Most often, it is connected to the wiper of a 5K or 10K potentiometer. One end of the potentiometer is connected to ground while the other is connected to +5 Volts. The potentiometer then allows the user to vary the contrast control signal between 0 Volts and +5 Volts and, therefore, the contrast of the display.

The Register Select signal on pin 4 is used to indicate to the LCD module whether the information being transferred on the data lines constitutes a character or a command. Supported commands include clearing the LCD screen, moving the display's cursor to a particular position on the display, causing the display's cursor to be visible or to blink, etc. Sending a byte of information to the LCD module with the Register Select signal set to True (logic 1, or high) means the module will attempt to display the byte as a character. On the other hand, sending data to the LCD module with the Register Select signal set to False (logic 0, or low) means the module will attempt to decode the transmitted data as a command.

The LCD module samples the Register Select signal (on pin 4) and the data bit signals (D0 through D7 on pins 7 through 14) when the Enable signal (on pin 6) makes a high-to-low transition. The Register Select and data bit signals must be present for a short time prior the high-to-low transition and remain present for a short time afterward to assure they will be transferred without error.

The LCD module supports two different modes of operation, 8-Bit Mode and 4-Bit Mode.

In 8-Bit Mode, a byte to be sent to the LCD module is presented on the D0 - D7 data lines, the Register Select line is held high or low (according to whether the byte is a character to be displayed or a command), and the Enable line makes a high-to-low transition which strobes the information into the LCD module.

In 4-bit Mode, the byte to be sent to the LCD module is split into two 4-bit halves. The more significant four bits are sent to the LCD module's D4 - D7 data lines, the Register Select is set just as with the 8-bit Mode, and the Enable line makes a high-to-low transition. After a short delay, the process is repeated, but this time with the less significant four bits being sent to the D4 - D7 data lines.

Let us examine how many pins of a typical microcontroller are required to operate an LCD module in each of these two modes. In 8-bit Mode, we need the eight data lines, the Register Select signal, and the Enable signal. Normally, each of these is driven by an I/O pin of the microcontroller. Therefore, 10 I/O pins are needed.

In 4-bit Mode, we need four data lines, the Register Select signal, and the Enable signal. Therefore, we need a total of 6 I/O pins.

I have seen a few other LCD interface solutions that allow the LCD module to be operated with fewer I/O pins (typically one or two I/O pins). Such solutions involve using an SPI interface, a shift register, or a TTL serial interface. Therefore, each of these solutions requires an integrated circuit to accept the information and convert it to a form that the LCD module can accept either in its 8-bit Mode or its 4-bit Mode.

This page presents another approach to reducing the number of I/O lines required. The advantage of this approach is that it does not require an integrated circuit. In fact, it requires no semiconductors at all. It uses three resistors and three small capacitors to permit operating an LCD module with only three I/O pins of a microcontroller.

It has been built and tested by the author with some seven different types of LCD modules. Some have genuine HD44780 LCD controller chips in them while some have "mystery" chips hidden from view by a blob of black epoxy plastic.

This is achieved by operating the LCD module in 4-bit mode but causing each I/O pin to perform double duty. One pin is used to drive both D4 and D5. Another I/O pin is used to drive both D6 and D7. The remaining I/O pin drives both Register Select and Enable.

To understand the concept used, consider this simple circuit which uses one I/O pin to drive two outputs:

Stated simply, if we hold the state of the I/O Pin steady for about 50 microseconds, the voltage charge on the capacitor will be essentially the same as that of the I/O Pin. Then if we abruptly change the I/O Pin signal, Output 1 will be presenting the new state of the I/O Pin signal while Output 2 will still be outputting the previous I/O pin state for a short time. The capacitor serves as a 1-bit short term memory.

Here is the schematic for the complete 2-Bit interface:

With this technique, the LCD module can be operated in its 4-bit Mode. It will be receiving the six needed signals but those signals will be provided by only 3 I/O pins.

While I could have provided a program listing as an example of a program to drive this LCD interface, I felt that would be rather narrow in scope since this technique can be implemented using most any microcontroller and many possible languages. Therefore, I have provided a step-by-step description of what a program needs to do, regardless of the microcontroller or the language used to make it work.

Here is how the software should be organized to make it work:

In the creation of your program:

When your program is initializing, call the LCDInit subroutine to get the I/O pins moded and initialized properly and then the LCD module initialized.

In the remainder of your program, there are several subroutines that you may call as needed to cause the LCD to present the information you wish. Here is the list of subroutines and the functions they perform:

Note that LCDSend4 and LCDSend8 are subroutines that are intended to be called only internally.


Subroutine: LCDInit

  Set LCDRSFlg = 0

  Mode LCDRSE pin, LCDD4D5 pin, and LCDD6D7 pin to be output pins.

  Set LCDRSE pin = 0

  NOTE: The following sequence of an extended delay followed by sending 0x30 three times resets the LCD.

  Delay for at least 100 milliseconds to assure that power and LCD have stabilized.

  Set LCDSndChr = 0x30

  Call the LCDSend4 subroutine

  Delay for at least 10 milliseconds.

  Call the LCDSend4 subroutine

  Delay for at least 1 millisecond.

  Call the LCDSend4 subroutine


  NOTE: Sending 0x20 to the LCD switches it from 8-bit to 4-bit mode.

  Set LCDSndChr = 0x20

  Call the LCDSend4 subroutine


  NOTE: Sending 0x28 to LCD selects 4-bit mode, sets up for two text lines, and selects 5x7 font. The two text line setting is also appropriate for LCD modules with four lines such as a 20x4 LCD but not for LCD modules that present more than 80 characters total. Those would require a more extensive driver.

  Set LCDSndChr = 0x28

  Call the LCDSend8 subroutine


  NOTE: Sending 0x0C to the LCD tells it to have the display on, no cursor, and not blinking.

  Set LCDSndChr = 0x0C

  Call the LCDSend8 subroutine


  Call the LCDCls subroutine


  NOTE: Sending 0x06 to LCD selects Entry mode, selects incrementing character position, no shifting.

  Set LCDSndChr = 0x06

  Call the LCDSend8 subroutine

  Return from the LCDInit subroutine




Subroutine: LCDCLS

  Set LCDSndChr = 0x01

  Set LCDRSFlg = 0

  Call the LCDSend8 subroutine

  Delay 5 milliseconds

  Return from the LCDCLS subroutine




Subroutine: LCDHome

  Set LCDSndChr = 0x02

  Set LCDRSFlg = 0

  Call the LCDSend8 subroutine

  Delay 5 milliseconds

  Return from the LCDHome subroutine




NOTE: To position the LCD cursor to a desired character position (0 to 79), call LCDPos subroutine with the desired character position.

Subroutine: LCDPos

  Set LCDSndChr = (0x80 + desired character position)

  Set LCDRSFlg = 0

  Call the LCDSend8 subroutine

  Return from the LCDPos subroutine




Subroutine: LCDSend8

  Call the LCDSend4 subroutine

  Swap the more significant and less significant nibbles of LCDSndChr

  Call the LCDSend4 subroutine

  Delay 50 microseconds

  Return from the LCDSend8 subroutine




Subroutine: LCDSend4

  Set the LCDRSE pin = LCDRSFlg

  Set the LCDD4D5 pin = bit 4 of LCDSndChr

  Set the LCDD6D7 pin = bit 6 of LCDSndChr

  Delay 50 microseconds
                                            __      * These 3 steps are shown as individual
  Set the LCDD4D5 pin = bit 5 of LCDSndChr *  \       steps but should be combined if
                                               \      possible for speed purposes.
  Set the LCDD6D7 pin = bit 7 of LCDSndChr *    \
                                                 \  These steps need to take place in rapid
  Set the LCDRSE pin = 1 *                        > succession. Disallow interruptions during
                                                 /  this sequence as timing is critical here.
  Delay 1 microsecond                           /
                                               /
  Set the LCDRSE pin = 0 _____________________/

  Delay 50 microseconds

  Return from the LCDSend4 subroutine




NOTE: To display a character on the LCD at the current cursor position, call LCDOut subroutine with the character code.

Subroutine: LCDOut

  Set LCDSndChr = character code for character to be displayed

  Set LCDRSFlg = 1

  Call the LCDSend8 subroutine

  Return from the LCDOut subroutine


Send comments to:

Where to send email

Back To My Home Page

Updated 20150729