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:
Hi,
I have several questions.
1. The call routines at the beginning, their place in the main code or the .inc file?
2. LCDByte is different than loByte & hiByte, right?
3. loByte & hiByte are defined to "Byte" GPR, and you call the low and high nibbles, correct?
Comments: