I'm trying to get a PIC16F690 (mplab's PICKIT 2) to send characters to a 2x20 HD44780-based display. I've cobbled bits from various sources into an assembly program, but all I get is a row of black boxes across the first line.
The circuit is wired as follows: micro display RC0-RC7 pin 7-14 (DB0-DB7) RB4 pin 4 (RS) RB5 pin 5 (R/W) RB6 pin 6 (E)
I've run the mplab simulator on the code below, and it seems to put out the signals in the right order, but obviously the display does not agree on 'right'! ;)
Can anyone point me to where the problem lies? Is it a timing issue?
Code follows.
;=========================== ;display text on a HD44780-based LCD ;from a PIC16F690.
;Preset variables, state and I/O settings ;============================================================ #include __config (_INTRC_OSC_NOCLKOUT & _WDT_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _BOD_OFF & _IESO_OFF & _FCMEN_OFF)
; register declarations PORT_A EQU 0x05 PORT_B EQU 0x06 PORT_C EQU 0x07 TRIS_A EQU 0x85 TRIS_B EQU 0x86 TRIS_C EQU 0x87
STATUS EQU 0x03 RP0 EQU 0x05 LCD_DATA EQU PORT_C ; LCD data lines interface - PORT C LCD_DATA_TRIS EQU TRIS_C ; PORTC tristate register LCD_CTRL EQU PORT_B ; LCD control lines interface - PORT B
; PORTB control bits LCD_E EQU 6 ; LCD Enable control line LCD_RW EQU 5 ; LCD Read/Write control line LCD_RS EQU 4 ; LCD Register-Select control line W EQU 0 ; MOVF designator for W register
cblock 0x20 LCD_TEMP ; LCD subroutines internal use DELAY ; Used in DELAYxxx routines X_DELAY ; Used in X_DELAYxxx routines endc
org 0x000 goto START
;Initiate LCD communications LCDINIT ; Busy-flag is not yet valid CLRF LCD_CTRL ; ALL PORTB output should output Low. ; power-up delay MOVLW 0x1E CALL X_DELAY500 ; 30 * 0.5mS = 15mS ; Busy Flag should be valid from here MOVLW 0x3C ; 8-bit-interface, 2-lines CALL LCDPUTCMD MOVLW 0x08 ; disp.on, curs.off, no-blink CALL LCDDMODE CALL LCDCLEAR MOVLW 0x010 ; curs. move CALL LCDDMODE MOVLW 0x02 ; cursor home CALL LCDDMODE RETURN
;test LCD busy line LCDBUSY BSF STATUS, RP0 ; Select Register page 1 MOVLW b'11111111' ; Set PORTC for input - read the BUSY line MOVWF LCD_DATA_TRIS BCF STATUS, RP0 ; Select Register page 0 BCF LCD_CTRL, LCD_RS ; Set LCD for command mode BSF LCD_CTRL, LCD_RW ; Setup to read busy flag BSF LCD_CTRL, LCD_E ; LCD E-line High MOVF LCD_DATA, W ; Read busy flag + DDram address BCF LCD_CTRL, LCD_E ; LCD E-line Low ANDLW 0x80 ; Check Busy flag, High = Busy BTFSS STATUS, Z GOTO LCDBUSY LCDNOTBUSY BCF LCD_CTRL, LCD_RW BSF STATUS, RP0 ; Select Register page 1 MOVLW 0x00 MOVWF LCD_DATA_TRIS ; Set PORTC for output BCF STATUS, RP0 ; Select Register page 0 RETURN
; clear LCD display LCDCLEAR MOVLW 0x001 CALL LCDPUTCMD RETURN
;returns LCD cursor to home position LCDHOME MOVLW 0x002 CALL LCDPUTCMD RETURN
;- Sets display control ;- Required entry mode must be set in W ; b0 : 0 = cursor blink off, 1 = cursor blink on (if b1 = 1) ; b1 : 0 = cursor off, 1 = cursor on ; b2 : 0 = display off, 1 = display on (display data remains in DD-RAM) ; b3-b7 : don't care
LCDDMODE ANDLW 0x007 ; Strip upper bits IORLW 0x008 ; Function set CALL LCDPUTCMD RETURN
;set character generator RAM address LCDSCGA ANDLW 0x03F ; Strip upper bits IORLW 0x040 ; Function set CALL LCDPUTCMD RETURN
;set display data RAM address LCDSDDA IORLW 0x080 ; Function set CALL LCDPUTCMD RETURN
;get address counter contents LCDGADDR BSF STATUS,RP0 ; Select Register page 1 MOVLW b'11111111' ; Set PORTB for input MOVWF LCD_DATA_TRIS BCF STATUS, RP0 ; Select Register page 0 BCF LCD_CTRL, LCD_RS ; Set LCD for command mode BSF LCD_CTRL, LCD_RW ; Setup to read busy flag BSF LCD_CTRL, LCD_E ; LCD E-line High MOVF LCD_DATA, W ; Read busy flag + RAM address BCF LCD_CTRL, LCD_E ; LCD E-line Low ANDLW 0x07F ; Strip upper bit BCF LCD_CTRL, LCD_RW BSF STATUS, RP0 ; Select Register page 1 MOVLW 0x000 MOVWF LCD_DATA_TRIS ; Set PORTB for output BCF STATUS, RP0 ; Select Register page 0 RETURN
;send character to LCD ;- Sends character to LCD ;- Required character must be in W
LCDPUTCHAR MOVWF LCD_TEMP ; Character to send is in W CALL LCDBUSY ; Wait for LCD to be ready BCF LCD_CTRL, LCD_RW ; Set LCD in read mode BSF LCD_CTRL, LCD_RS ; Set LCD in data mode MOVF LCD_TEMP, W MOVWF LCD_DATA ; Send data to LCD BSF LCD_CTRL, LCD_E ; LCD E-line High for one cycle BCF LCD_CTRL, LCD_E ; LCD E-line Low RETURN
;send command to LCD ;- Sends command to LCD ;- Required command must be in W
LCDPUTCMD MOVWF LCD_TEMP ; Command to send is in W CALL LCDBUSY ; Wait for LCD to be ready BCF LCD_CTRL, LCD_RW ; Set LCD in read mode BCF LCD_CTRL, LCD_RS ; Set LCD in command mode MOVF LCD_TEMP, W MOVWF LCD_DATA ; Send data to LCD BSF LCD_CTRL, LCD_E ; LCD E-line High for one cycle BCF LCD_CTRL, LCD_E ; LCD E-line Low RETURN
;delay loop ;- Used in LCDINIT subroutine ;- Required delay factor must be in W ; (Could be coded more efficient, but this approach gives more flexibility)
;*********************************** a 500uS delay @ 4MHz X-tal DELAY500 MOVLW D'165' ; +1 1 cycle MOVWF DELAY ; +2 1 cycle DELAY500_LOOP DECFSZ DELAY, F ; step1 1 cycle GOTO DELAY500_LOOP ; step2 2 cycles DELAY500_END RETURN ; +3 2 cycles
;*********************************** a delay of 'W' * 500mS X_DELAY500 MOVWF X_DELAY ; +1 1 cycle X_DELAY500_LOOP CALL DELAY500 ; step1 wait 500uSec DECFSZ X_DELAY, F ; step2 1 cycle GOTO X_DELAY500_LOOP ; step3 2 cycles X_DELAY500_END RETURN ; +2 2 cycles
START call LCDINIT
;set LCD display mode MOVLW 0x004 ;cursor off, blink off, display on CALL LCDDMODE
;Send special user characters to LCD
;Send LCD opening screen(s) ;line 1 MOVLW 'M' CALL LCDPUTCHAR ; MOVLW 'y' ; CALL LCDPUTCHAR ; MOVLW ' ' ; CALL LCDPUTCHAR ; MOVLW 't' ; CALL LCDPUTCHAR ; MOVLW 'e' ; CALL LCDPUTCHAR ; MOVLW 'x' ; CALL LCDPUTCHAR ; MOVLW 't' ; CALL LCDPUTCHAR ; MOVLW ' ' ; CALL LCDPUTCHAR ; MOVLW 'h' ; CALL LCDPUTCHAR ; MOVLW 'e' ; CALL LCDPUTCHAR ; MOVLW 'r' ; CALL LCDPUTCHAR ; MOVLW 'e' ; CALL LCDPUTCHAR ; MOVLW '!' ; CALL LCDPUTCHAR
;line 2 ; MOVLW 'S' ; CALL LCDPUTCHAR ; MOVLW 'u' ; CALL LCDPUTCHAR ; MOVLW 'c' ; CALL LCDPUTCHAR ; MOVLW 'c' ; CALL LCDPUTCHAR ; MOVLW 'e' ; CALL LCDPUTCHAR ; MOVLW 's' ; CALL LCDPUTCHAR ; MOVLW 's' ; CALL LCDPUTCHAR ; MOVLW '!' ; CALL LCDPUTCHAR
goto $ END