# PIC16f690 interfacing with LCD 16x2

#### andyv

Joined Apr 6, 2010
5
Hi all,

I'm just starting out in the world of microcontrollers, and the microchip pic was recommended to me, along with 'PIC in practice' book by D W Smith.

I have pretty much covered everything in the book, at times with difficulty due to my minute budget. I have been using the PICkit 2 that comes with a PIC16F690, and many will confirm has hidden problebs, such as recognising switch inputs.

My latest issue is interfacing with an 16x2 LCD alfanumeric display. I have come up with the following .asm code from sources off the internet and also the PIC in practice book.

I am using a Displaytech display from RS- 532-6442
Rich (BB code):
;*********************************************************
; EQUATES SECTION
#include <p16F690.inc>
DELAY1  EQU 21h
DELAY2  EQU 22h
DISPLAY  EQU 23h
COUNT  EQU 34h

;**********************************************************************
; Configuration Bits
__config (_INTRC_OSC_NOCLKOUT & _WDT_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _BOR_OFF & _IESO_OFF & _FCMEN_OFF)
org 0
;*********************************************************
;CONFIGURATION SECTION
Start:
bsf  STATUS,RP0    ;select Register Page 1
clrf TRISC             ;make make port C outputs
CLRF TRISA
bcf  STATUS,RP0    ;back to Register Page 0
bsf  STATUS,RP1    ;page 2
bcf  STATUS,RP1    ;back to page 0
CLRF PORTA
CLRF PORTC

;Display Configuration
MOVLW 03h
MOVWF PORTC  ;8 BIT DATA
CALL  CLOCK
CALL  DELAY
MOVLW 02h
MOVWF PORTC  ;CHANGE TO 4BIT
CALL CLOCK
CALL DELAY
MOVLW 0h
MOVWF PORTC  ;REPAET COMMAND
CALL DELAY
MOVLW 08h
MOVWF PORTC  ;2 LINE DISPLAY
CALL DELAY
MOVLW 0h
MOVWF PORTC  ;DISPLAY ON CURSOR OFF
CALL CLOCK
MOVLW 0Ch
MOVWF PORTC
CALL CLOCK
CALL DELAY
MOVLW 0h
MOVWF PORTC  ;INCREMENT CURSOR
CALL CLOCK
MOVLW 6h
MOVWF PORTC
CALL CLOCK

MOVLW .8
MOVWF DISPLAY
;*********************************************************
;Program starts now.

HELLO_WORLD
CALL CLRDISP
CLRF PORTA
MOVLW 8h   ;CURSOR AT TOP LEFT,80h
MOVWF PORTC
CALL CLOCK
MOVLW 0h
MOVWF PORTC
CALL  CLOCK
BSF  PORTA,0
CALL  H
CALL DELAY
CALL E
CALL DELAY
CALL  L
CALL DELAY
CALL L
CALL DELAY
CALL  O
CALL DELAY
CALL GAP
CALL DELAY
CALL  W
CALL DELAY
CALL O
CALL DELAY
CALL  R
CALL DELAY
CALL L
CALL DELAY
CALL  D
CALL DELAY
CALL DELAY3S
GOTO  HELLO_WORLD

;*********************************************************
;SUBROUTINE SECTION.
;1MS DELAY

DELAY
DECFSZ    DELAY1,f             ; Waste time.
GOTO      DELAY        ; The Inner loop takes 3 instructions per loop *
256 loopss = 768 instructions
DECFSZ    DELAY2,f             ; The outer loop takes and additional 3
instructions per lap * 256 loops
GOTO      DELAY          ; (768+3) * 256 = 197376 instructions / 1M
instructions per second = 0.197 sec.
; call it a two-tenths of a second.
RETLW  0

DELAY1S
MOVLW .10
MOVWF COUNT
LOOP
CALL DELAY
DECFSZ COUNT
GOTO LOOP
RETLW 0

DELAY3S
MOVLW .30
MOVWF COUNT
LOOP1
CALL DELAY
DECFSZ COUNT
GOTO LOOP1
RETLW 0

CLOCK
BSF  PORTA,2
NOP
BCF  PORTA,2
NOP
RETLW 0

;***********************************************************************
;
;HELLO WORLD

