FingerPrint Based Security System

Today, personal Safes are revolutionary locking storage cases that open with just the touch of your finger. These products are designed as secure storage for medications, jewelry, weapons, documents, and other valuable or
potentially harmful items.These utilize fingerprint recognition technology to allow access to only those whose fingerprints you choose. It contains all the necessary electronics to allow you to store, delete, and verify fingerprints with just the touch of a button. Stored fingerprints are retained even in the event of complete power failure or battery drain.These eliminates the need for keeping track of keys or remembering a combination password, or PIN. It can only be opened when an authorized user is present, since there are no keys or combinations to be copied or stolen, or locks that can be picked.

In this project the fingerprint module from Miaxis Biometrics is used. It can store up to 750 finger prints on its own memory. It can be controlled through its serial port.

The microcontroller AT89S52 interact with the module. You can Add a fingerprint, Delete a fingerprint and Identify the fingerprint.

To add a fingerprint, just show the finger on the module and press the ADD key. Now the microcontroller will send the ADD command to the module and the module will add it into the memory.
To delete the finger follow the same as above.

To identify the finger, press the Identify button and if the finger matches then the Relay is complemented.Also the fingerprint ID is displayed over the LCD display.

For more details about the Fingerprint module, please check the datasheet and you can get it from the datasheets page.



Circuit Diagram:




Code


RB0     EQU     00H    ; Select Register Bank 0
RB1     EQU     08H    ; Select Register Bank 1  ...poke to PSW to use
RB2     EQU     10H    ; Select Register Bank 1  ...poke to PSW to use

;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
; PORT DECLERATION
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 

; ***LCD CONTROL***
LCD_RS    EQU    P0.0     ;LCD REGISTER SELECT LINE
LCD_E     EQU    P0.1    ;LCD ENABLE LINE
LCD_DB4   EQU    P0.2     ;PORT 1 IS USED FOR DATA
LCD_DB5   EQU    P0.3     ;USED FOR DATA
LCD_DB6   EQU    P0.4    ;FOR DATA
LCD_DB7   EQU    P0.5     ;FOR DATA

SEARCH EQU P1.0
ADDS EQU P1.1
DELETE EQU P1.2

LOAD EQU P0.7
ALARM EQU P0.6


; ***CURSOR CONTROL INSTRUCTIONS***

OFFCUR    EQU    0CH
BLINKCUR  EQU    0DH

; ***DISPLAY CONTROL INSTRUCTIONS***

CLRDSP    EQU    01H
ONDSP     EQU    0CH

; ***SYSTEM INSTRUCTIONS***

CONFIG    EQU    28H      ; 4-BIT DATA,2 LINES,5X7 MATRIX LCD
ENTRYMODE EQU    6        ; INCREMENT CURSOR DON'T SHIFT DISPLAY 

    
DSEG            ; This is internal data memory
ORG     20H     ; Bit adressable memory
FLAGS1: DS 1
RECEIVED BIT FLAGS1.0

COUNTER: DS 1
BYTE: DS 10
TEMP: DS 1
TEMPS: DS 1
USER_COUNT: DS 1
ERROR_COUNT: DS 1
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CSEG            ; Code begins here
         
;  ---------==========----------==========---------=========---------
;  Main routine. Program execution starts here.
;  ---------==========----------==========---------=========---------
ORG     00H    ; Reset
AJMP MAIN
            
ORG 23H
JMP SERIAL 
;  ---------==========----------==========---------=========---------
MAIN:
         MOV    PSW,#RB0      ; Select register bank 0
MOV SP,#60h
MOV A,PCON
SETB ACC.7
MOV PCON,A
MOV TMOD,#20H
MOV TH1,#0FFH
MOV SCON,#50H
SETB ES
SETB EA
SETB TR1
SETB ADDS
SETB SEARCH
CLR LOAD
CLR ALARM
MOV ERROR_COUNT,#00H
;CHECK TO INITIALIZE THE USER COUNT IN FLASH MEMORY     
      CLR RECEIVED
      MOV DPTR,#READ_FLASH
      CALL SEND_SERIAL
      CALL DELAY
      MOV A,BYTE+4
      CJNE A,#0FFH,NOT_INT
      MOV DPTR,#STORE_FLASH
      CALL SEND_SERIAL
