Home
Product Description
Application Notes
FAQ
Sales
Support
 

AN-002 Driving an LCD Module

LCD display modules based on the Hitachi 44780 controller are very common, readily available, and offer an inexpensive way to add text output to your design. Driving these displays is not difficult and the Basic routines that perform the task occupy a reasonable amount of space, making their use practical for a number of applications.

The LCD modules accept two types of information: commands and data. Commands direct the LCD's behavior. Using commands you can perform such actions as moving the cursor around, setting its visibility, and scrolling the display. Commands are also used when the display is first initialized to set items such as character length and number of lines.

To control the text that appears on the display, data is written to it. Most of the common characters that are written to the display follow ASCII conventions. Not all commands are used in the demonstration program and no font tables are given. For that information you should consult your LCD modules data sheets.

LCD displays can be driven using an eight bit or a four bit interface. See Figure 1 and Figure 2. Using an eight bit interface reduces the size of the program that drives it. Using a four bit interface reduces the number of processor pins used, but increases the length of the program that drives it. A compromise can be struck by reusing the data lines that drive the display at the possible cost of additional hardware (you may need some way to ignore the data lines during display driving).

Regardless of the interface used, there are essentially two steps to using an LCD display module; initialization and data writing. Initialization only needs to be performed once after power up. If the rise time of the power supply from 0 to 4.5 V falls within a range of 0.1 ms to 10 ms, then initialization can be ignored. If the power supply rises too quickly (as most seem to do) then the display will act unpredictably.

The programs for both the 4 bit and 8 bit examples are nearly identical. The primary difference has to do with the the way the data is written to the display in the subroutine WriteValue.

The program is composed of the main body of the program and three subroutines. At the beginning of the program the variables that are used are DIMensioned and constants are defined to enhance the readability of the program and ease program maintenance and updates.

The next major event in the program is a call to the subroutine InitDisplay. InitDisplay initializes the display by allowing a sequence of times to occur between successive pulsing of the display's E pin. The timing shown will work for oscillator frequencies of 4 MHz or less. If you increase oscillator frequency then the constants that define these times should be updated. Consult your display's data sheets for specific timing information. InitDisplay pulses the LCD's E pin by calling the subroutine ToggleE which does nothing more than simply toggle the LCD's E line. Note that ToggleE also contains two Pause statements to accommodate the display's minimum timing requirements. If you increase the oscillator frequency, the constants associated with the Pause statements should be changed.

In the main part of the program after the subroutine call to InitDisplay, the program next writes a sequence of commands to the display by first setting a status bit that defines sending commands, then loading values into a shared variable, and finally by calling the subroutine WriteValue. This does not need to be done if the display's default initialization is satisfactory (8 bit, single line display). The sequence of commands sent by the program sets the display for 2 lines and either four or eight bit interface depending on the program.

Finally, the program gets to the heart of the matter - sending data. In this case data is sent in two For loops. The first sends sixteen letters and the second sends numbers followed by the characters that appear in the ASCII table.

The subroutines used here are reused in other application notes. See the application note for the LCD clock for an additional example of LCD driving.



Program 1 - 8 BIT LCD Interface Program

/*
*******************************  Driving an LCD   **************************
This program should be used with the "Generic 8 bit LCD" circuit. It displays some
simple information on an LCD.  The program is written for 8 data lines with
a 2 X 16 display.
This program is not heavily commented.  See the Application Note for complete details
on the circuits operation and a description of this program.
*/

'Before entering the body of the program declare the variables that will be used.
'The most frequently used variables are DIMensionsed beggining with register 16
'to minimize the size of the program.

DIM Byte At 16 SendValue, FlagReg, temp

'To make the program more readable define some constants.
RS = Bit5         'the bit connected to the RS line
RW = Bit4         'the bit connected to the RW line
E = Bit3          'the bit connected to the E line
LCDwrite = PortB  'the port where the data line are connected, data write
LCDRead = PinB    'the data lines when read
Control = PortD   'write to the control lines
Busy = Bit7       'the busy line from the display
PauseVal = 2      'This number changes with the oscillator.  At 4 Mhz 2 is used.
LongPause = 150000   'This number changes with the oscillator.  At 4 Mhz 150000 is used.
MidPause = 20000  'This number changes with the oscillator.  At 4 Mhz 20000 is used.

'Before starting, the input/output status of the ports must be established
setPortDirection(DDRD,10111000\B)'set the control lines as outputs
setPortDirection(DDRB,255)       'set the data lines as outputs

gosub InitDisplay


'Now it is time to issue some commands to the display so that it is in the proper mode
clearBit(FlagReg,0)                  'make sure that we are sending commands

