ON 20030102@2:28:12 PM at page: http://www.piclist.com/techref/io/lcd/pic.htm JMN-EFP-786 James Newton added 'reply ' ON 20030102@2:28:49 PM at page: http://www.piclist.com/techref/io/lcd/pic.htm JMN-EFP-786 James Newton added 'reply ' ON 20030102@3:03:17 PM at page: http://www.piclist.com/techref/io/lcd/pic.htm JMN-EFP-786 James Newton added 'reply ' ON 20030102@3:30:23 PM at page: http://www.piclist.com/techref/io/lcd/pic.htm JMN-EFP-786 James Newton added 'reply The delay depends on the LCD.' ON 20030117@7:28:06 AM at page: http://piclist.com/techref/io/lcd/pic.htm JMN-EFP-786 James Newton published post 37638.1373032407 a.borowski@student.qut.edu.au shares this code:
http://alborowski.tk
Here's a driver for a standard 16 char by 2 line LCD that I wrote.

The driver sets the LCD up for 4 bit mode, and is write only. 
Hence only 6 I/O pins are used. Data lines 4-7 go to pins A0-A4,
and the Register Select and Enable lines can be chosen by the user
as long as they are on port B by saying something like

LCDEnable equ 3 ; The LCD enable pin on Port B
LCDRS equ 4; The LCD R/S pins on Port B

NOTE: This code presently uses a 14.7456 mhz crystal. To use a differeny xtal,
use the PIClist delay code generator to change the values of the delays. The
delay times are not that critical. 

To use this code, firstly set the relevent TRIS bits, then initialise the LCD:
 
	CALL LONGDLY
	CALL LCDFUN ; sets the LCD's function to 4 bit, 2 line, 5x7 font
        CALL LONGDLY 	
        CALL LCDDISP ; Turns on the display and cursor
        CALL LONGDLY
	CALL LCDENT ; sets auto increment right after write (like a typewriter)
        CALL LCDCLR

You know the LCD is initialized when iot is totally blank. If you get the one row
solid black and the other clear, the LCD has not been initialised properly.

Now, there are 2 ways to write to the LCD. Firstly, you can use the LCDChar method. This
is nice because it automatcally word wraps the text, and prevents you writing to non-
visible memory. For instance:

movlw "A"
movwf LCDByte
CALL LCDCHAR

To write different commands to the LCD, such as different function select bytes, 
set the relevent RS bit, put the data in LCDByte, then call LCDBYTE. This is only for the LCD gurus!

To change the address, call LCDADD

eg to go to address 3,

movlw 
movwf LCDadd
CALL LCDADD 

To clear the LCD, CALL LCDCLR. 
To 'backspace', CALL LCDBACKSPACE

If you need a hand, email me @ a.borowski@student.qut.edu.au
or visit my website at http://www.alborowski.tk



LCDADD ; makes LCDAdd the current LCD Address
	nop
	BCF PORTB,LCDRS
	movf LCDAdd, 0
	movwf LCDByte
	bsf LCDByte, 7
	CALL LCDBYTE
	bsf PORTB,LCDRS
	nop
	nop 
	RETURN

LCDENT ; Entry Mode set - currently set to move cursor to right after each write
	nop
	BCF PORTB, LCDRS
	movlw b'00000110'
	movwf LCDByte
	CALL LCDBYTE
	BSF PORTB,LCDRS
	nop
	nop
	RETURN

LCDDISP ; turns on display and cursor
	nop
	BCF PORTB,LCDRS
	movlw b'00001110'
	movwf LCDByte
	CALL LCDBYTE
	BSF PORTB,LCDRS
	nop
	nop
	RETURN

LCDFUN ; sets up the LCD function byte, for 4 bit control, 2 lines, standard font
	nop
	movlw d'2'
	movwf nibToSend
	BCF PORTB, LCDRS ; we're sending a command, so R/S must be lo
	CALL SENDNIB ; due to 4 bit operation, we have to resend the first nibble
	CALL SHORTDLY	
	movlw b'00101000'
	movwf LCDByte
	CALL LCDBYTE
	BSF PORTB, LCDRS
	nop
	nop
RETURN

LCDCLR ; clears the entire display
        clrf LCDAdd
	nop
	movlw d'1'
	movwf LCDByte 
	BCF PORTB, LCDRS ; 'cause we are doing a command, set the R/S line lo
	CALL LCDBYTE ; writes LCDByte to the LCD
	CALL LONGDLY ; Clearing the LCD takes ages, so a larger delay is needed
	bsf PORTB, LCDRS ; set the R/S line, ready for characters
	RETURN


LCDCHAR
       ;use this for displaying characters only, NOT control chars
       ;keeps track of cursor colation, and word wraps if necessary


movf LCDAdd, 0
sublw h'50'
btfsc STATUS, Z
RETURN
       CALL LCDBYTE