NOT_INT:    
CALL RESETLCD4
TOPS: CALL DISPLAY

  
      

TOP:
      JNB ADDS,ADD_USERS
      JNB SEARCH,SEARCH_USERS
      JNB DELETE,DELETE_USER
      AJMP TOP

SEARCH_USERS:
AJMP SEARCH_USER      
ADD_USERS:
AJMP ADD_USER
DELETE_USER:
JNB DELETE,$
CALL DISPLAY_DEL
CLR RECEIVED
MOV DPTR,#SEARCH_USER_DATA
      CALL SEND_SERIAL

CALL DELAYS
MOV A,BYTE+4
CJNE A,#39H,NOT_MATCHS
CALL FIN_MATCHED
MOV TEMP,BYTE+6
      CALL DELAYS
      CALL DELAYS
      
      
      MOV DPTR,#DEL_USER_DATA
      MOV TEMPS,#00H
      CALL SEND_SERIAL
      MOV SBUF,TEMP
      CALL TRANSDELAY
      MOV A,TEMPS
      ADD A,TEMP
      MOV SBUF,A
      CALL TRANSDELAY
      CALL DELAYS
     
      MOV A,BYTE+4
CJNE A,#31H,NOT_MATCHES
      CALL FIN_DELETED
      CALL DELAYS
      CALL DELAYS
      AJMP TOPS
NOT_MATCHES:
CALL NOT_DELETED
CALL DELAYS
      CALL DELAYS
      AJMP TOPS
NOT_MATCHS:
CALL NOT_MATCHED
CALL DELAYS
      CALL DELAYS
      AJMP TOPS
 
ADD_USER:
CALL DISPLAY1
CALL DELAYS
JNB ADDS,$
CLR RECEIVED
MOV DPTR,#SEARCH_USER_DATA
      CALL SEND_SERIAL

CALL DELAYS
MOV A,BYTE+4
CJNE A,#39H,NOT_MATCHSS
CALL ALREADY_EXIT
CALL DELAYS
      CALL DELAYS
      AJMP TOPS


NOT_MATCHSS:
CLR RECEIVED
MOV DPTR,#READ_FLASH ;LOAD USER COUNT FROM FLASH MEMORY
      CALL SEND_SERIAL
      CALL DELAY
  MOV A,BYTE+4
  MOV USER_COUNT,A
  CJNE A,#16,USER_NOT_FULL
  CALL USER_FULL_DISPLAY
  CALL DELAYS
  CALL DELAYS
  AJMP TOPS
 
USER_NOT_FULL:
      CLR RECEIVED
      MOV DPTR,#ADD_USER_DATA
      MOV TEMPS,#00H
      CALL SEND_SERIAL
      MOV SBUF,USER_COUNT
      CALL TRANSDELAY
      MOV A,TEMPS
      ADD A,USER_COUNT
      MOV SBUF,A
      CALL TRANSDELAY
NEXT: 
      CALL DELAYS
      CALL DELAYS
      JNB RECEIVED,$
      MOV A,BYTE+4
      CJNE A,#31H,NOT_SAVED
CALL DISPLAY_SUCESS
      CALL DELAYS
      CALL DELAYS
      CLR RECEIVED
      MOV DPTR,#STORE_FLASH
      MOV TEMPS,#00H
      CALL SEND_SERIAL
      INC USER_COUNT
      MOV SBUF,USER_COUNT
      CALL TRANSDELAY
      MOV A,TEMPS
      ADD A,USER_COUNT
      MOV SBUF,A
      CALL TRANSDELAY
      CLR RECEIVED
      AJMP TOPS

NOT_SAVED:
CALL DISPLAY_NOTSUCESS
      CALL DELAYS
      CALL DELAYS  
      CLR RECEIVED
      AJMP TOPS    

