Search Your Query

Custom Search

Monday 23 May 2011

3-Wire LCD Interface For 8051 Systems


; ------------- READS51 generated header -------------- 
; module : C:\Rigel\Reads51\Work\LCD\LCD.asm
; created : 20:34:08, Thursday, August 15, 2002
; author : Vidyasagaran P. (v_sagar_p@yahoo.com)
; This file contains all the routines needed to manipulate the LCD display
; Please note that these routines are hardware wiring specific and will need
; changes if the wiring changes. You may have to adjust the delay (DLY_IDX) depending on
; the processor speed.
; +-------+ +---------------+
; | P0.0+-------------------------------------->+E LCD |
; | | +----------+ | |
; | P0.1+-------------->+CLK D5+----------->+RS R/W+---+
; | P0.2+-------------->+INPUT D0-4+--------\-->+D4-D7 | |
; | | | | +--\-->+D0-D3 | - Gnd
; +-------+ +----------+ | +---------------+
; 8051 74HC164 -Gnd LCD display
; How data is loaded into the LCD
;
; 1. clock the upper nibble in and use E bit to latch the higher 4 bits
; 2. clock the lower nibble in similarly
; -----------------------------------------------------
;
; The following definitions are as per the ABOVE hardware wiring.
; It assumes 3 port pins used for display functions. First one directly connected to LCD
; E (enable) bit and reset two are connected to an 8 bit output shift register as below.

#include <sfr51.inc>

;----------------------- PORTING Changes to be done in the following ---------
#define LCD_PORT P3 ;Port used for LCD interface
#define BASE 000 ;where the code this located
#define DLY_IDX 2FH ;depends on speed of processor

#define EBIT LCD_PORT.0 ;LCD Ebit pin
#define S2P_CLK LCD_PORT.1 ;Serial to parallel convertor 74HC164 clock pin
#define S2P_IN LCD_PORT.2 ;Serial to parallel convertor 74HC164 serial input


CodeSeg segment code

Public _Init_LCD
Public _display_string

rseg Codeseg
org BASE

_Init_LCD:
clr EBIT ;reset the LCD E bit used. 
                           ;Other pins need not be cleared.

acall init_lcd
mov DPTR,#Init_msg
acall _display_string
ret

;-----------------------------------------------------------
;clear_home_cursor - put the cursor back to first char
clear_home_cursor:
;clear display
clr c
mov acc,#00000001b
acall _write_char

;home cursor
clr c
mov acc,#00000010b
acall _write_char
ret

;-----------------------------------------------------------
;_display_string is a function which assumes the address of the string
;to be passed in DPTR, in the code memory. Strin must have a NULL at the end.
_display_string:
mov acc,r1 ;save R1
push acc
mov acc,r0 ;save R0, as this is destroyed in _write_char
push acc

acall clear_home_cursor
mov r1,#0 ;index count for next character
display_string_loop:
mov a,r1 ;move index count to accumulator
movc a,@a+DPTR ;next char to go
jz display_string_out ;is it a null?
setb c ;if not null set carry to write char
acall _write_char ;call write_char function
inc r1 ;next char to go
sjmp display_string_loop ;repeat till all chars are done
display_string_out:

pop acc ;restore R0 as write_char destroys this
mov r0,acc
pop acc ;restore R1
mov r1,acc
ret

;-----------------------------------------------------------
;A character is passed in to this routine in accumulator
;this routine assumes the following wiring from uP to the LCD.
;R0 is destroyed. But exported functions "display_string" saves this,
;(a precausion which is optimised also!)
_write_char:
mov ov,c ;store state of c for second nibble write
mov r0,#5 ;we need to shift these many times
setb ac ;this indicates second nibble needs to be written yet

write_char_loop:
mov S2P_IN,c ;serial input bit
clr S2P_CLK ;clock once
setb S2P_CLK
rlc a ;get c flag set as per data bits from next time
djnz r0,write_char_loop

;make the LCD latch the value
setb EBIT ;pulse Ebit for one time for the first nibble
clr EBIT

jnb ac,write_char_over
clr ac ;get out after the second nibble written

rrc a ;remove that extra rotation
mov c,ov ;restore the original carry to write second nibble
mov r0,#5 ;we need to write these many times
sjmp write_char_loop

write_char_over:
jb ov,write_char_nodelay ;for command writes delay is needed, not for chars!
acall big_dly
write_char_nodelay:
ret

;----------------------------------------------------------
;write_one_nibble : writes one Most significant nibble in a passed char
;to the LCD. Caller should set the C to indicate write to LCD command
;Assumes left roation of bits and hence wiring of data bits from Latch
;to be accordingly
;contents of R0 is destroyed
write_one_nibble:
mov r0,#5 ;we need to write these many times

write_one_nibble_loop:
mov S2P_IN,c ;serial input bit
clr S2P_CLK ;clock once
setb S2P_CLK
rlc a ;get c flag set as per data bits from second time
djnz r0,write_one_nibble_loop

;make the LCD latch the value
setb EBIT ;pulse Ebit for one time for the first nibble
clr EBIT
acall big_dly
ret

;----------------------------------------------------------
;a big delay for the LCD to settle after each init stuff. Some places this
;delay seems to be very critical. I have put more since it doesn't take much
;time and also since it is only one time init.
big_dly:
mov r0,#DLY_IDX
odly:
mov acc,#FFH
dly:
djnz acc,dly ;Simulater virtually hangs here. So comment this during simulation
djnz r0,odly
ret

;----------------------------------------------------------
;init_lcd : the following routine works fine from the first write after
;the power is applied. "write_one_nibble" is used to change the LCD mode
;from 8 bit interface to 4 bit one. For this write alone the D0-D3 is taken
;as 0000 as they are hardwired to ground.
init_lcd:
;set display width
clr c
mov acc,#00100000b
acall write_one_nibble

;enable display and cursor
clr c
mov acc,#00001100b ;no cursor and no blink
acall _write_char

;clear display
clr c
mov acc,#00000001b
acall _write_char

;home cursor
clr c
mov acc,#00000010b
acall _write_char
ret

;-----------------------------------------------------------
Init_msg:
DB "Display OK",0

end

No comments:

Post a Comment

Related Posts Plugin for WordPress, Blogger...