'set the display for two line 8 bit operation
sendValue = 00111000\B               'set for 2 line, 8 bits
goSub WriteValue                     'send the command

'set cursor control and on/off
sendValue = 00001110\B
goSub WriteValue                     'send the command

'set the display to auto increment the address counter
sendValue = 00000110\B
goSub WriteValue                     'send the command

'force the dispaly to home and clear
sendValue = 00000001\B
goSub WriteValue                     'send the command

'Now that the display is completely initialized send some data to it.
'This is not very fancy but it is straight forward
setBit(flagReg,0)                    'make sure that we are sending values

'send some letters in a loop
for sendValue = 97 to 112            'for sendValue = the letter "a" to "p"
   goSub WriteValue
next sendValue


'Now move the cursor to the first character position in the second line.
'This requires another command so clear the flag.
clearBit(FlagReg,0)                  'make sure that we are sending commands
sendValue = 11000000\B
goSub WriteValue                     'send the command

'Now send more characters.  Reset the flag.
setBit(flagReg,0)                    'make sure that we are sending values
'send some numers and other stuff in a loop
for sendValue = 48 to 63            'for sendValue = the ASCII for "0" to "?"
   goSub WriteValue
next sendValue

End


Sub WriteValue
   'This subroutine handles writting the value in the variable SendValue to the display.
   'If Bit 0 of FlagReg is 1 then data is written to the display else a command is written.
   'First make sure the display is not busy
   write(Control,11010111\B)           'set up for polling the busy flag from the display
   setPortDirection(DDRB,0)            'set port B for input
   setPortPin(Control,E)               'set the "E" line
   Pause(PauseVal)                     'LCD displays are slow - wait for a bit
writeWait:
   temp = read(PinB)                   'read the value from the display
   BranchOnHigh(temp,Busy,writeWait)   'if the busy bit is high (display is busy) jump up
   'now set up for a write to the dispaly
   setPortDirection(DDRB,255)          'set port B for output
   ClearPortPin(Control,RW)            'clear the RW pin to set up a write
   write(LCDwrite,sendValue)           'move the value to be written to the port
   
   BranchOnLow(flagReg,Bit0,hopAround) 'if data is to be written do the following
   SetPortPin(Control,RS)              'set the RS line
   Pause(PauseVal)                     'LCD displays are slow - wait for a bit
hopAround:
   setPortPin(Control,E)               'set the "E" line
   Pause(PauseVal)                     'LCD displays are slow - wait for a bit
   clearPortPin(Control,E)             'clear the "E" line
end sub

Sub initDisplay
   'This subroutine handles initializing the display. Depending on the characteristics of the
   'power supply used this routine may be modified or eliminated.
   write(LCDwrite,00110000\B)           'set up the value to be written
   Pause(LongPause)                     'wait for the display to gather itself
   gosub toggleE                        'raise and lower E
   Pause(MidPause)                      'wait again
   gosub toggleE                        'raise and lower E
   Pause(MidPause)                      'wait again
   gosub toggleE                        'raise and lower E
   Pause(MidPause)                      'wait again - longer than needed but thats ok
end sub

Sub toggleE
   setPortPin(Control,E)                'set the "E" line
   Pause(PauseVal)                      'LCD displays are slow - wait for a bit. Make larger at > 4 MHz
   clearPortPin(Control,E)              'set the "E" line
   Pause(PauseVal)                      'LCD displays are slow - wait for a bit. Make larger at > 4 MHz
end sub



Program 2 - 4 BIT LCD Interface Program

/*
******************************* Driving an LCD **************************
This program should be used with the "Generic 4 bit LCD" circuit. It displays some
simple information on an LCD. The program is written for 4 data lines with
a 2 X 16 display.
This program is not heavily commented. See the Application Note for complete details
on the circuits operation and a description of this program.
*/

'Before entering the body of the program declare the variables that will be used.
'The most frequently used variables are DIMensionsed beggining with register 16
'to minimize the size of the program.
DIM Byte At 16 SendValue, FlagReg, temp

'To make the program more readable define some constants.
RS = Bit6          'the bit connected to the RS line
RW = Bit5          'the bit connected to the RW line
E = Bit4           'the bit connected to the E line
LCD = PortD        'the port where the LCD is connected
LCDread = PinD     'the LCD input
Busy = Bit3        'the busy line from the display
PauseVal = 2       'This number changes with the oscillator. At 4 Mhz 2 is used.
LongPause = 150000 'This number changes with the oscillator. At 4 Mhz 150000 is used.
MidPause = 20000   'This number changes with the oscillator. At 4 Mhz 20000 is used.