;$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
SEND_SERIAL:
CLR A
MOVC A,@A+DPTR      
CJNE A,#0FFH,SEND_D
RET
SEND_D:
MOV SBUF,A
ADD A, TEMPS
MOV TEMPS,A
CALL TRANSDELAY
INC DPTR
AJMP SEND_SERIAL
;$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
SEARCH_USER:
JNB SEARCH,$
CALL DISPLAY2
CLR RECEIVED
MOV DPTR,#SEARCH_USER_DATA
      CALL SEND_SERIAL

CALL DELAYS
MOV A,BYTE+4
CJNE A,#39H,NOT_MATCH
CPL LOAD
CLR ALARM
MOV ERROR_COUNT,#00H
CALL MATCHED
MOV TEMP,BYTE+6
      CALL SPLITDISP
      CALL DELAYS
      CALL DELAYS
      AJMP TOPS
NOT_MATCH:
INC ERROR_COUNT
MOV A,ERROR_COUNT
CJNE A,#04H,ALARM_ON
SETB ALARM
ALARM_ON:
CALL NOT_MATCHED
CALL DELAYS
      CALL DELAYS
      AJMP TOPS

SPLITDISP:
MOV A,TEMP
   
   
   
    mov   b,#10         ; Divide By 10
      div   ab         ; Do Divide
      swap   a         ; Move Result To High Of A
      orl   a,b         ; OR In Remainder
    
      
      MOV TEMP,A
      ANL A,#0F0H
      SWAP A
      ADD A,#30H
      MOV R4,A
      CALL WRLCDDATA
      CALL MDELAY
      
      MOV A,TEMP
      ANL A,#0FH
      ADD A,#30H
      MOV R4,A
      CALL WRLCDDATA
      CALL MDELAY
      MOV R4,#' '
      CALL WRLCDDATA
      CALL MDELAY
      RET


;---------==========----------==========---------=========---------      
ADD_USER_DATA:
DB 4DH, 58H, 10H, 03H, 40H, 00H, 0FFH

DB 4DH, 58H, 10H, 03H, 40H, 00H, 01H, 0F9H, 0FFH
;ADDRESS--------------------------^
SEARCH_USER_DATA:
DB 04DH, 58H, 10H, 05H, 44H, 00H, 00H, 00H, 0FEH, 0FCH, 0FFH       


STORE_FLASH:
DB 4DH, 58H, 10H, 05H, 64H, 00H, 00H, 01H, 0FFH 


DB 4DH, 58H, 10H, 05H, 64H, 00H, 00H, 01H, 00H, 1FH, 0FFH   
  
READ_FLASH:
DB 4DH, 58H, 10H, 04H, 62H, 00H, 00H, 01H, 1CH, 0FFH
;ADDRESS--------------------------^   
;COUNT---------------------------------^   

DEL_USER_DATA:
DB 4DH, 58H, 10H, 03H, 42H, 00H, 0FFH
;---------==========----------==========---------=========---------
SERIAL:
PUSH   PSW           ; save current registerset
MOV    PSW,#RB1
      PUSH   ACC
JB TI,TRANSD
MOV A,SBUF
CJNE A,#4DH,DOWN2 
MOV COUNTER,#01H 
JMP DDWN
TRANSD: AJMP TRANS
DOWN2:
MOV R1,COUNTER
CJNE R1,#01H,YH1
MOV BYTE,A
JMP DOWN1
YH1: CJNE R1,#02H,YH2
MOV BYTE+1,A
JMP DOWN1
YH2: CJNE R1,#03H,YH3
MOV BYTE+2,A
MOV TEMP,A
JMP DOWN1
YH3: CJNE R1,#04H,YH4
MOV BYTE+3,A
DEC TEMP
MOV A,TEMP
CJNE A,#00H,DOWN1
SETB RECEIVED
JMP DOWN1
YH4: CJNE R1,#05H,YH5
MOV BYTE+4,A
DEC TEMP
MOV A,TEMP
CJNE A,#00H,DOWN1
SETB RECEIVED
JMP DOWN1
YH5: CJNE R1,#06H,YH6
MOV BYTE+5,A
DEC TEMP
MOV A,TEMP
CJNE A,#00H,DOWN1
SETB RECEIVED
JMP DOWN1
YH6: CJNE R1,#07H,YH7
MOV BYTE+6,A
DEC TEMP
MOV A,TEMP
CJNE A,#00H,DOWN1
SETB RECEIVED
JMP DOWN1
YH7: CJNE R1,#08H,DOWN1
MOV BYTE+7,A
DEC TEMP
MOV A,TEMP
CJNE A,#00H,DOWN1
SETB RECEIVED
JMP DOWN1
DOWN1:INC COUNTER

