LCD Initialization problem with 4x20 using XC8, PIC18F45K50, 4-Bit, Pins RD0-RD7

Discussion in 'Embedded Systems and Microcontrollers' started by Hoylegj, Apr 24, 2016.

  1. Hoylegj

    Thread Starter New Member

    Mar 10, 2016
    16
    1
    Hi, I'd really appreciate your help, this is driving me mad..

    This code works sometimes, if I compile it say 4 times it will run once or twice successfully, the other times the LED's used to trace the code flow were telling me its getting to the Init code but the LCD is not displaying.

    I've tried increased timing to silly numbers, I written a GH_delay_ms timer and tested it and its reasonably accurate. I've add delays all over the place without joy, I've reviewed and tried lots of code and LCD codes, but not been able to understand my errors. I've reviewed the data sheets and I'm obviously misunderstanding.

    He's my test code, I've pasted it all together in case you would like to run it, thanking you in advance.

    Many Thanks Geoff.

    Here's a snippet, the full code is attached.
    Code (C):
    1.  
    2. {
    3.     GH_delay_ms(50);
    4.  
    5.         // The data bits must be either a 8-bit port or the upper or
    6.         // lower 4-bits of a port. These pins are made into inputs
    7. #ifdef  BIT8                                      // 8-bit mode, use whole port
    8.         DATA_PORT        = 0;
    9.         TRIS_DATA_PORT   = 0x00;
    10. #else                                             // 4-bit mode
    11.     #ifdef UPPER                                  // Upper 4-bits of the port
    12.         DATA_PORT       &= 0x0f;
    13.         TRIS_DATA_PORT  &= 0x0F;
    14.     #else                                         // Lower 4-bits of the port
    15.         DATA_PORT       &= 0xf0;
    16.         TRIS_DATA_PORT  &= 0xF0;
    17.     #endif
    18. #endif
    19.  
    20.     TRIS_RW              = 0;                     // All control signals made outputs
    21.     TRIS_RS              = 0;
    22.     TRIS_E               = 0;
    23.     RW_PIN               = 0;                     // R/W pin made low
    24.     RS_PIN               = 0;                     // Register select pin made low
    25.     E_PIN                = 0;                     // Clock pin made low
    26.  
    27. // Delay for 15ms to allow for LCD Power on reset
    28.     GH_delay_ms(15);
    29.     LATAbits.LATA2            = 1;
    30.     WriteCmdXLCD(0x28);              
    31.     WriteCmdXLCD(0x28);
    32.     WriteCmdXLCD(0x28);    
    33.     WriteCmdXLCD(LCD_FUNCTION);                   // 4 bit interface, 2 lines, 5x8 font
    34.     WriteCmdXLCD(LCD_DISPLAY_OFF);
    35.     WriteCmdXLCD(LCD_CLEAR);                      // Clear
    36.     WriteCmdXLCD(LCD_ENTRY_MODE);                 // Increment, with display shift
    37.     WriteCmdXLCD(LCD_CURSOR_FWD);                 //
    38.     WriteCmdXLCD(LCD_DISP_ON_NO_CURSOR);          // Display on and blink cursor
    39.     WriteCmdXLCD(LCD_FUNCTION);                   // 4 bit interface, 2 lines, 5x8 font
    40. }
    Mod edit: code tags
     
    Last edited by a moderator: Apr 24, 2016
  2. JohnInTX

    Moderator

    Jun 26, 2012
    2,341
    1,024
    It does not look like there are the necessary delays between the init instructions. You can't check the busy flag until you send 3 function set (x28) commands. You must create a delay. Also, for a 4 bit interface, WriteCmdXLCD may not be what you want. It sends 8 bits of data in 4 bit chunks. That's not what the Hitachi controller wants. See Figure 24 in the attached datasheet. Note that after power up for a 4 bit interface 4 bits are sent (not 8 in two nibbles) three times with delays in between - you can't poll the busy flag until that is done.

    After init, be sure your code does poll the busy flag OR knows how long each function takes to process and delays accordingly. Note that Clear Display takes a long time to execute.

    Code (C):
    1.  
    2. // wait for 15ms power up
    3.    WriteNibble(0x3);    // wait >4.1ms after this  
    4.    delay(4.1ms);    
    5.     WriteNibble(0x3);// wait >100us after this
    6.     delay(100us);
    7.     WriteNibble(0x3);
    8.    WriteNibble(0x2); // 4 bit interface
    9.   // can now check busy flag AND subsequent writes are 8 bits in two 4 bit nibbles.
    10.  
    Good luck.
     
    Last edited: Apr 24, 2016
  3. Picbuster

    Member

    Dec 2, 2013
    373
    50
    I used the following codes and it works great.
    Code (C):
    1.  
    2. //==============  lcd.h ================================================
    3.  
    4. /*
    5. * LCD interface header file
    6. * See lcd.c for more info
    7. */
    8.  
    9. /* write a byte to the LCD in 4 bit mode */
    10.  
    11. extern void lcd_write(unsigned char);
    12.  
    13. /* Clear and home the LCD */
    14.  
    15. extern void lcd_clear(void);
    16.  
    17. /* write a string of characters to the LCD */
    18.  
    19. extern void lcd_puts(const char * s);
    20.  
    21. /* Go to the specified position */
    22.  
    23. extern void lcd_goto(unsigned char pos);
    24.  
    25. /* intialize the LCD - call before anything else */
    26.  
    27. extern void lcd_init(void);
    28.  
    29. extern void lcd_putch(char);
    30.  
    31. /* Set the cursor position */
    32.  
    33. #define lcd_cursor(x) lcd_write(((x)&0x7F)|0x80)
    34.  
    35. //================================================
    36.  
    37. #define DR1 0
    38. #define DR2 64
    39. #define DR3 20
    40. #define DR4 84
    41. //=========================================
    42.  
    43.  
    44.  
    45.  
    46.  
    47. //=========================================  driver ==================================
    48.  
    49.  
    50. /*
    51. * LCD interface example
    52. * Uses routines from delay.c
    53. * This code will interface to a standard LCD controller
    54. * like the Hitachi HD44780. It uses it in 4 bit mode, with
    55. * the hardware connected as follows (the standard 14 pin
    56. * LCD connector is used):
    57. *
    58. * PORTE bits 0-3 are connected to the LCD data bits 4-7 (high nibble)
    59. * PORTH2 bit 3 is connected to the LCD RS input (register select)
    60. * PORTH0 bit 1 is connected to the LCD EN bit (enable)
    61. *
    62. * To use these routines, set up the port I/O (TRISA, TRISD) then
    63. * call lcd_init(), then other routines as required.
    64. *
    65. */
    66.  
    67. // #ifndef _XTAL_FREQ
    68. // Unless specified elsewhere, 4MHz system frequency is assumed
    69.   #define _XTAL_FREQ 20000000
    70. // #endif
    71.  
    72.  
    73.  
    74. #include "lcd.h"
    75.  
    76. // ------------- settings used in my pic 18f8722 ---------------------
    77. #define LCD_RS PORTHbits.RH2
    78. #define LCD_RW PORTHbits.RH1
    79. #define LCD_EN PORTHbits.RH0
    80. #define LCD_DATA PORTE
    81.  
    82. //#define LCD_STROBE() ((LCD_EN = 1),(LCD_EN=0))
    83.  
    84. //  write a byte to the LCD in 4 bit mode */
    85.  
    86. #define lcd_cursor(x) lcd_write(((x)&0x7F)|0x80)
    87.  
    88. //#define lcd_cursor(x) lcd_write(((x)&0x7F)|0x80)
    89.  
    90.  
    91.  
    92. //========== Proto types ======================
    93. extern void lcd_puts(const char * s);
    94. extern void lcd_clear(void);
    95.  
    96. void LCD_STROBE()
    97. {
    98. LCD_EN=0;
    99. __delay_us(20);
    100.   LCD_EN=1;
    101.   }
    102.  
    103.  
    104.  
    105. void
    106. lcd_write(unsigned char c)
    107. {
    108. __delay_us(40);
    109. LCD_DATA = ( ( c >> 4 ) & 0x0F );
    110. LCD_STROBE();
    111. LCD_DATA = ( c & 0x0F );
    112. LCD_STROBE();
    113. __delay_us(20);
    114. }
    115.  
    116. /*
    117. *  Clear and home the LCD
    118. */
    119.  
    120. void
    121. lcd_clear(void)
    122. {
    123. LCD_RS = 0;
    124. lcd_write(0x1);
    125. __delay_ms(2);
    126. }
    127.  
    128. /* write a string of chars to the LCD */
    129.  
    130. void
    131. lcd_puts(const char * s)
    132. {
    133.   __delay_ms(2); // wait
    134. LCD_RS = 1; // write characters
    135. while(*s)
    136. lcd_write(*s++);
    137. }
    138.  
    139. /* write one character to the LCD */
    140.  
    141. void
    142. lcd_putch(char c)
    143. {
    144. LCD_RS = 1; // write characters
    145. lcd_write( c );
    146. }
    147.  
    148.  
    149. /*
    150. * Go to the specified position
    151. */
    152.  
    153. void
    154. lcd_goto(unsigned char pos)
    155. {
    156. LCD_RS = 0;
    157. lcd_write(0x80+pos);
    158. }
    159.  
    160. /* initialise the LCD - put into 4 bit mode */
    161. void
    162. lcd_init()
    163. {
    164. char init_value;
    165.  
    166. // ADCON1 = 0x06; // Disable analog pins on PORTA
    167.  
    168. init_value = 0x3;
    169.  
    170. LCD_RS = 0;
    171. LCD_EN = 0;
    172. LCD_RW = 0;
    173.  
    174. __delay_ms(15); // wait 15mSec after power applied,
    175. LCD_DATA  = init_value;
    176. LCD_STROBE();
    177. __delay_ms(5);
    178. LCD_STROBE();
    179. __delay_us(200);
    180. LCD_STROBE();
    181. __delay_us(200);
    182. LCD_DATA = 2; // Four bit mode
    183. LCD_STROBE();
    184.  
    185. lcd_write(0x28); // Set interface length
    186. lcd_write(0xC); // Display On, Cursor On, Cursor Blink was 0xE
    187. lcd_clear(); // Clear screen
    188. lcd_write(0x6); // Set entry Mode
    189. }
    190.  
    Mod note: Added code-tags, please use them.
     
    Last edited by a moderator: Apr 25, 2016
  4. Hoylegj

    Thread Starter New Member

    Mar 10, 2016
    16
    1
    thank you. Between your 2 posts I now have my code working and a functioning display. Thanks John for you explanation and Picbuster thanks for your code, together they were great. Picbuster, I may try your code next as its much lighter then my code which is based on the microchip code.

    Regards Geoff
     
    JohnInTX likes this.
  5. Picbuster

    Member

    Dec 2, 2013
    373
    50
    It's working pay attention to the content of lcd.h
    I used it for two 2 x 20 displays on the same 18f8722 the only modification is enable display one or display two.
     
    Hoylegj likes this.
  6. nigelwright7557

    Senior Member

    May 10, 2008
    487
    71
    If you read the lcd datasheet it gives a sequence of commands to send to LCD with the correct timings in between data bytes.
     
Loading...