PIC16F688 & 2 x 20 LCD

Discussion in 'Programmer's Corner' started by nerdegutta, Dec 23, 2012.

  1. nerdegutta

    Thread Starter Moderator

    Dec 15, 2009
    2,517
    785
    Hi.

    I've been trying to interface a PIC16F688 with a 2 x 20 LCD.

    RA4 = RS
    RA5 = E
    RC0-3 = D4-7
    R/W = GND (Tried to have this on RA3, and changed the lcd.c file, but nothing.)

    main.c
    Code ( (Unknown Language)):
    1.  
    2. // Include
    3. #include <htc.h>
    4. #include "lcd.h"
    5.  
    6. // Definitions
    7. #define _XTAL_FREQ 8000000
    8.  
    9. // Configuration
    10. __CONFIG (FOSC_INTOSCIO &    // Internal Oscillator
    11. WDTE_OFF &                     // Watchdog timer OFF
    12. PWRTE_OFF &                    // Power-up timer OFF
    13. MCLRE_OFF &                 // MCLR pin function is digital input
    14. CP_OFF &                     // Program Code Protection OFF
    15. CPD_OFF &                    // Data Code Protection OFF
    16. BOREN_OFF &                    // Brown out OFF
    17. IESO_OFF &                    // Internal External Switchover mode is disabled
    18. FCMEN_ON);                    // Fail-Safe Clock Monitor is disabled
    19.  
    20. // Variables
    21.  
    22. // Functions
    23.  
    24. // Main
    25. void main()
    26. {
    27. CMCON0 = 0x07;
    28. ANSEL = 0;
    29. ADCON0 = 0;
    30. ADCON1 = 0;
    31. OSCCONbits.IRCF0 = 1;    // 8MHz
    32. OSCCONbits.IRCF1 = 1;    // 8MHz
    33. OSCCONbits.IRCF2 = 1;    // 8MHz
    34. OSCCONbits.OSTS = 0;    // Device is running from internal osc
    35. OSCCONbits.HTS = 1;        // Stable
    36. OSCCONbits.LTS = 1;        // Stable
    37. OSCCONbits.SCS = 1;        // Internal oscillator used for system clock
    38.  
    39. OSCTUNE = 0b00000000;        // Oscillator running at calibrated freq
    40.  
    41. TRISA = 0b00000000;
    42. TRISC = 0b00000000;
    43.  
    44. lcd_init();
    45. lcd_puts("1234567890");
    46. lcd_goto(0x40);
    47. lcd_puts("Hello World.");
    48. for(;;);
    49.     } // end main
    50.    
    51.  
    lcd.c
    Code ( (Unknown Language)):
    1.  
    2. /*
    3.  *    LCD interface example
    4.  *    Uses routines from delay.c
    5.  *    This code will interface to a standard LCD controller
    6.  *    like the Hitachi HD44780. It uses it in 4 bit mode, with
    7.  *    the hardware connected as follows (the standard 14 pin
    8.  *    LCD connector is used):
    9.  *    
    10.  *    PORTD bits 0-3 are connected to the LCD data bits 4-7 (high nibble)
    11.  *    PORTA bit 3 is connected to the LCD RS input (register select)
    12.  *    PORTA bit 1 is connected to the LCD EN bit (enable)
    13.  *    
    14.  *    To use these routines, set up the port I/O (TRISA, TRISD) then
    15.  *    call lcd_init(), then other routines as required.
    16.  *    
    17.  */
    18.  
    19. #ifndef _XTAL_FREQ
    20.  // Unless specified elsewhere, 4MHz system frequency is assumed
    21.  #define _XTAL_FREQ 4000000
    22. #endif
    23.  
    24.  
    25. #include    <htc.h>
    26. #include    "lcd.h"
    27.  
    28. #define    LCD_RS RA4
    29. // #define    LCD_RW RA4 connected to GND
    30. #define LCD_EN RA5
    31.  
    32. #define LCD_DATA    PORTC
    33.  
    34. #define    LCD_STROBE()    ((LCD_EN = 1),(LCD_EN=0))
    35.  
    36. /* write a byte to the LCD in 4 bit mode */
    37.  
    38. void
    39. lcd_write(unsigned char c)
    40. {
    41.     __delay_us(40);
    42.     LCD_DATA = ( ( c >> 4 ) & 0x0F );
    43.     LCD_STROBE();
    44.     LCD_DATA = ( c & 0x0F );
    45.     LCD_STROBE();
    46. }
    47.  
    48. /*
    49.  *     Clear and home the LCD
    50.  */
    51.  
    52. void
    53. lcd_clear(void)
    54. {
    55.     LCD_RS = 0;
    56.     lcd_write(0x1);
    57.     __delay_ms(2);
    58. }
    59.  
    60. /* write a string of chars to the LCD */
    61.  
    62. void
    63. lcd_puts(const char * s)
    64. {
    65.     LCD_RS = 1;    // write characters
    66.     while(*s)
    67.         lcd_write(*s++);
    68. }
    69.  
    70. /* write one character to the LCD */
    71.  
    72. void
    73. lcd_putch(char c)
    74. {
    75.     LCD_RS = 1;    // write characters
    76.     lcd_write( c );
    77. }
    78.  
    79.  
    80. /*
    81.  * Go to the specified position
    82.  */
    83.  
    84. void
    85. lcd_goto(unsigned char pos)
    86. {
    87.     LCD_RS = 0;
    88.     lcd_write(0x80+pos);
    89. }
    90.    
    91. /* initialise the LCD - put into 4 bit mode */
    92. void
    93. lcd_init()
    94. {
    95.     char init_value;
    96.  
    97.     ADCON1 = 0x06;    // Disable analog pins on PORTA
    98.  
    99.     init_value = 0x3;
    100.     TRISA=0;
    101.     TRISC=0;
    102.     LCD_RS = 0;
    103.     LCD_EN = 0;
    104. //    LCD_RW = 0;
    105.    
    106.     __delay_ms(15);    // wait 15mSec after power applied,
    107.     LCD_DATA     = init_value;
    108.     LCD_STROBE();
    109.     __delay_ms(5);
    110.     LCD_STROBE();
    111.     __delay_us(200);
    112.     LCD_STROBE();
    113.     __delay_us(200);
    114.     LCD_DATA = 2;    // Four bit mode
    115.     LCD_STROBE();
    116.  
    117.     lcd_write(0x28); // Set interface length
    118.     lcd_write(0xF); // Display On, Cursor On, Cursor Blink
    119.     lcd_clear();    // Clear screen
    120.     lcd_write(0x6); // Set entry Mode
    121. }
    122.  
    lcd.h is untouched.

    All I get is squares on the first line.

    It was working the other day, but I had to mess around with the code, and now it's not working.

    I think it is a timer / oscillator problem, but I can't seem to find it.

    Can you?
     
    Last edited: Dec 23, 2012
  2. spinnaker

    AAC Fanatic!

    Oct 29, 2009
    4,887
    1,016
    Squares usually mean your contrast is not set correctly. Check with a volt meter.

    Also verify each of the connections to the LCD just to be sure you did not mess up a connection between a couple days ago and now. A good way to do this is to write a quick program to toggle each bit and test with a logic probe, scope, logic analyzer etc.

    If you use MPLabX, it automatically keeps code changes. I really nice feature.
     
  3. nerdegutta

    Thread Starter Moderator

    Dec 15, 2009
    2,517
    785
    Been over the connections a few times.:)

    Attached is a screenshot from D0.
     
    • d0.png
      d0.png
      File size:
      42.6 KB
      Views:
      32
  4. absf

    Senior Member

    Dec 29, 2010
    1,493
    372
    I normally dont use Port A for LCD connection. Try add pull-up resistors on RS & E and see if it works. Else shift them to PORT B if it is available.

    Allen
     
  5. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,395
    1,607
    Not on my LCD, which BTW doesn't need nor use a contrast adjustment.

    Squares on this one mean uninitialized.
     
  6. spinnaker

    AAC Fanatic!

    Oct 29, 2009
    4,887
    1,016
    Do you have a bypass cap on your LCD power pin?
     
  7. nerdegutta

    Thread Starter Moderator

    Dec 15, 2009
    2,517
    785
    No, I don't.

    It get ~5v from a 7805 regulator, with caps on in and out pins.

    I think it has to do with initialization and the oscillator.
     
  8. spinnaker

    AAC Fanatic!

    Oct 29, 2009
    4,887
    1,016
    You should have .1uf caps on all of your power pins of all of your chips including the LCD. Not saying that is the problem here but it certainly would not hurt to try since you should add them anyway.
     
  9. nerdegutta

    Thread Starter Moderator

    Dec 15, 2009
    2,517
    785
    Actually I thought that it was integrated in the LCD display, but it can't hurt to put one. I'll do it. :)
     
  10. t06afre

    AAC Fanatic!

    May 11, 2009
    5,939
    1,222
    You have defined _XTAL_FREQ to 4Mhz in the lcd.c and 8 MHz in your main.c Your MCU is running on 8MHz. So this may have messed up your delay timing.
    Edit now I see your error. The example you are using are OK then you use two ports. But you use only one port. And at the same time you also have in your code
    So the high nibble of LCD_DATA will always be cleared then writing to PORTA. Hence you will always tell the LCD to expect a command and not data. You must rewrite your code so EN and RS have the correct value before you write to PORTA. EN should be high before the STROBE command and RS according to data command setting. Just use temp variable to work on before you send your data to the port
     
    Last edited: Dec 23, 2012
  11. t06afre

    AAC Fanatic!

    May 11, 2009
    5,939
    1,222
    One more thing is not RA3 input only:eek:
     
  12. nerdegutta

    Thread Starter Moderator

    Dec 15, 2009
    2,517
    785
    Code ( (Unknown Language)):
    1.  
    2. #ifndef _XTAL_FREQ
    3.  // Unless specified elsewhere, 4MHz system frequency is assumed
    4.  #define _XTAL_FREQ 8000000
    5. #endif
    6.  
    What does this mean?

    Hm... Need some more guidance here, 'cause this was working....

    Yup, it is, but I'm not using it.
     
  13. t06afre

    AAC Fanatic!

    May 11, 2009
    5,939
    1,222
    Forget my last postings. I read your code wrong. Thinking you used only PORTA as your LCD control port:confused:
    Looking again at your code it looks correct. Then using the lower nibble of PORTC. The squares are often a sign of something wrong then setting up. Could it be loose wire some place (no pun), or a bad solder
     
  14. nerdegutta

    Thread Starter Moderator

    Dec 15, 2009
    2,517
    785
    Tried wit 4 different PICs
    Tried with 2 different LCD
    Tried changing RS and E to ports C, and added R/W
    No luck!

    All is set up on breadboard, and I've checked for connection between PIC wires and actual contacts on the LCD.

    I just don't get it. :(
     
  15. thatoneguy

    AAC Fanatic!

    Feb 19, 2009
    6,357
    718
    Try toggling an unused port every time through main(), then check the speed with the scope to see if it is a 1 MHz square wave for 8Mhz in (toggle every 4 clock cycles, 1 cycle high, 1 cycle low = 1Mhz out pin)

    Are you getting data out on the other LCD lines when you look with a scope?

    In lcd.c, the ports are hard coded?
    Code ( (Unknown Language)):
    1.  
    2. #define LCD_EN RA5  
    3. #define LCD_DATA    PORTC
    4.  
    Since nothing is on portC....
     
  16. nerdegutta

    Thread Starter Moderator

    Dec 15, 2009
    2,517
    785
    Yes, I get a reading on the scope, when probing the other datalines.

    The LCDs shows the same squares.

    The LCD data bits are on RC0-RC3
     
  17. thatoneguy

    AAC Fanatic!

    Feb 19, 2009
    6,357
    718
    Your Original Post shows data on RA0-RA3 in text ? (RA0-3 = D4-7)

    If that's not the issue, check the clock.

    Maybe try a "known good" lcd app on the PIC with a demo board to compare signals?
     
  18. nerdegutta

    Thread Starter Moderator

    Dec 15, 2009
    2,517
    785
    My fault. It should be RC0-3 = D4-7. I have corrected the OP. I think it has something to to with clock, initialization or oscillation, but I cannot get my head around it...
     
  19. MrChips

    Moderator

    Oct 2, 2009
    12,449
    3,365
    Just shooting in the dark.
    Try rewriting the LCD_STROBE( ) macro as a separate subroutine
    and put some delay between going high and low.

    Call lcd_init( ) twice in main( ).

    Check timings on the scope and make sure you are not running too fast.
    Increase the delays where necessary.
     
  20. nerdegutta

    Thread Starter Moderator

    Dec 15, 2009
    2,517
    785
    Maybe going too fast. The attachment is from the E bit.

    Which reminds me... I had a problem with some ADC acquisition. The error message/warning said something about less that 1.60uS. How can I slow down?
     
    • e.png
      e.png
      File size:
      42.3 KB
      Views:
      25
Loading...