DDWN: CLR RI
POP    ACC
    POP    PSW 
RETI
TRANS: CLR TI
POP    ACC
    POP    PSW 
RETI
;********************************************************** 
;**********************************************************    
TRANSDELAY:
MOV R7,#5FH
DJNZ R7,$
RET 
;************************************************************************** 
;##########################################################
; DISPLAY ROUTINES
;##########################################################
DISPLAY:
MOV DPTR,#MSAG1
CALL LCD_MSG
RET
MSAG1:
DB 1H,80H,'Fingerprint Based',0C0H,'Security System',00H
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
DISPLAY1:
MOV DPTR,#MSAG2
CALL LCD_MSG
RET
MSAG2:
DB 1H,83H,'Show your',0C0H,'Finger to ADD..',00H
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
DISPLAY2:
MOV DPTR,#MSAG3
CALL LCD_MSG
RET
MSAG3:
DB 1H,83H,'Show your',0C3H,'Finger....',00H
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
USER_FULL_DISPLAY:
MOV DPTR,#MSAG4
CALL LCD_MSG
RET
MSAG4:
DB 1H,83H,'User memory',0C3H,'## FULL ##',00H
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
DISPLAY_SUCESS:
MOV DPTR,#MSAG5
CALL LCD_MSG
RET
MSAG5:
DB 1H,83H,'User Added',0C3H,'Sucessfully',00H
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
DISPLAY_NOTSUCESS:
MOV DPTR,#MSAG6
CALL LCD_MSG
RET
MSAG6:
DB 1H,83H,'User Added',0C2H,'## Failed ##',00H
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MATCHED:
MOV DPTR,#MSAG7
CALL LCD_MSG
RET
MSAG7:
DB 1H,83H,'Fingerprint',0C1H,'Matched ID:',00H
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
NOT_MATCHED:
MOV DPTR,#MSAG8
CALL LCD_MSG
RET
MSAG8:
DB 1H,83H,'Fingerprint',0C2H,'NOT Matched',00H
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
DISPLAY_DEL:
MOV DPTR,#MSAG9
CALL LCD_MSG
RET
MSAG9:
DB 1H,83H,'Show your',0C0H,'Finger to DELETE',00H
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
FIN_MATCHED:
MOV DPTR,#MSAG10
CALL LCD_MSG
RET
MSAG10:
DB 1H,83H,'Fingerprint',0C4H,'Matched',00H
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
FIN_DELETED:
MOV DPTR,#MSAG11
CALL LCD_MSG
RET
MSAG11:
DB 1H,83H,'Fingerprint',0C1H,'## Deleted ##',00H
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
NOT_DELETED:
MOV DPTR,#MSAG12
CALL LCD_MSG
RET
MSAG12:
DB 1H,83H,'Fingerprint',0C2H,'NOT Deleted',00H
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALREADY_EXIT:
MOV DPTR,#MSAG13
CALL LCD_MSG
RET
MSAG13:
DB 1H,83H,'Fingerprint',0C1H,'Already Exits',00H
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
DELAY:
MOV R1,#0FFH
RE1: MOV R2,#0FFH
RE: NOP
DJNZ R2,RE
DJNZ R1,RE1
RET
;**********************************************************
DELAYS:                       ;One second delay routine
      MOV R0,#05H
RS3: MOV R1,#0FFH
RA1: MOV R2,#0FFH
RS2: NOP
DJNZ R2,RS2
DJNZ R1,RA1  
DJNZ R0,RS3  
  RET
;**********************************************************
DELAYSS:                       ;One second delay routine
      MOV R0,#03H
