PIC16f690 interfacing with LCD 16x2

Thread Starter

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
  clrf ANSEL             ;turn off ADC
  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
 

Thread Starter

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
859
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

Last edited:

Thread Starter

andyv

Joined Apr 6, 2010
5
Thanks guys, you've helped loads.

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
859
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.

Good luck on your project.
 

Thread Starter

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
859
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
 

Thread Starter

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.
 
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
859
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
 
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
859
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?
 
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
859
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
859
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.
 
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
 
Top