;===================================================================================
; FOUR BIT INTERFACING LCD DRIVER FOR 8051 or DERIVATED
; >>>
;-----------------------------------------------------------------------------------
; This utility is used for cotrolled LCD-Display with 4BIT interfacing
; The Port I/O is bit port of microcontroller. The configurations is :
; PORT: Bit 7 6 5 4 3 2 1 0
; FOR : U U U U D7 D6 D5 D4
;
; Note:
; - U is used for RS_LCD, RW_LCD and E_LCD pin or another bit output port.
; - 4 bit lcd data bus (for 4 bit interfacing is D7..D4) must be connected to
; bit 0..3 of I/O port (bidirectional, because this interfacing can write/read)
;
; RS_LCD, RW_LCD, E_LCD can connected to Bit 4 to 7.
; Please use pseudo opcode BIT to refer the bit that you like
; The PORT_LCD label is the LCD bit Port address of microcontroller
;
; This driver can intefaced to C language Keil-C51 uVision2 with "extern" prototype
; or Assembly.
;------------------------------------------+----------------------------------------
; EXTERN PROTOTYPE | FUNCTION
;------------------------------------------+----------------------------------------
; void init_lcd(void); | Initialaze LCD,LCD ON,NOBLINK,NOCURSOR
; void clr_lcd(void); | Clear LCD and Home Cursor
; void locate_lcd(char row, char col); | Locate cursor (begin 0)
; void csrhome_lcd(void); | Locate cursor to (0,0), char no clear
; void on_lcd(void) | Lcd ON no blink, no cursor
; void off_lcd(void); | Lcd off, character no display, no clear
; void wrchar_lcd(char character); | Display character to current cursor
; void wrstr_lcd(char *buff_char); | Display string depend generic pointer
; | *buff_char, in idata, data, xdata,
; | cdata, and pdata. Automatic pointer.
; void csrmode_lcd(char cur, char blink); | Set cursor mode
;===================================================================================
; THIS PROGRAM IS TESTED WITH C51 Keil uVision2 Version 6.20
; THE RESULT WORK FINE, NO ANY TROUBLE
; THE ALL ROUTINE USED REGISTER BANK 0 FOR PARAMETERS PASSING, IF ANOTHER BANK USED
; WILL NOT WORK FINE.
;===================================================================================
NAME Utility_LCD_4Bit_Port
Utility_LCD_4Bit_Port_SEG SEGMENT CODE
;==========================================================================
; The following is Control pin configurations.
; If the pin are changed, please the pin configurations are changed by you
;--------------------------------------------------------------------------
RS_LCD BIT P2.4
RW_LCD BIT P2.5
E_LCD BIT P2.6
sfr PORT_LCD = P2;
;==========================================================================
PUBLIC init_lcd
PUBLIC _wrstr_lcd
PUBLIC clr_lcd
PUBLIC csrhome_lcd
PUBLIC _locate_lcd
PUBLIC on_lcd
PUBLIC off_lcd
PUBLIC _wrchar_lcd
PUBLIC _wrctl_lcd
PUBLIC _csrmode_lcd
RSEG Utility_LCD_4Bit_Port_SEG
USING 0
;==========================================================================
; WRCTL_LCD_4BYTE : write 4bit data for control lcd
;--------------------------------------------------------------------------
; INPUT : R7 = data 4 bit : 0000DDDD
; OUTPUT : NONE
; REG USES : A, R7
; NO-PUBLIC to C51
;==========================================================================
wrctl_lcd_4byte: CLR C ; write operation prepare
CLR RS_LCD ; select control address
SJMP enable_lcd
;==========================================================================
; ENABLE_LCD : write/read 4bit data to/from lcd (data or control)
; and enable operation
;--------------------------------------------------------------------------
; INPUT : R7 = 4 bit data: 0000DDDD
; CY = 0:write, 1:read operation select
; OUTPUT : R7:data result if read operation is selected
; REG USED : A,R7
; NO-PUBLIC to C51
;==========================================================================
enable_lcd: MOV RW_LCD,C ; set r/w lcd
MOV A,PORT_LCD ; read old data port
ORL A,#0FH ; prepare D0..D3=1111 for read
; and prepare D4..D7 not changed
JC enable_lcd1 ; jump if read operation
ANL A,#0F0H ; masking bit, D4..D7 not change
; D0..D3 = 0000
ORL A,R7 ; ORing for 4 bit data
MOV PORT_LCD,A ; output to 4bit data lcd port
SJMP enable_lcd2
enable_lcd1: MOV PORT_LCD,A ; write data lcd
enable_lcd2: SETB E_LCD ; pulse for E lcd, now high logic
NOP ; for timing high logic
NOP ; total nop depend to crystal
NOP
NOP
NOP
NOP
NOP
NOP
MOV A,PORT_LCD ; no proble this operation for data lcd reading
NOP
NOP
NOP
NOP
CLR E_LCD ; e_lcd to low logic
JNC enable_lcd3 ; if write operation no 4bit data masking
ANL A,#0FH ; 4bit data masking
MOV R7,A ; return value for C51 language
enable_lcd3: RET
;==========================================================================
; BUSY_LCD : read busy lcd flag bit 7 from control lcd
;--------------------------------------------------------------------------
; INPUT : none
; OUTPUT : CY for busy lcd flag
; REG USED : A,B,R7
; NO-PUBLIC to C51
;==========================================================================
busy_lcd: SETB C ; read prepare
CLR RS_LCD ; select control address
CALL enable_lcd ; generated enable pulse
MOV B,R7 ; save 4bit return value D4..D7
CALL enable_lcd ; generated enable pulse
MOV A,B ; get value D4..D7
JB ACC.3,busy_lcd ; check busy lcd bit 7
RET ; for 4 bit interfacing is bit 3
;==========================================================================
; _RDCHAR_LCD : read char lcd from current cursor
;--------------------------------------------------------------------------
; INPUT : none
; OUTPUT : R7 = data ASCII char from current cursor lcd
; REG USED : A,B,R6,R7
;
; PUBLIC to C51
; C51 PROTYPE: extern char rdchar_lcd(void)
;==========================================================================
_rdchar_lcd: SETB C ; read prepare
SETB RS_LCD ; select data address
CALL enable_lcd ; generated enable pulse
SWAP A ; shift left 4 position to MSNyble
MOV B,A ; save
CALL enable_lcd ; generated enable pulse
ORL A,B ; joint to LSNyble data
MOV R6,A ; save 8bit data
CALL busy_lcd ; check busy lcd for high speed access
; because without delay routine
MOV R7,AR6 ; return value to C51 language
RET
;==========================================================================
; _WRCTL_LCD : write control lcd to perform clear_lcd, locate_lcd etc
;--------------------------------------------------------------------------
; INPUT : R7 = 8bit data to be writing to lcd as data control
; OUTPUT : none
; REG USED : A,B,R6,R7
;
; PUBLIC to C51
; C51 PROTYPE: extern void wrctl_lcd(char)
;==========================================================================
_wrctl_lcd: CLR C
CLR RS_LCD
SJMP _wrchar_lcd1
;==========================================================================
; _WRCHAR_LCD : write ascii char lcd to perform char display in current cur
;--------------------------------------------------------------------------
; INPUT : R7 = 8bit data to be writing to lcd as data ascii char
; OUTPUT : none
; REG USED : A,B,R6,R7
;
; PUBLIC to C51
; C51 PROTYPE: extern void wrchar_lcd(char)
;==========================================================================
_wrchar_lcd: CLR C
SETB RS_LCD
_wrchar_lcd1:
MOV R6,AR7
MOV A,R7
SWAP A
ANL A,#0FH
MOV R7,A
CALL enable_lcd
MOV A,R6
ANL A,#0FH
MOV R7,A
CALL enable_lcd
CALL busy_lcd
RET
;==========================================================================
; FOR USED FIRT POWER UP TO INITIALIZE LCD
; BECAUSE FOR THE FIRT POWER UP TIME, THE BUSY LCD FLAG CAN NOT READ
; IF YOU HAVE ANOTHER DELAY ROUTINE OUTSIDE THIS DRIVER,
; PLEASE WRITE: PUBLIC to the top line
;==========================================================================
delay_lcd: MOV R7,#0FFH
delay_lcd1: MOV R6,#0FFH
delay_lcd2: DEC R6
MOV A,R6
ORL A,#0
JNZ delay_lcd2
DJNZ R7,delay_lcd1
RET
;==========================================================================
;==========================================================================
; _WRSTR_LCD : write sequence ascci in memory until NULL char is reached
; The memory is free on all 8051 memory mapping as:
; idata, data, xdata, cdata and pdata
;
; This routine check Reg R3 to specify memory type.
; If 00H:idata/data 01H:xdata FFH:cdata FEH:pdata
;
; Automatic generic pointer configuration for C51 language interfacing
;--------------------------------------------------------------------------
; INPUT : R3 = memory type, R2 = MSB address, R1 = LSB address
; OUTPUT : none
; REG USED : A,B,R6,R7, R0 for pdata/idata/data, DPTR for cdata and xdata
;
; PUBLIC to C51
; C51 PROTYPE: extern void wrstr_lcd(char*)
;==========================================================================
_wrstr_lcd: CJNE R3,#0,_wrstr_lcd_xdata ; for idata memory
MOV R0,AR1
_wrstr_lcd_idata1:MOV A,@R0
ORL A,#0
JZ _wrstr_lcd_exit
MOV R7,A
CALL _wrchar_lcd
INC R0
SJMP _wrstr_lcd_idata1
_wrstr_lcd_xdata: CJNE R3,#1,_wrstr_lcd_cdata ; for xdata memory
MOV DPH,R2
MOV DPL,R1
_wrstr_lcd_xdata1:MOVX A,@DPTR
ORL A,#0
JZ _wrstr_lcd_exit
MOV R7,A
CALL _wrchar_lcd
INC DPTR
SJMP _wrstr_lcd_xdata1
_wrstr_lcd_cdata: CJNE R3,#0FFH,_wrstr_lcd_pdata ; for cdata memory
MOV DPH,R2
MOV DPL,R1
_wrstr_lcd_cdata1:CLR A
MOVC A,@A+DPTR
ORL A,#0
JZ _wrstr_lcd_exit
MOV R7,A
CALL _wrchar_lcd
INC DPTR
SJMP _wrstr_lcd_cdata1
_wrstr_lcd_pdata: CJNE R3,#0FEH,_wrstr_lcd_exit ; for external page memory
MOV R0,AR1
_wrstr_lcd_pdata1:MOVX A,@R0
ORL A,#0
JZ _wrstr_lcd_exit
MOV R7,A
CALL _wrchar_lcd
INC R0
SJMP _wrstr_lcd_pdata1
_wrstr_lcd_exit: RET
;==========================================================================
; CLR_LCD : clear all character in lcd, move to home cursor
;--------------------------------------------------------------------------
; INPUT : none
; OUTPUT : none
; REG USED : A,B,R7
;
; PUBLIC to C51
; C51 PROTYPE: extern void clr_lcd(void)
;==========================================================================
clr_lcd: MOV R7,#1
CALL _wrctl_lcd
RET
;==========================================================================
; CSRHOME_LCD : move cursor to home position
;--------------------------------------------------------------------------
; INPUT : none
; OUTPUT : none
; REG USED : A,B,R7
;
; PUBLIC to C51
; C51 PROTYPE: extern void csrhome_lcd(void)
;==========================================================================
csrhome_lcd: MOV R7,#2
CALL _wrctl_lcd
RET
;==========================================================================
; _LOCATE_LCD : move cursor to row,col
;--------------------------------------------------------------------------
; INPUT : R7 = row, R5 = col, 0 is the firt col/row
; OUTPUT : none
; REG USED : A,B,R7
;
; PUBLIC to C51
; C51 PROTYPE: extern void locate_lcd(char row, char col)
;==========================================================================
_locate_lcd: CJNE R7,#0,_locate_lcd1 ; row 0
MOV A,#80H
SJMP _locate_lcd4
_locate_lcd1: CJNE R7,#1,_locate_lcd2 ; row 1
MOV A,#0C0H
SJMP _locate_lcd4
_locate_lcd2: CJNE R7,#2,_locate_lcd3 ; row 2
MOV A,#94H
SJMP _locate_lcd4
_locate_lcd3: CJNE R7,#3,_locate_lcd5 ; row 3
MOV A,#0D4H
_locate_lcd4: ADD A,R5 ; add to col
MOV R7,A
CALL _wrctl_lcd
_locate_lcd5: RET
;==========================================================================
; OFF_LCD : off lcd display, all char not clear only no-display
;--------------------------------------------------------------------------
; INPUT : none
; OUTPUT : none
; REG USED : A,B,R7
;
; PUBLIC to C51
; C51 PROTYPE: extern void off_lcd(void)
;==========================================================================
off_lcd: MOV R7,#08H
SJMP on_lcd1
on_lcd: MOV R7,#0CH
on_lcd1: CALL _wrctl_lcd
RET
;==========================================================================
; OFF_LCD : setting lcd cursor to blink or/not/and cursor
;--------------------------------------------------------------------------
; INPUT : R7 = cursor 1:on 0:off
; R5 = blink 1:on 0:off
; OUTPUT : none
; REG USED : A,B,R7
;
; PUBLIC to C51
; C51 PROTYPE: extern void csrmode_lcd(char cursor, char blink)
;==========================================================================
_csrmode_lcd: MOV B,#0CH
MOV A,R7
JZ _csrmode_lcd1
INC B
INC B
_csrmode_lcd1: MOV A,R5
JZ _csrmode_lcd2
INC B
_csrmode_lcd2: MOV R7,B
CALL _wrctl_lcd
RET
;==========================================================================
; Initialize LCD for the first time on power up
;==========================================================================
init_lcd: MOV R7,#03H
CALL wrctl_lcd_4byte
CALL delay_lcd
MOV R7,#03H
CALL wrctl_lcd_4byte
CALL delay_lcd
MOV R7,#03H
CALL wrctl_lcd_4byte
MOV R7,#02H
CALL wrctl_lcd_4byte
MOV R7,#028H
CALL _wrctl_lcd
MOV R7,#0CH
CALL _wrctl_lcd
MOV R7,#01H
CALL _wrctl_lcd
MOV R7,#06H
CALL _wrctl_lcd
CALL delay_lcd
RET
;==========================================================================
END