;------------------------------------------------------------------------------------------------------------------------
; Source code for the PIC16F873A interfacing with LCD.
;------------------------------------------------------------------------------------------------------------------------
;	**LCD Pinouts
;	1	Vss -	Ground, 3rd pin of the potentiometer
;  	2	Vcc	-	5V DC, 1st pin of the potentiometer
;  	3 	Vee	-	Middle pin of the potentiometer
;  	4 	RS	-	RB0		(Data - 1, Instruction - 0)
;  	5 	R/W	-	RB1		(R - 1, W - 0)
;	6 	E	-	RB2		(Enable Pulse)
;	7 	DB0	-	RC0		(LSB)
;	8 	DB1	-	RC1
;	9 	DB2	-	RC2
; 	10	DB3	-	RC3		(Lower 4 bits)
; 	11	DB4 -	RC4		(Upper 4 bits)
; 	12	DB5	-	RC5
; 	13	DB6	-	RC6
; 	14	DB7	-	RC7		(MSB)
;
;	Instruction Cycle Time = 1 / (4MHz / 4) = 1us per instruction
;------------------------------------------------------------------------------------------------------------------------

		LIST P=16F873A           
		INCLUDE "p16f873A.inc"   
		ERRORLEVEL -302        
		__CONFIG _PWRTE_OFF & _XT_OSC & _WDT_OFF & _WRT_OFF & _LVP_OFF & _BODEN_OFF;  configuration switches

N 			EQU 0x2E
FIXDELAY	EQU 0x2F

		ORG 0x00
		GOTO START

START	clrf PORTB
		clrf PORTC
		movlw 0x00

		banksel TRISB
		movwf TRISB

		banksel TRISC
		movwf TRISC
		
		call INITLCD

MAIN	movlw A'H'
		call PUTCHAR
		movlw A'E'
		call PUTCHAR
		movlw A'L'
		call PUTCHAR
		movlw A'L'
		call PUTCHAR
		movlw A'O'
		call PUTCHAR
		movlw A'!'
		call PUTCHAR

FOREVER	goto $

;**********************************************************************************************
; Initialize the LCD.
;**********************************************************************************************

INITLCD		
			BANKSEL PORTB		; Select Bank for PORTB.

			MOVLW	0xE6		; Call for 46ms delay
			CALL 	NDELAY		; Wait for VCC of the LCD to reach 5V
			
			BCF		PORTB, 0	; Clear RS to select Instruction Reg.
			BCF		PORTB, 1	; Clear R/W to write
		
			MOVLW	B'00111011'	; Function Set to 8 bits, 2 lines and 5x7 dot matrix
			MOVWF 	PORTC
			CALL	ENABLEPULSE
			CALL	ENABLEPULSE
			CALL	ENABLEPULSE
			CALL	DELAY50		; Call 50us delay and wait for instruction completion

			MOVLW	B'00001000'	; Display OFF
			MOVWF	PORTC
			CALL	ENABLEPULSE
			CALL	DELAY50		; Call 50us delay and wait for instruction completion

			MOVLW	B'00000001'	; Clear Display
			MOVWF	PORTC
			CALL	ENABLEPULSE
			MOVLW	0x09		; Call 1.8ms delay and wait for instruction completion				
			CALL	NDELAY		

			MOVLW	B'00000010'	; Cursor Home
			MOVWF	PORTC
			CALL	ENABLEPULSE
			MOVLW	0x09		; Call 1.8ms delay and wait for instruction completion				
			CALL	NDELAY
		
			MOVLW	B'00001100'	; Display ON, Cursor OFF, Blinking OFF
			MOVWF	PORTC
			CALL	ENABLEPULSE
			CALL	DELAY50		; Call 50us delay and wait for instruction completion

			MOVLW 	B'00000110'	; Entry Mode Set, Increment & No display shift
			MOVWF	PORTC
			CALL	ENABLEPULSE
			CALL	DELAY50		; Call 50us delay and wait for instruction completion

			BSF		PORTB, 0	; Set RS to select Data Reg.
			BCF		PORTB, 1	; Clear R/W to write

			RETURN

;**********************************************************************************************
; Enable Pulse for writing or reading instructions or data
;**********************************************************************************************

ENABLEPULSE	BCF	PORTB, 2
			CALL DELAY50
			BSF	PORTB, 2	; 50us E-Pulse
			CALL DELAY50
			BCF PORTB, 2
			RETURN

;**********************************************************************************************
; N DELAY SUBROUTINE, delay in multiples of 200us up to 200us*255 = 51ms (or more)
;**********************************************************************************************

NDELAY
			MOVWF N				; N is delay multiplier
NOTOVER		CALL DELAY200		; Call for 200us
			DECFSZ N, 1			; Decrease N by 1
			GOTO NOTOVER		; The delay isn't done
			RETURN
	
;**********************************************************************************************
; FIXED 200us DELAY (Possibly more due to execution time of the DECFSZ instruction.)
;**********************************************************************************************

DELAY200	
			MOVLW 0x42			; 66 LOOPS
			MOVWF FIXDELAY		; 200us fixed delay
NOTDONE200	DECFSZ FIXDELAY, 1 	; Decrement of FIXDELAY
			GOTO NOTDONE200		; If 200us isn't up go back to NOTDONE200
			RETURN				; If 200us is up then return to instruction.

;**********************************************************************************************
; FIXED 50us DELAY (Possibly more due to execution time of the DECFSZ instruction.)
;**********************************************************************************************

DELAY50	
			MOVLW 0x10			; 16 LOOPS
			MOVWF FIXDELAY		; 50us fixed delay
NOTDONE50	DECFSZ FIXDELAY, 1 	; Decrement of FIXDELAY
			GOTO NOTDONE50		; If 50us isn't up go back to NOTDONE50
			RETURN				; If 50us is up then return to instruction.

;**********************************************************************************************
; Fast Directive to write characters to LCD.
;**********************************************************************************************

PUTCHAR
			MOVWF PORTC			; A quicker way of writing characters to LCD.
			CALL ENABLEPULSE
			CALL DELAY50
			RETURN

			end
