Maker Pro
Maker Pro

PIC16F690 and HD44780 display

R

Randy Day

Jan 1, 1970
0
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
 
Randy said:
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.

That means the lcd has not been initialised properly. You will get a
blank screen when youve done it right.
 
Randy said:
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.
<snip code>

I'm not a PIC guy but I have used displays with Motorola processors in
assembly language. The initialization is not difficult but must be done
as described in the data sheet on the processor. IIRC it was send a
start sequence, wait 20mS, send it again, wait 4.5mS, send again, etc.
If followed, it works just fine. The automatic hardware init never
worked for me but the 'programmed' init always did. I never used the
busy flag for comm as I just 'spread out' the data through the main run
loop. What's the point of waiting for a busy flag when there are other
tasks to be done?

I found a website for the 44780 that includes PIC code examples. Here
you go.

http://ouwehand.net/~peter/lcd/lcd2.shtml#PIC_lcd_init

GG
 
J

Joe McElvenney

Jan 1, 1970
0
Hi,

Have a look at -

http://www.oshonsoft.com/index.html


and audit Vladimir's PIC simulator program. You should be able
to fix your problem in the evaluation period as there are a lot of
LCD statements in his PIC BASIC. You can mix-in assembler code so
you can use most of what you've done. Whether you later purchase
it or not is up to you.

BTW, there is also a Yahoo Group.


Cheers - Joe
 
J

Joe McElvenney

Jan 1, 1970
0
Hi,

Sorry, his program doesn't support the 'F690 yet but that
wouldn't stop you looking at and disassembling the LCD statements.


Cheers - Joe, with egg on face :-(
 
J

Jan Wagner

Jan 1, 1970
0
Randy said:
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.
<snip>

Some thoughts...

You've LCDCLEAR near the end of LCDINIT, but LCDCLEAR takes a quite
long time to complete, during which nothing should be written to the
LCD otherwise it messes up. Instead of LCDCLEAR, you can write
spaces ' ' to the LCD lines, faster and IMO failsafer (at least in
my experience).

Second, try a first 8-bit mode set without busy flag checking, wait
over 4ms, then do a second 8-bit mode set.

Also, check that you haven't set LCD contrast wrong (wrong Vcc).

And add a test LED to a new I/O pin on the PIC, light the led if you
ever reach the end of LCDINIT to see if the busy flag reading really
works, and not that the LCD got stuck already before end of LCDINIT.

regards,
- Jan
 
R

Randy Day

Jan 1, 1970
0
I appreciate the replies I received, and I've tried
the suggestions, but still no letters on screen.

One thing I've noticed is that the debugger in MPLAB
is showing incorrect register values after
particular instructions. I can't work out if these
are being reflected in the .hex file or on-chip, but
it would certainly cause comm problems.

===========================================
Here's one:
bsf STATUS,RP0 ; select Register Page 1
movlw 0x3F
movwf TRIS_A ; Make PortA all input
clrf TRIS_C
bcf STATUS,RP0 ; select Register Page 0

1) TRIS_A shows 0x0F after the MOVWF, but since A
has RA0-RA5, shouldn't it show 0x3F?

2) TRISC has bits 6 and 7 high after the CLRF - why?

==========================================
Here's another:
; Busy Flag should be valid from here
MOVLW b'11111111'
CALL LCDPUTCMD

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 two cycles
NOP
BCF LCD_CTRL, LCD_E ; LCD E-line Low
RETURN

When the 'MOVWF LCD_DATA' command executes, the value
in LCD_TEMP (0xFF) should be sent to the LCD_DATA port
(PORTC in my case). What actually shows up at the port
is 0x30; it drops bits 0-3, 6 and 7!

I noticed this behavior when writing to the wrong bits
of a partial port, and that's expected, but on the
'690, port C is the one full 8-bit port ... isn't it?

Or is there something about this chip I need to know?
 
Top