RE3: MOV R1,#0FFH
RZ1: MOV R2,#0FFH
RE2: NOP
DJNZ R2,RE2
DJNZ R1,RZ1  
DJNZ R0,RE3  
  RET
;**********************************************************
; INITIALIZE THE LCD 4-BIT MODE                                                                                   
;**********************************************************
INITLCD4:
         CLR         LCD_RS     ; LCD REGISTER SELECT LINE
         CLR         LCD_E      ; ENABLE LINE
         MOV         R4, #CONFIG; FUNCTION SET - DATA BITS,
                                ; LINES, FONTS
         CALL       WRLCDCOM4
         MOV         R4, #ONDSP ; DISPLAY ON
         CALL       WRLCDCOM4
         MOV         R4, #ENTRYMODE ; SET ENTRY MODE
         CALL       WRLCDCOM4  ; INCREMENT CURSOR RIGHT, NO SHIFT
         MOV         R4, #CLRDSP; CLEAR DISPLAY, HOME CURSOR
         CALL       WRLCDCOM4
         RET
; **********************************************************
; SOFTWARE VERSION OF THE POWER ON RESET
; **********************************************************
RESETLCD4:
         CLR         LCD_RS     ; LCD REGISTER SELECT LINE
         CLR         LCD_E      ; ENABLE LINE
         CLR         LCD_DB7    ; SET BIT PATTERN FOR...
         CLR         LCD_DB6    ; ... POWER-ON-RESET
         SETB        LCD_DB5
         SETB        LCD_DB4
         SETB        LCD_E      ; START ENABLE PULSE
         CLR         LCD_E      ; END ENABLE PULSE
         MOV         A, #4      ; DELAY 4 MILLISECONDS
         CALL       MDELAY
         SETB        LCD_E      ; START ENABLE PULSE
         CLR         LCD_E      ; END ENABLE PULSE
         MOV         A, #1      ; DELAY 1 MILLISECOND
         CALL       MDELAY
         SETB        LCD_E      ; START ENABLE PULSE
         CLR         LCD_E      ; END ENABLE PULSE
         MOV         A, #1      ; DELAY 1 MILLISECOND
         CALL       MDELAY
         CLR         LCD_DB4    ; SPECIFY 4-BIT OPERATION
         SETB        LCD_E      ; START ENABLE PULSE
         CLR         LCD_E      ; END ENABLE PULSE
         MOV         A, #1      ; DELAY 1 MILLISECOND
         CALL       MDELAY
         MOV         R4, #CONFIG; FUNCTION SET
         CALL       WRLCDCOM4
         MOV         R4, #08H   ; DISPLAY OFF
         CALL       WRLCDCOM4
         MOV         R4, #1     ; CLEAR DISPLAY, HOME CURSOR
         CALL       WRLCDCOM4
         MOV         R4,#ENTRYMODE  ; SET ENTRY MODE
         ACALL       WRLCDCOM4
    JMP INITLCD4

; **********************************************************
; SUB RECEIVES A COMMAND WORD TO THE LCD
; COMMAND MUST BE PLACED IN R4 BY CALLING PROGRAM
; **********************************************************
WRLCDCOM4:
         CLR         LCD_E
         CLR         LCD_RS     ; SELECT READ COMMAND
         PUSH        ACC        ; SAVE ACCUMULATOR
         MOV         A, R4      ; PUT DATA BYTE IN ACC
         MOV         C, ACC.4   ; LOAD HIGH NIBBLE ON DATA BUS
         MOV         LCD_DB4, C ; ONE BIT AT A TIME USING...
         MOV         C, ACC.5   ; BIT MOVE OPERATOINS
         MOV         LCD_DB5, C
         MOV         C, ACC.6
         MOV         LCD_DB6, C
         MOV         C, ACC.7
         MOV         LCD_DB7, C
         SETB        LCD_E      ; PULSE THE ENABLE LINE
         CLR         LCD_E
         MOV         C, ACC.0   ; SIMILARLY, LOAD LOW NIBBLE
         MOV         LCD_DB4, C
         MOV         C, ACC.1
         MOV         LCD_DB5, C
         MOV         C, ACC.2
         MOV         LCD_DB6, C
         MOV         C, ACC.3
         MOV         LCD_DB7, C
         CLR         LCD_E
         SETB        LCD_E      ; PULSE THE ENABLE LINE
         CLR         LCD_E
         CALL MADELAY
         POP         ACC
         RET
