; (This code is not mine, except for the delays, I just added this comments)
;
;Connection is like this:
;
; PIC       LCD
; -------------
; RBO       E
; RB1       RS
; RB2       RW
; RB3       --
; RB4       D4
; RB5       D5
; RB6       D6
; RB7       D7
;
; (RB0-RB7: PIC PINS 6-13 RESPECTIVELY)
; (E, RS, RW, D4-D7: LCD PINS 6, 4, 7, 10-14 RESPECTIVELY)
;
; MAKE SURE YOU CONNECT THE CONTRAST POT (10K) TO PIN 3
; POWER IS 1: GND, 2: +5V
; 
; 
; the subroutine DELAY seems to be the same as DELAY_MS, at least it works if you change all 'delay' to 'delay_ms'
; here's the Q&D delay I use (1ms for 4MHz XT):
;
;
; delays
	cblock 0x0D
	d1
	d2
	bit_tmp
	msres
	endc
	
delay_ms
	movwf msres
dl3	decfsz msres, f
	goto dl
	return
dl			;993 cycles
	movlw	0xC6
	movwf	d1
	movlw	0x01
	movwf	d2
delay_ms_0
	decfsz	d1, f
	goto	$+2
	decfsz	d2, f
	goto	delay_ms_0

			;3 cycles
	nop
	goto	dl3

;lcd routines


	cblock	0x2A
		lcd_shadow,lcd_tmp,lcda,lcd_char
	endc


#define lcd_port	PORTB
#define lcd_enable	lcd_shadow,0
#define	lcd_rs		lcd_shadow,1
#define	lcd_rw		lcd_shadow,2



;------------------------------
lcd_uport macro
	movf	lcd_shadow,w
	movwf	lcd_port
	endm



;------------------------------
;strobe lcd enable
lcd_strobe:
	movlw	.20
	call	delay
	bsf	lcd_enable
	lcd_uport
	movlw	.20
	call	delay

	movf	lcd_port,w
	andlw	0xF0
	movwf	lcd_tmp

	bcf	lcd_enable
	lcd_uport
	swapf	lcd_tmp,w
	return



;------------------------------
lcd_send_nibble:
	movwf	lcd_tmp
	movlw	0x0F
	andwf	lcd_tmp,f
	andwf	lcd_shadow,f

	swapf	lcd_tmp,w
	iorwf	lcd_shadow,f
	lcd_uport

	goto	lcd_strobe
	



;------------------------------
lcd_read_byte:
	movlw	0xF0
	tris	lcd_port
	bsf	lcd_rw

	lcd_uport
	call	lcd_strobe
	movwf	lcda
	swapf	lcda,f	
	call	lcd_strobe
	iorwf	lcda,f

	movlw	0
	tris	lcd_port

	bcf	lcd_rw
	movf	lcda,w
	return



;------------------------------
#define	sv_addr		bit_tmp,0

lcd_putc:
	bsf	lcd_rs

lcd_send_byte:
	movwf	lcd_char		
	bcf	sv_addr
	btfsc	lcd_rs
	 bsf	sv_addr

	bcf	lcd_rs
sb0	call	lcd_read_byte		;wait until not lcd busy
	andlw	B'10000000'
	skpz
	 goto	sb0

	bcf	lcd_rw	
	bcf	lcd_rs
	btfsc	sv_addr
	 bsf	lcd_rs

	swapf	lcd_char,w
	call	lcd_send_nibble	
	movf	lcd_char,w
	goto	lcd_send_nibble	



;------------------------------
lcd_init:
	movlw	0
	tris	lcd_port

	clrf	lcd_shadow
	lcd_uport
	
	movlw	.50
	call	delay_ms

	movlw	3
	movwf	lcda
	bcf	lcd_rs
lcdi0	movlw	3
	call	lcd_send_nibble
	movlw	.15
	call	delay_ms
	decfsz	lcda,f
	 goto	lcdi0

        movlw   .2
	call	lcd_send_nibble

	movlw	B'00101000'		;function set
	call	lcd_send_byte		;4 bit,1/6 duty,5x8

	movlw	B'00001000'		;display off,cursor off, blink off
	call	lcd_send_byte

        movlw   B'00000001'		;clear screen cursor home
	call	lcd_send_byte

	movlw	B'00000110'		;Increment cursor, don't shift screen
	call	lcd_send_byte

	movlw	B'00001111'		;display on,cursor on, blink on
	call	lcd_send_byte

	return



;------------------------------
;lcd_gotoxy
;   input W = YYXXXXXX
;             76543210
;
;       Y    address
;      ---   -------
;       00    0
;       01    0x40
;       10    20 
;       11    0x40+20

xy_loc	macro	x, y
	movlw	(y << 6) | (x & B'00111111')
	call	lcd_gotoxy
	endm

lcd_gotoxy:
	movwf	lcd_tmp
	andlw	B'00111111'

	btfsc	lcd_tmp,6
	 addlw	0x40

	btfsc	lcd_tmp,7
	 addlw	.20

	iorlw	B'10000000'
	bcf	lcd_rs
	goto	lcd_send_byte



;------------------------------
lcd_cursor_off:
	bcf	lcd_rs
	movlw	B'00001100'		;display on,cursor off, blink off
	goto	lcd_send_byte



;------------------------------
lcd_cursor_on:
	bcf	lcd_rs
	movlw	B'00001111'		;display on,cursor on, blink on
	goto	lcd_send_byte