gosub InitDisplay

'Now it is time to issue some commands to the display so that it is in the proper mode
clearBit(FlagReg,0)                  'make sure that we are sending commands
'set the display for two line operation
sendValue = 00101000\B               'set for 2 lines
goSub WriteValue                     'send the command
'set cursor control and on/off
sendValue = 00001100\B
goSub WriteValue                     'send the command
'set the display to auto increment the address counter
sendValue = 00000110\B
goSub WriteValue                     'send the command
'force the dispaly to position 0 on the display
sendValue = 10000000\B
goSub WriteValue                     'send the command


'Now that the display is completely initialized send some data to it.
'This is not very fancy but it is straight forward
setBit(flagReg,0)                    'make sure that we are sending values
'send some letters in a loop
for sendValue = 97 to 112            'for sendValue = the letter "a" to "p"
      goSub WriteValue
next sendValue

'Now move the cursor to the first character position in the second line.
'This requires another command so clear the flag.
clearBit(FlagReg,0)                  'make sure that we are sending commands
sendValue = 11000000\B
goSub WriteValue                     'send the command
'Now send more characters. Reset the flag.
setBit(flagReg,0)                    'make sure that we are sending values
'send some numers and other stuff in a loop
for sendValue = 48 to 63             'for sendValue = the ASCII for "0" to "?"
      goSub WriteValue
next sendValue
End


Sub WriteValue
   'This subroutine handles writting the value in the variable SendValue to the display.
   'If Bit 0 of FlagReg is 1 then data is written to the display else a command is written.
   'First make sure the display is not busy
   write(LCD,00100000\B)                'set up for polling the busy flag from the display
   setPortDirection(DDRD,01110000\B)    'set the data direction for reading the busy flag
   Pause(PauseVal)                      'LCD displays are slow - wait for a bit
   setPortPin(LCD,E)                    'set the "E" line
   Pause(PauseVal)                      'LCD displays are slow - wait for a bit
writeWait:
   temp = read(LCDread)                 'read the value from the display
   BranchOnHigh(temp,Busy,writeWait)    'if the busy bit is high (display is busy) jump up

   'Now that the display is ready get the upper nibble of sendValue to the low nibble position
   temp = sendValue                     'move it into a temp register
   swap(temp)                           'flip the nibbles
   temp = temp AND 00001111\B           'turn off the upper bits
   copyBit(flagReg,Bit0,temp,RS)        'if the write data bit is set set up RS to match
   'That done move to the port
   write(LCD,temp)                      'move it to the port
   setPortDirection(DDRD,255)           'set port D for output
   Pause(PauseVal)
   'send the first nibble
   setPortPin(LCD,E)                    'set the "E" line
   Pause(PauseVal)                      'LCD displays are slow - wait for a bit
   clearPortPin(LCD,E)                  'clear the "E" line

   'set up the next data to be sent
   temp = sendValue AND 00001111\B      'knock off the upper 4 bits
   copyBit(flagReg,Bit0,temp,RS)        'if the write data bit is set set up RS to match
   write(LCD,temp)
   Pause(PauseVal)
   'send the second nibble
   setPortPin(LCD,E)                    'set the "E" line
   Pause(PauseVal)                      'LCD displays are slow - wait for a bit
   clearPortPin(LCD,E)                  'clear the "E" line
hopAroundMore:
end sub

Sub initDisplay
   'This subroutine handles initializing the display and setting it up for 4 bit data transfers.
   'Depending on the characteristics of the power supply used this routine may be modified by
   'eliminating the hardwre initialization.
   write(LCD,00000011\B)                'set up the value to be written
   setPortDirection(DDRD,255)           'set the pins to output
   Pause(LongPause)                     'wait for the display to gather itself
   gosub toggleE                        'raise and lower E
   Pause(MidPause)                      'wait again
   gosub toggleE                        'raise and lower E
   Pause(MidPause)                      'wait again
   gosub toggleE                        'raise and lower E
   Pause(MidPause)                      'wait again - longer than needed but thats ok
   'Now put it into 4 bit mode
   write(LCD,00000010\B)                'now set it to 4 bit mode
   gosub toggleE                        'raise and lower E
end sub

Sub toggleE
   setPortPin(LCD,E)                    'set the "E" line
   Pause(PauseVal)                      'LCD displays are slow - wait for a bit. Make larger at > 4 MHz
   clearPortPin(LCD,E)                  'set the "E" line
   Pause(PauseVal)                      'LCD displays are slow - wait for a bit. Make larger at > 4 MHz
end sub
   
Copyright ©1997-99 Optical Countermeasures