character LCD 16F684 help

Discussion in 'Embedded Systems and Microcontrollers' started by adrenalina, Jul 23, 2011.

  1. adrenalina

    Thread Starter Active Member

    Jan 4, 2011
    78
    3
    Hello everybody. I am trying to interface my LCD to a 16F684. I am following the tutorial on this page: http://joshuagalloway.com/lcd.html

    I wrote the program, but I can't get anything on the display. I am programming the chip using assembly.

    I went step by step following the tutorial to write the code. I wrote a routine to write a command to the LCD (LCD_WriteC) and a routine to write data to the lcd (LCD_WriteD). Can anybody help me out to see why I can't get anything on the display?
    I already checked my code with the instructions on how to initialize the lcd and how to write data/commands and according to me they do what the website says.

    edit: forgot to mention that I am trying to interface using 4-bit mode

    Code ( (Unknown Language)):
    1. list        p=16F684
    2. #include    <p16F684.inc>
    3.  
    4. errorlevel    -302
    5. errorlevel    -312
    6.  
    7. EXTERN        delay10
    8.  
    9.  
    10. ;***** CONFIGURATION
    11.             ; ext rest, no code protect, no brownout detect,
    12.             ; no watchdog, power-up timer, int clock with I/O,
    13.             ; no failsafe clock monitor, two-speed start-up disabled
    14. __CONFIG    _MCLRE_ON & _CP_OFF & _CPD_OFF & _BOD_OFF & _WDT_OFF & _PWRTE_ON & _INTOSCIO & _FCMEN_OFF & _IESO_OFF
    15.  
    16.  
    17. ;***** PIN ASSIGNMENTS
    18.  
    19. #define        LCD_EN    PORTA,5        ; LCD enable pin
    20. #define        LCD_RS    PORTA,4        ; LCD RS pin
    21.    
    22.  
    23. ;***** VARIABLE DEFINITIONS
    24. CONTEXT     UDATA_SHR            ; variables for context saving
    25. cs_W        res    1
    26. cs_STATUS    res    1
    27.  
    28. SHADOW        UDATA_SHR
    29. sPORTA        res    1                ; shadow registers
    30. sPORTC        res    1            
    31.  
    32. GENVAR        UDATA_SHR            ; general variables
    33. LCD_DATA    res    1                ;variable to store data to be written to lcd    
    34.  
    35. DELAY        UDATA
    36. counter        res    1
    37.  
    38. ;*******************************************************************
    39. RESET    CODE    0x0000            ; processor reset vector
    40.         pagesel    Start
    41.         goto    Start
    42.  
    43. ;***** INTERRUPT SERVICE ROUTINE
    44. ISR        CODE    0x0004
    45.         ; *** Save context
    46.         movwf    cs_W            ; save W
    47.         movf    STATUS,w        ; save STATUS
    48.         movwf    cs_STATUS
    49.  
    50.         ; isr code goes here
    51.    
    52.  
    53. isr_end
    54.         movf    cs_STATUS,w        ; restore STATUS
    55.         movwf    STATUS
    56.         swapf    cs_W,f            ; restore W
    57.         swapf    cs_W,w
    58.         retfie
    59.    
    60. ;***** MAIN PROGRAM
    61. MAIN    CODE
    62.  
    63. ;***** Initialization
    64. Start    ;configure ports
    65.         movlw    b'00001111'        ; set RC<3:0> as digital IO
    66.         banksel    ANSEL
    67.         movwf    ANSEL
    68.        
    69.         banksel    TRISA            ; configure PORTA and PORTC
    70.         movlw    b'110000'        ; set RC<3:0> as outputs
    71.         movwf    TRISC
    72.         movlw    b'001111'        ; set RC<5:4> as outputs
    73.         movwf    TRISA
    74.        
    75. Initialize_LCD
    76.         call    delay5ms        ; wait 20ms for LCD to power up
    77.         call    delay5ms
    78.         call    delay5ms
    79.         call    delay5ms
    80.  
    81.         banksel    PORTA
    82.         bcf        LCD_RS
    83.         movlw    0x03
    84.         movwf    PORTC            ; write 0x03 with RS = 0
    85.         call    delay5ms        ; wait 5ms
    86.  
    87.         movwf    PORTC            ; write 0x03 with RS = 0 again
    88.         call    delay200us                ; wait 200us
    89.  
    90.         movwf    PORTC            ; write 0x03 with RS = 0 one more time
    91.         call    delay200us            ; wait 200us
    92.  
    93.         movlw    0x02            ; write 0x02 to enable four-bit mode
    94.         movwf    PORTC
    95.         call    delay5ms        ; wait 5ms
    96.        
    97.         movlw    0x28            ; write command "Set interface"
    98.         movwf    LCD_DATA
    99.         call    LCD_WriteC
    100.  
    101.         movlw    0x08            ; write command "Enable display/cursor"
    102.         movwf    LCD_DATA
    103.         call    LCD_WriteC
    104.        
    105.         movlw    0x01            ; write command "Clear and Home"
    106.         movwf    LCD_DATA        
    107.         call    LCD_WriteC
    108.        
    109.         movlw    0x06            ; write comamand "Set cursor move direction (right)
    110.         movwf    LCD_DATA
    111.         call    LCD_WriteC
    112.        
    113.         movlw    0x0C            ; turn on display
    114.         movwf    LCD_DATA
    115.         call    LCD_WriteC
    116.        
    117.        
    118.            
    119. ;***** Main loop
    120. mainloop
    121.         call    delay5ms
    122.         movlw    'A'
    123.         movwf    LCD_DATA
    124.         call    LCD_WriteD
    125.         goto    $
    126.  
    127. LCD_WriteD
    128.         banksel    PORTA
    129.         bcf        LCD_EN            ; clear LCD_EN (low)
    130.         nop
    131.         bsf        LCD_RS            ; set LCD_RS (data = 1)
    132.         swapf    LCD_DATA,w        ; put high nibble of data on d7-4
    133.         movwf    PORTC
    134.         bsf        LCD_EN            ; set LCD_EN (high)
    135.         nop                        ; wait at least 450 ns
    136.         bcf        LCD_EN            ; clear LCD_EN (low)
    137.         call    delay200us                ; wait 200 us for data writes
    138.         movf    LCD_DATA,w
    139.         movwf    PORTC            ; put the low nibble of data on d7-4
    140.         bcf        LCD_EN             ;clear LCD_EN
    141.         call    delay200us                ;wait 200us for data writes
    142.         return
    143.  
    144. LCD_WriteC
    145.         banksel    PORTA
    146.         bcf        LCD_EN            ; clear LCD_EN (low)
    147.         nop
    148.         bcf        LCD_RS            ; clear LCD_RS (command = 0)
    149.         swapf    LCD_DATA,w        ; put high nibble of data on d7-4
    150.         movwf    PORTC
    151.         bsf        LCD_EN            ; set LCD_EN (high)
    152.         nop                        ; wait at least 450 ns
    153.         bcf        LCD_EN            ; clear LCD_EN (low)
    154.         call    delay5ms                ; wait 5ms for command writes
    155.         movf    LCD_DATA,w
    156.         movwf    PORTC            ; put the low nibble of data on d7-4
    157.         bcf        LCD_EN             ;clear LCD_EN
    158.         call    delay5ms                ;wait 5ms for command writes
    159.         return
    160.  
    161. delay5ms
    162.         clrf    counter            ; delay = 5.124 ms    with 4Mhz clock
    163. delayn    goto    $+1                
    164.         goto    $+1
    165.         goto    $+1
    166.         goto    $+1
    167.         goto    $+1
    168.         goto    $+1
    169.         goto    $+1
    170.         goto    $+1
    171.         nop
    172.        
    173.         decfsz    counter
    174.         goto    delayn
    175.         return
    176.  
    177. delay200us
    178.         movlw    .67                ; delay = 206 us with 4Mhz clock
    179.         movwf    counter
    180. decc    decfsz    counter
    181.         goto    decc
    182.         return
    183.  
    184.  
    185.         END
    186.  
    187.        
    188.  
     
    Last edited: Jul 23, 2011
  2. adrenalina

    Thread Starter Active Member

    Jan 4, 2011
    78
    3
    Finally found the problem. In the initialization part for the display I forgot to clear LCD_EN before moving the data to portc and after moving the data I forgot to set LCD_EN.
    Another problem was in the tutorial. In the section that says 4-bit write sequence:

    After put the LOW byte of the data/command on d7-4 and before the wait at least 450 ns instruction there is supposed to be another instruction which is set "en" (EN=1 or high). if not the low nibble never gets written to the lcd. So if anybody is following the tutorial on that website don't forget to set "EN" after putting the lower nibble on the data pins.

    final code:

    Code ( (Unknown Language)):
    1. list        p=16F684
    2. #include    <p16F684.inc>
    3.  
    4. errorlevel    -302
    5. errorlevel    -312
    6.  
    7. EXTERN        delay10
    8.  
    9.  
    10. ;***** CONFIGURATION
    11.             ; ext rest, no code protect, no brownout detect,
    12.             ; no watchdog, power-up timer, int clock with I/O,
    13.             ; no failsafe clock monitor, two-speed start-up disabled
    14. __CONFIG    _MCLRE_ON & _CP_OFF & _CPD_OFF & _BOD_OFF & _WDT_OFF & _PWRTE_ON & _INTOSCIO & _FCMEN_OFF & _IESO_OFF
    15.  
    16.  
    17. ;***** PIN ASSIGNMENTS
    18.  
    19. #define        LCD_EN    PORTA,5        ; LCD enable pin
    20. #define        LCD_RS    PORTA,4        ; LCD RS pin
    21.    
    22.  
    23.  
    24.  
    25. ;***** VARIABLE DEFINITIONS
    26. CONTEXT     UDATA_SHR            ; variables for context saving
    27. cs_W        res    1
    28. cs_STATUS    res    1
    29.  
    30. SHADOW        UDATA_SHR
    31. sPORTA        res    1                ; shadow registers
    32. sPORTC        res    1            
    33.  
    34. GENVAR        UDATA_SHR            ; general variables
    35. LCD_DATA    res    1                ;variable to store data to be written to lcd    
    36. counter        res    1
    37.  
    38. ;*******************************************************************
    39. RESET    CODE    0x0000            ; processor reset vector
    40.         pagesel    Start
    41.         goto    Start
    42.  
    43. ;***** INTERRUPT SERVICE ROUTINE
    44. ISR        CODE    0x0004
    45.         ; *** Save context
    46.         movwf    cs_W            ; save W
    47.         movf    STATUS,w        ; save STATUS
    48.         movwf    cs_STATUS
    49.  
    50.         ; isr code goes here
    51.    
    52.  
    53. isr_end
    54.         movf    cs_STATUS,w        ; restore STATUS
    55.         movwf    STATUS
    56.         swapf    cs_W,f            ; restore W
    57.         swapf    cs_W,w
    58.         retfie
    59.    
    60. ;***** MAIN PROGRAM
    61. MAIN    CODE
    62.  
    63. ;***** Initialization
    64. Start    ;configure ports
    65.         movlw    b'00001111'        ; set RC<3:0> as digital IO
    66.         banksel    ANSEL
    67.         movwf    ANSEL
    68.        
    69.         banksel    TRISA            ; configure PORTA and PORTC
    70.         movlw    b'110000'        ; set RC<3:0> as outputs
    71.         movwf    TRISC
    72.         movlw    b'001111'        ; set RC<5:4> as outputs
    73.         movwf    TRISA
    74.        
    75. Initialize_LCD
    76.         call    delay5ms        ; wait 20ms for LCD to power up
    77.         call    delay5ms
    78.         call    delay5ms
    79.         call    delay5ms
    80.  
    81.         banksel    PORTA
    82.         bcf        LCD_RS
    83.         movlw    0x03
    84.         bcf        LCD_EN
    85.         movwf    PORTC            ; write 0x03 with RS = 0
    86.         bsf        LCD_EN
    87.         call    delay5ms        ; wait 5ms
    88.  
    89.         bcf        LCD_EN
    90.         movwf    PORTC            ; write 0x03 with RS = 0 again
    91.         bsf        LCD_EN
    92.         call    delay200us                ; wait 200us
    93.  
    94.         bcf        LCD_EN
    95.         movwf    PORTC            ; write 0x03 with RS = 0 one more time
    96.         bsf        LCD_EN
    97.         call    delay200us            ; wait 200us
    98.  
    99.         bcf        LCD_EN
    100.         movlw    0x02            ; write 0x02 to enable four-bit mode    
    101.         movwf    PORTC
    102.         bsf        LCD_EN
    103.         call    delay5ms        ; wait 5ms
    104.    
    105.            
    106.         movlw    0x28            ; write command "Set interface"
    107.         movwf    LCD_DATA
    108.         call    LCD_WriteC
    109.  
    110.         movlw    0x08            ; write command "Enable display/cursor"
    111.         movwf    LCD_DATA
    112.         call    LCD_WriteC
    113.        
    114.         movlw    0x01            ; write command "Clear and Home"
    115.         movwf    LCD_DATA        
    116.         call    LCD_WriteC
    117.        
    118.         movlw    0x06            ; write command "Set cursor move direction (right)
    119.         movwf    LCD_DATA
    120.         call    LCD_WriteC
    121.        
    122.         movlw    0x0C            ; turn on display
    123.         movwf    LCD_DATA
    124.         call    LCD_WriteC
    125.        
    126.        
    127.            
    128. ;***** Main loop
    129. mainloop
    130.         call    delay5ms
    131.         movlw    'A'
    132.         movwf    LCD_DATA
    133.         call    LCD_WriteD
    134.         goto    $
    135.  
    136. LCD_WriteD
    137.         banksel    PORTA
    138.         bcf        LCD_EN            ; clear LCD_EN (low)
    139.         nop
    140.         bsf        LCD_RS            ; set LCD_RS (data = 1)
    141.         swapf    LCD_DATA,w        ; put high nibble of data on d7-4
    142.         movwf    PORTC
    143.         bsf        LCD_EN            ; set LCD_EN (high)
    144.         nop                        ; wait at least 450 ns
    145.         bcf        LCD_EN            ; clear LCD_EN (low)
    146.         call    delay200us        ; wait 200 us for data writes
    147.         movf    LCD_DATA,w
    148.         movwf    PORTC            ; put the low nibble of data on d7-4
    149.         bsf        LCD_EN             ; set LCD_EN
    150.         nop                        ; wait at least 450 ns
    151.         bcf        LCD_EN            ; clear LCD_EN
    152.         call    delay200us                ;wait 200us for data writes
    153.         return
    154.  
    155. LCD_WriteC
    156.         banksel    PORTA
    157.         bcf        LCD_EN            ; clear LCD_EN (low)
    158.         nop
    159.         bcf        LCD_RS            ; clear LCD_RS (command = 0)
    160.         swapf    LCD_DATA,w        ; put high nibble of data on d7-4
    161.         movwf    PORTC
    162.         bsf        LCD_EN            ; set LCD_EN (high)
    163.         nop                        ; wait at least 450 ns
    164.         bcf        LCD_EN            ; clear LCD_EN (low)
    165.         call    delay5ms                ; wait 5ms for command writes
    166.         movf    LCD_DATA,w
    167.         movwf    PORTC            ; put the low nibble of data on d7-4
    168.         bsf        LCD_EN             ; set LCD_EN
    169.         nop                        ; wait at least 450 ns
    170.         bcf        LCD_EN            ; clear LCD_EN
    171.         call    delay5ms                ;wait 5ms for command writes
    172.         return
    173.  
    174. delay5ms
    175.        
    176.         clrf    counter            ; delay = 5.124 ms    with 4Mhz clock
    177. delayn    goto    $+1                
    178.         goto    $+1
    179.         goto    $+1
    180.         goto    $+1
    181.         goto    $+1
    182.         goto    $+1
    183.         goto    $+1
    184.         goto    $+1
    185.         nop
    186.        
    187.         decfsz    counter
    188.         goto    delayn
    189.         return
    190.  
    191. delay200us
    192.         movlw    .67                ; delay = 206 us with 4Mhz clock
    193.         movwf    counter
    194. decc  decfsz    counter
    195.         goto      decc
    196.         return
    197.  
    198.  
    199.  
    200.  
    201.  
    202.  
     
  3. adrenalina

    Thread Starter Active Member

    Jan 4, 2011
    78
    3
    never mind it doesn't work well it works on a simulator, but when I built the circuit and programmed the chip it doesn't display anything on the lcd. I already checked my connections to make sure everything is connected correctly and it is. if it works on the simulator it should work physically.
    This is what happens. The display turns on and the 1st line is filled with black squares. Then I pull the reset button on the pic high and the lcd has both lines filled with light black squares, not as dark as it was on the first line.

    I thought the lcd might be bad, so I got my arduino and tested it with an example program and it works perfectly so its not the lcd.
     
    Last edited: Jul 23, 2011
  4. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    That sounds like the LCD is at least initialising ok.

    Have you checked the contrast pot voltage adjustment? It is very easy to get caught out with that. :)

    I noticed on bootup your PORTA pins are in an undefined state, you might try setting the RS pin HI and the E pin LO immediately after setting TRISA. That will hold those pins in a more desirable state when the LCD does the 20mS initial delay before bootup.

    Also check the R/W pin has been connected to ground!
     
  5. adrenalina

    Thread Starter Active Member

    Jan 4, 2011
    78
    3
    so I did everything you suggested and well unfortunately it didn't work R/W pin is grounded put the RS High and E low and also checked the pot.

    Then I remembered reading about read modify write problem with bsf and bcf. In the code I was doing for example bcf LCD_RS and then immediately bsf LD_EN and that could cause problem. So I used a shadow register. instead bsf and bcf on the port A, I changed it so that it does it on the shadow register then copy the shadow to the port.

    part of the code:
    Code ( (Unknown Language)):
    1.  
    2.  
    3. #define        LCD_EN    sPORTA,5        ; LCD enable pin
    4. #define        LCD_RS    sPORTA,4        ; LCD RS pin
    5.  
    6.  
    7.         bcf        LCD_RS
    8.         nop
    9.         bcf        LCD_EN
    10.         call    shadow_A
    11.         movlw    0x03
    12.         movwf    PORTC            ; write 0x03 with RS = 0
    13.         bsf        LCD_EN
    14.         call    shadow_A
    15.         nop
    16.         bcf        LCD_EN
    17.         call    shadow_A
    18.         call    delay5ms        ; wait 5ms
    19.  
    20.  
    21. shadow_A
    22.         movf    sPORTA,w
    23.         movwf    PORTA
    24.         return
    25.  
    26.  
    and finally after making those changes the LCD displayed the text!!! I guess that is why it only worked on the simulator for the simulator having to bsf or bcf instructions one after another is not a problem, but for the chip it is.
     
  6. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,392
    1,605
    Congratulations. Everyone stumbles getting these things working the first time.

    A bcf/bsf can cause a problem as the output may not have changed by the time the bsf is executed, and as this instruction does "read, make change, write" it can read the wrong data, thus negating the initial bcf.

    Sometimes a nop will fix the problem, but a nop may not work on a faster PIC or slower hardware. A shadow register will always work.

    There are a few other weird things the MPLAB simulator gets wrong, but generally (I don't know of an exception) if it works in MPLAB it words in the chip.

    Now I have seen MPLAB get a different incorrect answer then the chip would get, but both are bugs and fixing the bug fixed both sim and chip. I don't remember the example where I saw this, it was something like a port with an analog function and the analog was not disabled for digital use.
     
Loading...