LCD Display Driver

Overview

The control of the HD47780 based LCD display is handled by this module.  There is a lot of information available from the internet about this type of display, and the necessary control pins etc.  This code uses 4 bit mode (so each byte has to be clocked in as 2 nibbles) in order to save I/O lines.

One thing that's slightly unusual about these displays is the screen layout - I was using a 4 line display (20 chars width) and this is handled like a 2 line display, with the 1st and 3rd lines being treated as a 40 character line (and the same for line 2 being mapped to lines 2 and 4).

Code

subtitle "LCD Module"

LCD_PORT_D4 EQU PORTA
LCD_PORT_D5 EQU PORTA
LCD_PORT_D6 EQU PORTA
LCD_PORT_D7 EQU PORTA
LCD_PORT_E EQU PORTE
LCD_PORT_RS EQU PORTE
LCD_PORT_RW EQU PORTE

LCD_BIT_D4 EQU 0
LCD_BIT_D5 EQU 1
LCD_BIT_D6 EQU 2
LCD_BIT_D7 EQU 3
LCD_BIT_E EQU 0
LCD_BIT_RS EQU 1 ; 0 = Instruction, 1 = Data
LCD_BIT_RW EQU 2 ; 0 = Write, 1 = Read



; **************************************************************
; *
; * LCD_Initialise
; *
; * General Initialisation routines for the LCD display
; *
; **************************************************************
LCD_Initialise

; PORTE is exclusively for the LCD display, so
; set all these as outputs
banksel TRISE
clrf TRISE
movlw H'06' ; Same bank as TRISE
movwf ADCON1 ; Setup PORTE for Digital I/O

; PORTA set for outputs
banksel TRISA
movlw b'11110000'
andwf TRISA, F

; Make sure the enable pin is cleared
banksel PORTE
bcf LCD_PORT_E, LCD_BIT_E

banksel LCD_PORT_RS
bsf LCD_PORT_E, LCD_BIT_E
bcf LCD_PORT_RS, LCD_BIT_RS
bcf LCD_PORT_RW, LCD_BIT_RW

movlw 0xf0
banksel LCD_PORT_D4
andwf LCD_PORT_D4, F ; Clear the Data port

; Wait for 15mS as the Power Up delay
VarDelay10mS 4

bsf LCD_PORT_D5, LCD_BIT_D5
bsf LCD_PORT_D4, LCD_BIT_D4 ; Load 0x03

; drop the clock to latch data
bcf LCD_PORT_E, LCD_BIT_E

; Wait for 4.1mS as the Power Up delay
VarDelay10mS 0x2

; Now clock the same data again
bsf LCD_PORT_E, LCD_BIT_E
VarDelay100uS 5
bcf LCD_PORT_E, LCD_BIT_E
VarDelay100uS 5

; And one more time
bsf LCD_PORT_E, LCD_BIT_E
VarDelay100uS 5
bcf LCD_PORT_E, LCD_BIT_E
VarDelay100uS 5

; Now setup the display correctly
movlw 0x08 ; 4-bit interface, 2-lines
call LCD_FunctionSet
movlw 0x00
call LCD_DisplayOnOff ; Disp Off, Cursor Off, No blink
movlw 0x04
call LCD_DisplayOnOff ; Display On, Cursor Off

call LCD_ClearDisplay

movlw 0x02 ; Auto increment (shift-cursor)
call LCD_EntryModeSet

return


; **************************************************************
; *
; * LCD_Load8Bits
; *
; * Load 8 bits of data from W to the display
; *
; **************************************************************
LCD_Load8Bits

movwf LCDTemp0

banksel TRISA

; Make sure PORTA 0-3 are set to outputs
movlw H'F0'
andwf TRISA, 1

banksel PORTE

; Set RW line to low (Write mode)
bcf LCD_PORT_RW, LCD_BIT_RW

; Raise the Enable line ready for loading the data
bsf LCD_PORT_E, LCD_BIT_E

; Now load the first (upper) nibble onto the lines
bcf LCD_PORT_D4, LCD_BIT_D4 ; Clear the D4 line
btfsc LCDTemp0, 4 ; If Data, bit 4 is set, execute next line:
bsf LCD_PORT_D4, LCD_BIT_D4 ; Set D4 line
bcf LCD_PORT_D5, LCD_BIT_D5 ; Clear the D5 line
btfsc LCDTemp0, 5 ; If Data, bit 5 is set, execute next line:
bsf LCD_PORT_D5, LCD_BIT_D5 ; Set D5 line
bcf LCD_PORT_D6, LCD_BIT_D6 ; Clear the D6 line
btfsc LCDTemp0, 6 ; If Data, bit 6 is set, execute next line:
bsf LCD_PORT_D6, LCD_BIT_D6 ; Set D6 line
bcf LCD_PORT_D7, LCD_BIT_D7 ; Clear the D7 line
btfsc LCDTemp0, 7 ; If Data, bit 7 is set, execute next line:
bsf LCD_PORT_D7, LCD_BIT_D7 ; Set D7 line

; Drop the enable line to load the data
bcf LCD_PORT_E, LCD_BIT_E

; Raise the Enable line ready for loading the data
bsf LCD_PORT_E, LCD_BIT_E

