R
Randy Day
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 <p16F690.inc>
__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
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 <p16F690.inc>
__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