A  MOVLW .1  ;Enables Display
MOVWF PORTA
MOVLW 3h  ;First part of byte (31h)
MOVWF PORTC
CALL CLOCK
MOVLW 1h
MOVWF PORTC
CALL CLOCK
RETLW 0

H  MOVLW .1  ;Enables Display
MOVWF PORTA
MOVLW 3h  ;First part of byte (38h)
MOVWF PORTC
CALL CLOCK
MOVLW 8h
MOVWF PORTC
CALL CLOCK
RETLW 0

E  MOVLW .1  ;Enables Display
MOVWF PORTA
MOVLW 3h  ;First part of byte (35h)
MOVWF PORTC
CALL CLOCK
MOVLW 5h
MOVWF PORTC
CALL CLOCK
RETLW 0

L  MOVLW .1  ;Enables Display
MOVWF PORTA
MOVLW 3h  ;First part of byte (3Ch)
MOVWF PORTC
CALL CLOCK
MOVLW 0Ch
MOVWF PORTC
CALL CLOCK
RETLW 0

O  MOVLW .1  ;Enables Display
MOVWF PORTA
MOVLW 3h  ;First part of byte (3Fh)
MOVWF PORTC
CALL CLOCK
MOVLW 0Fh
MOVWF PORTC
CALL CLOCK
RETLW 0

WW  MOVLW .1  ;Enables Display
MOVWF PORTA
MOVLW 4h  ;First part of byte (47h)
MOVWF PORTC
CALL CLOCK
MOVLW 7h
MOVWF PORTC
CALL CLOCK
RETLW 0

RR  MOVLW .1  ;Enables Display
MOVWF PORTA
MOVLW 4h  ;First part of byte (42h)
MOVWF PORTC
CALL CLOCK
MOVLW 2h
MOVWF PORTC
CALL CLOCK
RETLW 0

DD  MOVLW .1  ;Enables Display
MOVWF PORTA
MOVLW 3h  ;First part of byte (32h)
MOVWF PORTC
CALL CLOCK
MOVLW 4h
MOVWF PORTC
CALL CLOCK
RETLW 0

GAP  MOVLW .1  ;Enables Display
MOVWF PORTA
MOVLW 1h  ;First part of byte (10h)
MOVWF PORTC
CALL CLOCK
MOVLW 0h
MOVWF PORTC
CALL CLOCK
RETLW 0

CLRDISP CLRF PORTA
MOVLW .1  ;Enables Display
MOVWF PORTA
MOVLW 0h  ;First part of byte (01h)
MOVWF PORTC
CALL CLOCK
MOVLW 1h
MOVWF PORTC
CALL CLOCK
RETLW 0

END
If you could either go through my code, or possibly suggest code for me that I can then play with, and learn from, that would be a great help

Thanks all,

AndyV

Last edited:

#### t06afre

Joined May 11, 2009
5,934
Welcome to the forum I am sure we can help you. What is problem Can you write a few words about that also. And perhaps post a schematic that show us how the LCD is connected. It would be very helpful for us.
By the way. Then you post code it is more convenient to use the code option explained here http://forum.allaboutcircuits.com/misc.php?do=bbcode#code You can edit your first posting to see the difference

#### andyv

Joined Apr 6, 2010
5
Cheers t06afre,

I'm not getting anything displayed on my screen, just all white squares surrounded by black lines (if that makes sense I'll be amazed!)

I have connect the PIC to the LCD by RA0-RS RA2-E and RC0-RC7 - DB0-DB7 for the command lines.

I have grounded R/W as I don't need to read back the values.

When i check the o/p of the pic with an LED there is definatly a supply to the screen on the command lines, RS, and E. So There must be something wrong in the initialising, but i can't figure out what it is.

Thanks again,

Andy.

#### MMcLaren

Joined Feb 14, 2010
853
Hi Andy,

You may be running into a few problems;

(1) You need to clear the ANSEL and ANSELH registers in bank 2 to disable the ADC and enable the I/O pins for "digital" I/O. <added> Please excuse me -- I just saw that you cleared ANSEL.

(2) You've connected the LCD using an 8-bit data interface but the software you posted is for 4-bit interface mode. If you want to use 4-bit mode then you should ground the LCD D3 through D0 pins.

(3) There's a reasonably precise procedure for initializing '44780 displays in either 8-bit or 4-bit interface mode. Both procedures are outlined pretty well here; Brief overview about Hitachi HD44780 LCD controller