; Now load the second (lower) nibble onto the lines
bcf LCD_PORT_D4, LCD_BIT_D4 ; Clear the D4 line
btfsc LCDTemp0, 0 ; If Data, bit 0 is set, execute next line:
bsf LCD_PORT_D4, LCD_BIT_D4 ; Set D4 line
bcf LCD_PORT_D5, LCD_BIT_D5 ; Clear the D5 line
btfsc LCDTemp0, 1 ; If Data, bit 1 is set, execute next line:
bsf LCD_PORT_D5, LCD_BIT_D5 ; Set D5 line
bcf LCD_PORT_D6, LCD_BIT_D6 ; Clear the D6 line
btfsc LCDTemp0, 2 ; If Data, bit 2 is set, execute next line:
bsf LCD_PORT_D6, LCD_BIT_D6 ; Set D6 line
bcf LCD_PORT_D7, LCD_BIT_D7 ; Clear the D7 line
btfsc LCDTemp0, 3 ; If Data, bit 3 is set, execute next line:
bsf LCD_PORT_D7, LCD_BIT_D7 ; Set D7 line

; Drop the enable line to load the data
bcf LCD_PORT_E, LCD_BIT_E

VarDelay100uS 0x1

return

; **************************************************************
; *
; * LCD_WriteInstruction
; *
; * Write an 8 bit instruction from W to the display
; *
; **************************************************************
LCD_WriteInstruction
; Clear the RS bit (INSTRUCTION mode)
bcf LCD_PORT_RS, LCD_BIT_RS

; Transfer the contents of W to the display
call LCD_Load8Bits

return

; **************************************************************
; *
; * LCD_WriteData
; *
; * Write 8 bit data from W to the display
; *
; **************************************************************
LCD_WriteData
; Set the RS bit (DATA mode)
bsf LCD_PORT_RS, LCD_BIT_RS

; Transfer the contents of W to the display
call LCD_Load8Bits

; Increment the screen locations (save having to read from display)
incf ScreenLoc, F

return

; **************************************************************
; *
; * LCD_WriteData (MACRO)
; *
; * Write 8 bit data from W to the display
; *
; **************************************************************
LCD_DisplayText macro TextPointer
movlw 0 ; Startindex of table message
LocalLCD_DisplayMsg
movwf LCDTextTableIndex ; Holds message address
pagesel TextPointer
call TextPointer
andlw 0x0FF ; Check if at end of message
btfsc STATUS, Z ; (zero returned at end)
goto LocalLCD_DisplayMsgEnd
call LCD_WriteData ; Display character
movf LCDTextTableIndex, W ; Point to next character
addlw 1
goto LocalLCD_DisplayMsg
LocalLCD_DisplayMsgEnd
endm



; **************************************************************
; *
; * LCD_ClearDisplay
; *
; **************************************************************
LCD_ClearDisplay
movlw H'01'
call LCD_WriteInstruction
VarDelay100uS 40
return

; **************************************************************
; *
; * LCD_CursorHome
; *
; **************************************************************
LCD_CursorHome
movlw H'02'
call LCD_WriteInstruction
VarDelay100uS 40
return

; **************************************************************
; *
; * LCD_EntryModeSet
; *
; * W: Inc/Dec = bit 1, Shift = bit 0
; *
; **************************************************************
LCD_EntryModeSet
; Set bit 2 and transfer bits 0 and 1
iorlw b'00000100'
andlw b'00000111'
call LCD_WriteInstruction
return

; **************************************************************
; *
; * LCD_DisplayOnOff
; *
; * W: I/O = bit 2, Cursor = bit 1, Blink = bit 0
; *
; **************************************************************
LCD_DisplayOnOff
; Set bit 3 and transfer bits 0, 1 and 2
iorlw b'00001000'
andlw b'00001111'
call LCD_WriteInstruction
return

; **************************************************************
; *
; * LCD_CursorDisplayShift
; *
; * W: S/C = bit 3, R/L = bit 2
; *
; **************************************************************
LCD_CursorDisplayShift
; Set bit 4 and transfer bits 2 and 3
iorlw b'00010000'
andlw b'00011100'
call LCD_WriteInstruction
return

; **************************************************************
; *
; * LCD_FunctionSet
; *
; * W: DL = bit 4, N = bit 3, F = bit 2
; *
; **************************************************************
LCD_FunctionSet
; Set bit 5 and transfer bits 3 and 4
iorlw b'00100000'
andlw b'00111100'
call LCD_WriteInstruction
return

; **************************************************************
; *
; * LCD_SetCGRAMAddress
; *
; * W: bits 0 to 5 = CGRAM Address
; *
; **************************************************************
LCD_SetCGRAMAddress
; Set bit 6 and transfer bits 0 to 5
iorlw b'01000000'
andlw b'01111111'
call LCD_WriteInstruction
return

; **************************************************************
; *
; * LCD_SetDDRAMAddress
; *
; * W: bits 0 to 6 = DDRAM Address
; *
; **************************************************************
LCD_SetDDRAMAddress
; Set bit 7 and transfer bits 0 to 6
iorlw b'10000000'
andlw b'11111111'
call LCD_WriteInstruction
return
Page Last Updated on Wednesday September 04, 2002