;------------------------------------------------------------------ ; 4 Bit HD44780 LCD driver ;------------------------------------------------------------------ ; ; ifdef LCD8x2 ; ; 8 character x 2 line display ; (may be physically arranged as 16x1) ; #DEFINE LCDLENGTH 8 #DEFINE LCDLINE2 0x40 ; else ; ; 16 character x 2 line display ; #DEFINE LCDLENGTH 16 #DEFINE LCDLINE2 0x40 ; endif ; ; ; 8 level voltage divider ; ;#DEFINE LCD8L ; ; LCD Port pin assignments ; ; 6 pins used (any 6 pins, any port(s), any order) ; Change bit assigns to suit your wiring! ; ;#DEFINE LCD_D7 = PORTB,0 ;#DEFINE LCD_D6 = PORTB,1 ;#DEFINE LCD_D5 = PORTB,2 ;#DEFINE LCD_D4 = PORTB,3 ;#DEFINE LCD_E = PORTB,4 ;#DEFINE LCD_RS = PORTB,5 ; ; Variables used by the LCD routines ; BYTE lcd_char ; ASCII character to send BYTE lcd_dat ; data/instruction byte to send BYTE sd_loop ; short delay counter BYTE ld_loop_in ; long delay inner counter BYTE ld_loop_ex ; long delay outer counter BYTE lcd_address ; cursor address in LCD RAM ; ; output high nybble of LCD data ; lcd_hi: bsf LCD_D7 btfss lcd_dat,7 bcf LCD_D7 bsf LCD_D6 btfss lcd_dat,6 bcf LCD_D6 bsf LCD_D5 btfss lcd_dat,5 bcf LCD_D5 bsf LCD_D4 btfss lcd_dat,4 bcf LCD_D4 RETURN ; ; output low nybble of LCD data ; lcd_lo: bsf LCD_D7 btfss lcd_dat,3 bcf LCD_D7 bsf LCD_D6 btfss lcd_dat,2 bcf LCD_D6 bsf LCD_D5 btfss lcd_dat,1 bcf LCD_D5 bsf LCD_D4 btfss lcd_dat,0 bcf LCD_D4 RETURN ;------------------------------------------------------------------- ; Initialise the LCD Display ; ; LCDinit: call set_4bit_mode call display_on goto Clear_Display ;------------------------------------------------------------------- ; Set LCD Controller to 4 bit Mode ; ; The LCD controller starts in 8 bit mode. We have to set it to ; 4 bit mode using only 4 bits! The bits for "Display lines" and ; "Character Font" are the lower nybble which we cannot send in ; 8 bit mode, so the command has to be repeated in 4 bit mode. ; set_4bit_mode: movlw B'00101000' movwf lcd_dat call lcd_hi ; upper nybble only! bcf LCD_RS bsf LCD_E nop ; send "Function Set" in 8 bit mode bcf LCD_E call wait100 ; now in 4 bit mode movlw B'00101000' call LCDinst ; send "Function Set" in 4 bit mode movlw B'10001000' goto LCDinst ; send "Entry Mode Set" ;------------------------------------------------------------------ ; Send Instruction Byte to LCD ; ; Input: W = instruction byte ; LCDinst: bcf LCD_RS goto LCD_write ;------------------------------------------------------------------ ; Send Data Byte to LCD ; ; Input: W = data byte ; LCDdata: incf lcd_address ; update cursor position bsf LCD_RS LCD_write: movwf lcd_dat call lcd_hi bsf LCD_E nop bcf LCD_E call lcd_lo bsf LCD_E nop bcf LCD_E goto wait100 ; wait 100uS ;------------------------------------------------------------------ ; Clear the Display ; Clear_Display: clrf lcd_address ; cursor home movlw b'00000001' ; "Clear Display" command call LCDinst goto wait4000 ; Wait 4mS ;------------------------------------------------------------------- ; Turn the Display ON ; display_on: movlw B'00001100' ; Display ON, cursor OFF, blink OFF goto LCDinst ;------------------------------------------------------------------- ; Position Cursor in Display RAM ; ; Input: W = address ; Set_Cursor: movwf lcd_address iorlw b'10000000' goto LCDinst ;--------------------------------------------------- ; Show an ASCII Character on the LCD ; ; Input: W = character ; Print_Char: goto LCDdata ;--------------------------------------------------- ; Wait for 100uS ;--------------------------------------------------- wait100: movlw (100-4)/4 ;--------------------------------------------------- ; Short Delay ;--------------------------------------------------- ; Input: W = delay ; ; Output: waits for (W*4)+4 cycles ; waitx4: movwf sd_loop sd_loops: decf sd_loop,F ; skpz ; 4 cycles goto sd_loops ; RETURN wait4000: movlw (4000/250) ;---------------------------------------------------- ; Long Delay ;---------------------------------------------------- ; Input: W = delay ; ; Output: waits for (w*250)+4 cycles ; waitx250: movwf ld_loop_ex ld_loopex: movlw (250-4)/4 movwf ld_loop_in ld_loopin: decf ld_loop_in,F skpz goto ld_loopin decf ld_loop_ex,F skpz goto ld_loopex RETURN