PIC 4 bit 16x2 Hitachi 44780 LCD driver

by Anonymous


NEW! 416028

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 3
	movwf LCDadd
	CALL LCDADD 

To clear the LCD,

	CALL LCDCLR. 
To 'backspace',
	CALL LCDBACKSPACE


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
	

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

Interested:

See:

Questions:

Comments: