LCD Interfacing
...................................................................................................................................

As we've mentioned, the LCD requires either 8 or 11 I/O lines to communicate with. For the sake of this tutorial, we are going to use an 8-bit data bus--so we'll be using 11 of the 8051's I/O pins to interface with the LCD.

Let's draw a sample psuedo-schematic of how the LCD will be connected to the 8051.
As you can see, we've established a 1-to-1 relation between a pin on the 8051 and a line on the 44780 LCD. Thus as we write our assembly program to access the LCD, we are going to equate constants to the 8051 ports so that we can refer to the lines by their 44780 name as opposed to P0.1, P0.2, etc. Let's go ahead and write our initial equates:

DB0        EQU        P1.0
DB1        EQU        P1.1        
DB2        EQU        P1.2
DB3        EQU        P1.3
DB4        EQU        P1.4
DB5        EQU        P1.5
DB6        EQU        P1.6
DB7        EQU        P1.7
EN        EQU        P3.7
RS        EQU        P3.6
RW        EQU        P3.5
DATA EQU        P1

Having established the above equates, we may now refer to our I/O lines by their 44780 name. For example, to set the RW line high (1), we can execute the following instruction:

SETB RW

HANDLING THE EN CONTROL LINE

As we mentioned above, the EN line is used to tell the LCD that you are ready for it to execute an instruction that you've prepared on the data bus and on the other control lines. Note that the EN line must be raised/lowered before/after each instruction sent to the LCD regardless of whether that instruction is read or write, text or instruction. In short, you must always manipulate EN when communicating with the LCD. EN is the LCD's way of knowing that you are talking to it. If you don't raise/lower EN, the LCD doesn't know you're talking to it on the other lines.

Thus, before we interact in any way with the LCD we will always bring the EN line high with the following instruction:

SETB EN

And once we've finished setting up our instruction with the other control lines and data bus lines, we'll always bring this line back low:

CLR EN

Programming Tip: The LCD interprets and executes our command at the instant the EN line is brought low. If you never bring EN low, your instruction will never be executed. Additionally, when you bring EN low and the LCD executes your instruction, it requires a certain amount of time to execute the command.
CHECKING THE BUSY STATUS OF THE LCD

As previously mentioned, it takes a certain amount of time for each instruction to be executed by the LCD. The delay varies depending on the frequency of the crystal attached to the oscillator input of the 44780 as well as the instruction which is being executed.

While it is possible to write code that waits for a specific amount of time to allow the LCD to execute instructions, this method of "waiting" is not very flexible. If the crystal frequency is changed, the software will need to be modified. Additionally, if the LCD itself is changed for another LCD which, although 44780 compatible, requires more time to perform its operations, the program will not work until it is properly modified.

A more robust method of programming is to use the "Get LCD Status" command to determine whether the LCD is still busy executing the last instruction received.

The "Get LCD Status" command will return to us two tidbits of information; the information that is useful to us right now is found in DB7. In summary, when we issue the "Get LCD Status" command the LCD will immediately raise DB7 if it's still busy executing a command or lower DB7 to indicate that the LCD is no longer occupied. Thus our program can query the LCD until DB7 goes low, indicating the LCD is no longer busy. At that point we are free to continue and send the next command.

Since we will use this code every time we send an instruction to the LCD, it is useful to make it a subroutine. Let's write the code:

WAIT_LCD:
SETB EN                        ;Start LCD command
CLR RS                        ;It's a command
SETB RW                        ;It's a read command
MOV DATA,#0FFh                ;Set all pins to FF initially
MOV A,DATA                        ;Read the return value
JB ACC.7,WAIT_LCD        ;If bit 7 high, LCD still busy
CLR EN                        ;Finish the command
CLR RW                        ;Turn off RW for future commands
RET

Thus, our standard practice will be to send an instruction to the LCD and then call our WAIT_LCD routine to wait until the instruction is completely executed by the LCD. This will assure that our program gives the LCD the time it needs to execute instructions and also makes our program compatible with any LCD, regardless of how fast or slow it is.

Programming Tips: The above routines does the job of waiting for the LCD, but were it to be used in a real application a very definite improvement would need to be made: as written, if the LCD never becomes "not busy" the program will effectively "hang," waiting for DB7 to go low. If this never happens, the program will freeze. Of course, this should never happen and won't happen when the hardware is working properly. But in a real application it would be wise to put some kind of time limit on the delay--for example, a maximum of 256 attempts to wait for the busy signal to go low. This would guarantee that even if the LCD hardware fails, the program would not lock up.
INITIALIZING THE LCD

CLEARING THE DISPLAY

A "HELLO WORLD" PROGRAM

LCD command Codes & Character Code