incf LCDAdd, 1
; check if we have hit the end of the top line
movlw d'16'
subwf LCDAdd, 0
btfsc STATUS, Z ; skip if not zero
GOTO LCDLINE2 ; must go to new line
RETURN

LCDLINE2


; here we must go to the new line
movlw b'01000000'
movwf LCDAdd
CALL LCDADD
RETURN



LCDBYTE; sends a byte to the LCD, in 4bit fashion
        ; responsible for breaking up the byte to send into high and low nibbles
	; and dumps them to LCD
	
	;NOT responsible for the status of the LCDRS line, nor the major delays

	; IN: LCDByte  - distructive OUT: hiByte, loByte

	clrf hiByte ; clears the vars, to prevent bugs
	clrf loByte
	bcf STATUS,0 ; get rif of any carry which could screw up the bitshifts
	rlf LCDByte, 1
	rlf hiByte
	rlf LCDByte, 1
	rlf hiByte
	rlf LCDByte, 1
	rlf hiByte
	rlf LCDByte, 1
	rlf hiByte
	movf LCDByte, 0
	movwf loByte
	swapf loByte, 1
    
	movf hiByte,0
	movwf nibToSend
	CALL SENDNIB
	movf loByte,0
	movwf nibToSend
	CALL SENDNIB
	CALL SHORTDLY ; blocks until most instructions are done
	RETURN


SENDNIB; responsible for sending nibble commands to the LCD. 
         ;IN: nibToSend - non-distructive
        
	clrf W ; clears W
	movf nibToSend, 0
        movwf PORTA
	nop
	bsf PORTB, LCDEnable; pulse the LCD Enable high
	nop
	nop
	bcf PORTB, LCDEnable ; lower LCD Enable
	nop
	nop
	RETURN
	


	
BIN2BHF
	; this command wil encode a byte into bastard hex format. In: BIN Out: BHF1,BHF2
	clrw
	clrf BHF1
	clrf BHF2
	bcf STATUS,0 ; get rid of any carry that could screw up the bitshift
	rrf BIN,1
	rrf BHF2,1	
	rrf BIN,1
	rrf BHF2,1
	rrf BIN,1
	rrf BHF2,1
	rrf BIN,1
	rrf BHF2,1
	swapf BHF2,1 ; fix up annoying bug	
	movf BIN, 0
	movwf BHF1 ; put BHF nibble in place
;Now, to enocde in ASCII
	movf BHF1, 0; put BHF1 into W for debugging
	movf BHF2,0 ; put BHF2 into W for debugging	
	movlw d'10' ; put 10 in W
	subwf BHF1, 0
	clrw ; W is cleared
	btfsc STATUS,0 ; test if we have a number or a letter - next command is skipped if we have a number
	addlw d'39'
	addlw d'48' ; subtract 10 for hex
	addwf BHF1,1
	movf BHF1,0 ; put BHF1 in W for debugging	
	;OK, BHF 1 is encoded
	bcf STATUS,0 ; clear any carry (as if that could make a difference)
	clrw ; Wipe W
	movf BHF2,0 ; put BHF2 into W for debugging
	movlw d'10' ; put 10 in W	
	subwf BHF2, 0
	clrw ; W is cleared
	btfsc STATUS,0 ; test if we have a number or a letter - next command is skipped if we have a number
	addlw d'39'
	addlw d'48' ; subtract 10 for hex
	addwf BHF2,1
	movf BHF2,0 ; put BHF2 in W for debugging
        RETURN

SHORTDLY ; around 50us


			;217 cycles
	movlw	0x48
	movwf	d1
SHORTDLY_0
	decfsz	d1, f
	goto	SHORTDLY_0

			;4 cycles (including call)
	return



LONGDLY ; 25ms delay

			;92153 cycles
	movlw	0xFE
	movwf	d1
	movlw	0x48
	movwf	d2
LONGDLY_0
	decfsz	d1, f
	goto	$+2
	decfsz	d2, f
	goto	LONGDLY_0

			;3 cycles
	goto	$+1
	nop

			;4 cycles (including call)
	return



LCDBACKSPACE ; acts like a backspace

movf LCDAdd,0
andlw b'11111111'
btfsc STATUS, Z ; skip if not zero
RETURN ; already at end, so ignore backspace

sublw h'40'
btfsc STATUS, Z ; skip if at start of 2nd line
GOTO LCDBSTARTBOTLINE ; correct for moveing up to new line
decf LCDAdd, 1;
CALL LCDADD ;         move back one
movlw d'32' ;         wipe the current char
movwf LCDByte
CALL LCDBYTE

CALL LCDADD
RETURN

LCDBSTARTBOTLINE ; correct for moveing up to new line
movlw d'15'
movwf LCDAdd
CALL LCDADD ; put us at 15
movlw d'32'
movwf LCDByte
CALL LCDBYTE

RETURN
|Delete 'P-' before: '' but after: 'sarigat@hotmail.com asks: " anyone know how to interface a 18F452 to a 16x2 LCD display " |Delete 'P-' before: '' but after: '