I attached an example program that I just threw together and tested on a 16F690 using 4-MHz INTOSC with LCD D4..D7 on RC0..RC3, LCD RS on RC4, and LCD E on RC7. Please note in the LCD init' procedure where you need to send single 4-bit nybbles instead of bytes during the first part of the procedure until the controller is switched into 4-bit mode. After that you can start sending 8-bit bytes as two nybbles.

Best luck. Regards, Mike

#### Attachments

• 10.2 KB Views: 379
• 36.5 KB Views: 305
Last edited:

#### andyv

Joined Apr 6, 2010
5

Theres some language in your example Mike that I've never seen before! Theres still a long road ahead, and look forward to going down it.

Cheers again, Andy.

#### MMcLaren

Joined Feb 14, 2010
853
Hi Andy,

You're probably talking about those assembler pseudo opcodes; skpc (skip if carry), skpnc (skip no carry), etc. They're described in the MPLAB "MPASM Assembler" help file. I use them because they're more intuitive (to me) then the 'btfss' (bit test file skip if set) or 'btfsc' (bit test file skip if clear) instructions they replace. I apologize for any confusion they may have caused you Sir.

#### andyv

Joined Apr 6, 2010
5
No, not at all, i kinda got the hang of it once I had read it through a few times. Its nice to see more language used to open my eyes, and hopefully applications.

Thanks.

#### MMcLaren

Joined Feb 14, 2010
853
Hi Andy,

Did you get your LCD working yet or would you like an example program setup for your 8-bit interface using RC7..RC0 (D7..D0) + RA2 (E) + RA0 (RS)?

Mike

#### andyv

Joined Apr 6, 2010
5
Sorry to resurrect this, but I think I may have found the reason why I'm being unsuccessful with the interfacing.

I have run the program that you've suggested Mike, and it still didn't run, so I went back to basics, read through the links you've suggested, and still didn't run, so I ran the MPLAB SIM and watched the registers, it writes the info for an 8 bit interface, but only seems to write the lower 4 bits.

Is there something obvious I'm missing?!?!

Cheers again, Andy.

#### MMcLaren

Joined Feb 14, 2010
853
Hi Andy,

The "working" example program I posted is for 4-bit interface mode and is wired like this;

#### Attachments

• 21.3 KB Views: 621

#### halestorm

Joined Apr 7, 2012
4
I think there's a bug in the program, in the init routine where it sends 0x03 three times followed by 0x02 once, these should be 0x30 and 0x20.

--Dave

#### MMcLaren

Joined Feb 14, 2010
853
I think there's a bug in the program, in the init routine where it sends 0x03 three times followed by 0x02 once, these should be 0x30 and 0x20.

--Dave
Hi Dave,

That's not a bug. In that portion of the LCD init sequence you need to place the upper four bits of the 0x30 and the 0x20 commands onto the D7 through D4 LCD lines. Please notice that the D7..D4 lines are connected to the RC3..RC0 pins and take a closer look at the driver (and the Hitachi HD44780 Datasheet).

Regards, Mike

#### t06afre

Joined May 11, 2009
5,934
This thread is quite old. The Op has not posted in about two years. I would assume his problem are solved by now

#### halestorm

Joined Apr 7, 2012
4
Well, I tried running the code in a 16f690 and it didn't work unless I changed the 0x03 -> 0x30 and 0x02 -> 0x20.

I wasn't pointing this out for the OP, but for future people like myself that may search these archives.

#### MMcLaren

Joined Feb 14, 2010
853
Well, I tried running the code in a 16f690 and it didn't work unless I changed the 0x03 -> 0x30 and 0x02 -> 0x20.
Did you change the LCD init routine? The code relies on the Carry flag being clear on return from the DelayCy() routine calls.

I wasn't pointing this out for the OP, but for future people like myself that may search these archives.
Then why not be more helpful to future people by posting your schematic and code?

#### halestorm

Joined Apr 7, 2012
4
Did you change the LCD init routine? The code relies on the Carry flag being clear on return from the DelayCy() routine calls.
Then why not be more helpful to future people by posting your schematic and code?
I used the code as downloaded and the schematic as shown in the earlier post -- no changes. It didn't work. But when I changed the 0x03s and 0x02s to 0x30s and 0x20s, it worked (no other changes).

#### MMcLaren