; **********************************************************
; SUB TO RECEIVE A DATA WORD TO THE LCD
; DATA MUST BE PLACED IN R4 BY CALLING PROGRAM
; **********************************************************
WRLCDDATA:
         CLR         LCD_E
         SETB        LCD_RS     ; SELECT READ DATA
             PUSH        ACC        ; SAVE ACCUMULATOR
         MOV         A, R4      ; PUT DATA BYTE IN ACC
         MOV         C, ACC.4   ; LOAD HIGH NIBBLE ON DATA BUS
         MOV         LCD_DB4, C ; ONE BIT AT A TIME USING...
         MOV         C, ACC.5   ; BIT MOVE OPERATOINS
         MOV         LCD_DB5, C
         MOV         C, ACC.6
         MOV         LCD_DB6, C
         MOV         C, ACC.7
         MOV         LCD_DB7, C
         SETB        LCD_E      ; PULSE THE ENABLE LINE
         CLR         LCD_E
         MOV         C, ACC.0   ; SIMILARLY, LOAD LOW NIBBLE
         MOV         LCD_DB4, C
         MOV         C, ACC.1
         MOV         LCD_DB5, C
         MOV         C, ACC.2
         MOV         LCD_DB6, C
         MOV         C, ACC.3
         MOV         LCD_DB7, C
         CLR         LCD_E
         SETB        LCD_E      ; PULSE THE ENABLE LINE
         CLR         LCD_E
         NOP
         NOP
         POP         ACC
         RET

; **********************************************************
; SUB TAKES THE STRING IMMEDIATELY FOLLOWING THE CALL AND
; DISPLAYS ON THE LCD. STRING MUST BE TERMINATED WITH A
; NULL (0).
; **********************************************************
LCD_MSG:
CLR A ; Clear Index 
MOVC A,@A+DPTR ; Get byte pointed by Dptr 
INC DPTR ; Point to the next byte 
JZ LCD_Msg9 ; Return if found the zero (end of stringz) 
        CJNE A,#01H,Lcd_Msg1 ; Check if is a Clear Command 
MOV R4,A
CALL WRLCDCOM4       ;If yes, RECEIVE it as command to LCD 
JMP   LCD_MSG           ;Go get next byte from stringz 
                              
Lcd_Msg1: CJNE A,#0FFH,FLL ;Check for displaying full character
MOV R4,A
CALL WRLCDDATA
JMP LCD_MSG
 FLL: CJNE  A,#080h,$+3       ; Data or Address?  If => 80h then is address. 
JC    Lcd_Msg_Data     ; Carry will be set if A < 80h (Data) 
MOV R4,A
CALL  WRLCDCOM4         ; Carry not set if A=>80, it is address 
JMP Lcd_Msg           ; Go get next byte from stringz 
                             
Lcd_Msg_Data:                   ; 
MOV R4,A
CALL WRLCDDATA         ; It was data, RECEIVE it to Lcd 
JMP  Lcd_Msg           ; Go get next byte from stringz 
Lcd_Msg9: 
RET                     ; Return to Caller 

; **********************************************************
; 1 MILLISECOND DELAY ROUTINE
; **********************************************************

MDELAY:
         PUSH        ACC
         MOV         A,#0A6H
MD_OLP:
         INC         A
         NOP
         NOP
         NOP
         NOP
         NOP
         NOP
         NOP
         NOP
         JNZ         MD_OLP
         NOP
         POP         ACC
         RET
MADELAY:
         PUSH        ACC
         MOV         A,#036H
MAD_OLP:
         INC         A
         NOP
         NOP
         NOP
         NOP
         NOP
         NOP
         NOP
         NOP
         JNZ         MAD_OLP
         NOP
         POP         ACC
         RET

END