PIC16f690 interfacing with LCD 16x2

Discussion in 'Embedded Systems and Microcontrollers' started by andyv, Apr 6, 2010.

  1. andyv

    Thread Starter New Member

    Apr 6, 2010
    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
    Code ( (Unknown Language)):
    3. ;*********************************************************
    5.  #include <p16F690.inc>
    6.  DELAY1  EQU 21h
    7.  DELAY2  EQU 22h  
    8.  DISPLAY  EQU 23h
    9.  COUNT  EQU 34h
    11. ;**********************************************************************
    12. ; Configuration Bits
    14. org 0
    15. ;*********************************************************
    17. Start:
    18.   bsf  STATUS,RP0    ;select Register Page 1
    19.   clrf TRISC             ;make make port C outputs
    20.   CLRF TRISA
    21.   bcf  STATUS,RP0    ;back to Register Page 0
    22.   bsf  STATUS,RP1    ;page 2
    23.   clrf ANSEL             ;turn off ADC
    24.   bcf  STATUS,RP1    ;back to page 0
    25.   CLRF PORTA
    26.   CLRF PORTC
    28. ;Display Configuration
    29.   MOVLW 03h
    30.   MOVWF PORTC  ;8 BIT DATA
    31.   CALL  CLOCK
    32.   CALL  DELAY
    33.   MOVLW 02h
    35.   CALL CLOCK
    36.   CALL DELAY
    37.   MOVLW 0h
    39.   CALL DELAY
    40.   MOVLW 08h
    42.   CALL DELAY
    43.   MOVLW 0h
    45.   CALL CLOCK
    46.   MOVLW 0Ch
    47.   MOVWF PORTC
    48.   CALL CLOCK
    49.   CALL DELAY
    50.   MOVLW 0h
    52.   CALL CLOCK
    53.   MOVLW 6h
    54.   MOVWF PORTC
    55.   CALL CLOCK
    57.   MOVLW .8
    59. ;*********************************************************
    60. ;Program starts now.
    63.   CALL CLRDISP
    64.   CLRF PORTA
    65.   MOVLW 8h   ;CURSOR AT TOP LEFT,80h
    66.   MOVWF PORTC
    67.   CALL CLOCK
    68.   MOVLW 0h
    69.   MOVWF PORTC
    70.   CALL  CLOCK
    71.   BSF  PORTA,0
    72.   CALL  H
    73.   CALL DELAY
    74.   CALL E
    75.   CALL DELAY
    76.   CALL  L
    77.   CALL DELAY
    78.   CALL L
    79.   CALL DELAY
    80.   CALL  O
    81.   CALL DELAY
    82.   CALL GAP
    83.   CALL DELAY
    84.   CALL  W
    85.   CALL DELAY
    86.   CALL O
    87.   CALL DELAY
    88.   CALL  R
    89.   CALL DELAY
    90.   CALL L
    91.   CALL DELAY
    92.   CALL  D
    93.   CALL DELAY
    94.   CALL DELAY3S
    97. ;*********************************************************
    99. ;1MS DELAY
    101. DELAY
    102.      DECFSZ    DELAY1,f             ; Waste time.  
    103.      GOTO      DELAY        ; The Inner loop takes 3 instructions per loop *
    104.                                   256 loopss = 768 instructions
    105.      DECFSZ    DELAY2,f             ; The outer loop takes and additional 3
    106.                                               instructions per lap * 256 loops
    107.      GOTO      DELAY          ; (768+3) * 256 = 197376 instructions / 1M
    108.                                        instructions per second = 0.197 sec.
    109.                                       ; call it a two-tenths of a second.
    110.      RETLW  0
    112. DELAY1S
    113.   MOVLW .10
    114.   MOVWF COUNT
    115. LOOP
    116.   CALL DELAY
    117.   DECFSZ COUNT
    118.   GOTO LOOP
    119.   RETLW 0
    121. DELAY3S
    122.   MOVLW .30
    123.   MOVWF COUNT
    124. LOOP1
    125.   CALL DELAY
    126.   DECFSZ COUNT
    127.   GOTO LOOP1
    128.   RETLW 0
    130. CLOCK
    131.   BSF  PORTA,2
    132.   NOP
    133.   BCF  PORTA,2
    134.   NOP
    135.   RETLW 0
    137. ;***********************************************************************
    138. ;
    139. ;HELLO WORLD
    141. A  MOVLW .1  ;Enables Display
    142.   MOVWF PORTA
    143.   MOVLW 3h  ;First part of byte (31h)
    144.   MOVWF PORTC
    145.   CALL CLOCK
    146.   MOVLW 1h
    147.   MOVWF PORTC
    148.   CALL CLOCK
    149.   RETLW 0
    151. H  MOVLW .1  ;Enables Display
    152.   MOVWF PORTA
    153.   MOVLW 3h  ;First part of byte (38h)
    154.   MOVWF PORTC
    155.   CALL CLOCK
    156.   MOVLW 8h
    157.   MOVWF PORTC
    158.   CALL CLOCK
    159.   RETLW 0
    161. E  MOVLW .1  ;Enables Display
    162.   MOVWF PORTA
    163.   MOVLW 3h  ;First part of byte (35h)
    164.   MOVWF PORTC
    165.   CALL CLOCK
    166.   MOVLW 5h
    167.   MOVWF PORTC
    168.   CALL CLOCK
    169.   RETLW 0
    171. L  MOVLW .1  ;Enables Display
    172.   MOVWF PORTA
    173.   MOVLW 3h  ;First part of byte (3Ch)
    174.   MOVWF PORTC
    175.   CALL CLOCK
    176.   MOVLW 0Ch
    177.   MOVWF PORTC
    178.   CALL CLOCK
    179.   RETLW 0
    181. O  MOVLW .1  ;Enables Display
    182.   MOVWF PORTA
    183.   MOVLW 3h  ;First part of byte (3Fh)
    184.   MOVWF PORTC
    185.   CALL CLOCK
    186.   MOVLW 0Fh
    187.   MOVWF PORTC
    188.   CALL CLOCK
    189.   RETLW 0
    191. WW  MOVLW .1  ;Enables Display
    192.   MOVWF PORTA
    193.   MOVLW 4h  ;First part of byte (47h)
    194.   MOVWF PORTC
    195.   CALL CLOCK
    196.   MOVLW 7h
    197.   MOVWF PORTC
    198.   CALL CLOCK
    199.   RETLW 0
    201. RR  MOVLW .1  ;Enables Display
    202.   MOVWF PORTA
    203.   MOVLW 4h  ;First part of byte (42h)
    204.   MOVWF PORTC
    205.   CALL CLOCK
    206.   MOVLW 2h
    207.   MOVWF PORTC
    208.   CALL CLOCK
    209.   RETLW 0
    211. DD  MOVLW .1  ;Enables Display
    212.   MOVWF PORTA
    213.   MOVLW 3h  ;First part of byte (32h)
    214.   MOVWF PORTC
    215.   CALL CLOCK
    216.   MOVLW 4h
    217.   MOVWF PORTC
    218.   CALL CLOCK
    219.   RETLW 0
    221. GAP  MOVLW .1  ;Enables Display
    222.   MOVWF PORTA
    223.   MOVLW 1h  ;First part of byte (10h)
    224.   MOVWF PORTC
    225.   CALL CLOCK
    226.   MOVLW 0h
    227.   MOVWF PORTC
    228.   CALL CLOCK
    229.   RETLW 0
    232.   MOVLW .1  ;Enables Display
    233.   MOVWF PORTA
    234.   MOVLW 0h  ;First part of byte (01h)
    235.   MOVWF PORTC
    236.   CALL CLOCK
    237.   MOVLW 1h
    238.   MOVWF PORTC
    239.   CALL CLOCK
    240.   RETLW 0
    242.    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,

    Last edited: Apr 6, 2010
  2. t06afre

    AAC Fanatic!

    May 11, 2009
    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
  3. andyv

    Thread Starter New Member

    Apr 6, 2010
    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,

  4. MMcLaren

    Distinguished Member

    Feb 14, 2010
    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
    Last edited: Apr 7, 2010
  5. andyv

    Thread Starter New Member

    Apr 6, 2010
    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.
  6. MMcLaren

    Distinguished Member

    Feb 14, 2010
    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.
  7. andyv

    Thread Starter New Member

    Apr 6, 2010
    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.

  8. MMcLaren

    Distinguished Member

    Feb 14, 2010
    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)?

  9. andyv

    Thread Starter New Member

    Apr 6, 2010
    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.
  10. MMcLaren

    Distinguished Member

    Feb 14, 2010
    Hi Andy,

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

  11. halestorm

    New Member

    Apr 7, 2012
    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.

  12. MMcLaren

    Distinguished Member

    Feb 14, 2010
    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
  13. t06afre

    AAC Fanatic!

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

    New Member

    Apr 7, 2012
    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.
  15. MMcLaren

    Distinguished Member

    Feb 14, 2010
    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?
  16. halestorm

    New Member

    Apr 7, 2012
    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).
  17. MMcLaren

    Distinguished Member

    Feb 14, 2010

    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: Apr 14, 2012
  18. t06afre

    AAC Fanatic!

    May 11, 2009
    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
  19. MMcLaren

    Distinguished Member

    Feb 14, 2010
    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.
  20. halestorm

    New Member

    Apr 7, 2012

    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,

    Code ( (Unknown Language)):
    1. ;
    2. ;  now we're in 4-bit mode and can handle 8-bit transactions
    3. ;
    4.         movlw   b'00101000'     ; 4-bit, 2-lines, 5x7 font        |B0
    5.         call    PutCMD          ; send "function set" command     |B0
    6.         movlw   b'00001000'     ; display, cursor, blink all off  |B0
    7.         call    PutCMD          ; send "display on/off" command   |B0
    8.         movlw   b'00000001'     ; clear display (1.53-msecs)      |B0
    9.         call    PutCMD          ; send "entry mode set" command   |B0
    10.         DelayCy(1500*usecs)     ; required 1.53-msec delay        |B0
    11.         movlw   b'00000110'     ; cursor inc, shift off           |B0
    12.         call    PutCMD          ; send "entry mode set" command   |B0
    13. [COLOR="Red"]        DelayCy(1500*usecs)
    14. [/COLOR]        movlw   b'00001100'     ; display on, leave cursor off    |B0
    15.         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?