Joined Feb 14, 2010
853
Dave,

I just tested the circuit and code and it works fine. It's difficult to say why you had a problem. If you use the simulator you'll see that using three 0x30 values and one 0x20 value results in sending four '0000' nibbles to the LCD.

Regards, Mike

Last edited:

#### t06afre

Joined May 11, 2009
5,934
After power on of the LCD and during the first four writings to the LCD data bus. The lower nibble is "dont care" In the example by MMcLaren. He has connected the lower nibble of PORTC to the high nibble of the LCD databus. Hence it is correct to send 0x03 three times followed by 0x02 once. It will all depend on which nibble you use on the PIC PORTx. I have done LCD designs on the 16f690 and found using PORTB was the most practical for LCD data

#### MMcLaren

Joined Feb 14, 2010
853
If Dave has the LCD D0-D3 lines grounded then the LCD is actually seeing four 8-bit 0x00 commands. I believe 0x00 ('00000000') is undefined in the HD44780 command set so I wonder if his LCD isn't just doing the normal power-up initialization into 8-bit mode and then catching the first half of the two nibble 0x28 instruction to switch into 4-bit mode? If that's the case, he could use 0x00 byte parameters for those first four instructions and get the same results. Perhaps the 30-msec time delay before the first instruction in the init sequence isn't long enough if he's using a power supply with large electrolytic capacitors which would effect Vcc/Vdd rise-time. Anyway, lots of possibilities but I don't think the 0x03 and 0x02 operands used in the HD44780 "initialize by instruction" sequence in that example program are the problem.

#### halestorm

Joined Apr 7, 2012
4
hi,

OK, I need to correct a mistake in what I said but first let me start with the easy part, which is stating what remains unchanged. I also want to say, since you don't know me, I'm not trying to be a jerk, but was really trying to be helpful to future searchers. I believe you when you say it works for you. So now I'm trying to understand the problem and discrepancy. Anyway, here's what I can say with certainty:

• I have checked and re-checked, and confirmed that my wiring is exactly as shown in Mike's schematic
• When I run Mike's original code as downloaded, it does not work.

There was some comment about the power supply. I have tried powering from the PICKit2 itself, from a bench ps (which has big caps), and from a 9V battery (the latter two use a 5V regulator, of course). I get the same results for all three power supplies.

Now, here's where I was wrong. It turns out that I did change more than just 0x03 to 0x30 and 0x02 to 0x20 but forgot it when I typed my easlier post and frankly, I didn't realize the significance of it. Also, you are correct, for the wiring and the code, the values should be 0x03 and 0x02. Incidentally, once I found (what I believe to be) the actual problem, I went back and tried 0x03, 0x30, 0x20, 0x02, and even 0x00 -- and it didn't matter -- they all worked. I think what that means is that my controller is doing the internal power-up reset properly on its own, as Mike most recently suggested.

So there is ONE difference that I have to make to the original code in order to make it work here, and that is to insert a small delay just before the command which turns the display on, which I've colored in red in the following snippet of the init routine,

Rich (BB code):
;
;  now we're in 4-bit mode and can handle 8-bit transactions
;
movlw   b'00101000'     ; 4-bit, 2-lines, 5x7 font        |B0
call    PutCMD          ; send "function set" command     |B0
movlw   b'00001000'     ; display, cursor, blink all off  |B0
call    PutCMD          ; send "display on/off" command   |B0
movlw   b'00000001'     ; clear display (1.53-msecs)      |B0
call    PutCMD          ; send "entry mode set" command   |B0
DelayCy(1500*usecs)     ; required 1.53-msec delay        |B0
movlw   b'00000110'     ; cursor inc, shift off           |B0
call    PutCMD          ; send "entry mode set" command   |B0
DelayCy(1500*usecs)
movlw   b'00001100'     ; display on, leave cursor off    |B0
call    PutCMD          ; send "display on/off" command   |B0
I didn't pick the length of this delay for any particular reason, I just copied and pasted the one above; it could be shorter, perhaps. What I think it probably happening here is that my HD44780 is busy and doesn't accept the last command which turns the display on. (As a check to that, I also tried replacing the display-off command in the second line shown above, with a display-on command, omitting the red delay and this also works.) Probably the correct solution here would be to check the busy flag before proceeding with each write.

Sound reasonable?

best,

--Dave