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

#### Hoylegj

Joined Mar 10, 2016
26

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.
C:
{
GH_delay_ms(50);

// The data bits must be either a 8-bit port or the upper or
// lower 4-bits of a port. These pins are made into inputs
#ifdef  BIT8                                      // 8-bit mode, use whole port
DATA_PORT        = 0;
TRIS_DATA_PORT   = 0x00;
#else                                             // 4-bit mode
#ifdef UPPER                                  // Upper 4-bits of the port
DATA_PORT       &= 0x0f;
TRIS_DATA_PORT  &= 0x0F;
#else                                         // Lower 4-bits of the port
DATA_PORT       &= 0xf0;
TRIS_DATA_PORT  &= 0xF0;
#endif
#endif

TRIS_RW              = 0;                     // All control signals made outputs
TRIS_RS              = 0;
TRIS_E               = 0;
RW_PIN               = 0;                     // R/W pin made low
RS_PIN               = 0;                     // Register select pin made low
E_PIN                = 0;                     // Clock pin made low

// Delay for 15ms to allow for LCD Power on reset
GH_delay_ms(15);
LATAbits.LATA2            = 1;
WriteCmdXLCD(0x28);
WriteCmdXLCD(0x28);
WriteCmdXLCD(0x28);
WriteCmdXLCD(LCD_FUNCTION);                   // 4 bit interface, 2 lines, 5x8 font
WriteCmdXLCD(LCD_DISPLAY_OFF);
WriteCmdXLCD(LCD_CLEAR);                      // Clear
WriteCmdXLCD(LCD_ENTRY_MODE);                 // Increment, with display shift
WriteCmdXLCD(LCD_CURSOR_FWD);                 //
WriteCmdXLCD(LCD_DISP_ON_NO_CURSOR);          // Display on and blink cursor
WriteCmdXLCD(LCD_FUNCTION);                   // 4 bit interface, 2 lines, 5x8 font
}
Mod edit: code tags

#### Attachments

• 42.1 KB Views: 7
Last edited by a moderator:

#### JohnInTX

Joined Jun 26, 2012
4,379
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.

C:
// wait for 15ms power up
WriteNibble(0x3);    // wait >4.1ms after this
delay(4.1ms);
WriteNibble(0x3);// wait >100us after this
delay(100us);
WriteNibble(0x3);
WriteNibble(0x2); // 4 bit interface
// can now check busy flag AND subsequent writes are 8 bits in two 4 bit nibbles.
Good luck.

#### Attachments

• 255.3 KB Views: 7
Last edited:

#### Picbuster

Joined Dec 2, 2013
1,026

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.
C:
{
GH_delay_ms(50);

// The data bits must be either a 8-bit port or the upper or
// lower 4-bits of a port. These pins are made into inputs
#ifdef  BIT8                                      // 8-bit mode, use whole port
DATA_PORT        = 0;
TRIS_DATA_PORT   = 0x00;
#else                                             // 4-bit mode
#ifdef UPPER                                  // Upper 4-bits of the port
DATA_PORT       &= 0x0f;
TRIS_DATA_PORT  &= 0x0F;
#else                                         // Lower 4-bits of the port
DATA_PORT       &= 0xf0;
TRIS_DATA_PORT  &= 0xF0;
#endif
#endif

TRIS_RW              = 0;                     // All control signals made outputs
TRIS_RS              = 0;
TRIS_E               = 0;
RW_PIN               = 0;                     // R/W pin made low
RS_PIN               = 0;                     // Register select pin made low
E_PIN                = 0;                     // Clock pin made low

// Delay for 15ms to allow for LCD Power on reset
GH_delay_ms(15);
LATAbits.LATA2            = 1;
WriteCmdXLCD(0x28);
WriteCmdXLCD(0x28);
WriteCmdXLCD(0x28);
WriteCmdXLCD(LCD_FUNCTION);                   // 4 bit interface, 2 lines, 5x8 font
WriteCmdXLCD(LCD_DISPLAY_OFF);
WriteCmdXLCD(LCD_CLEAR);                      // Clear
WriteCmdXLCD(LCD_ENTRY_MODE);                 // Increment, with display shift
WriteCmdXLCD(LCD_CURSOR_FWD);                 //
WriteCmdXLCD(LCD_DISP_ON_NO_CURSOR);          // Display on and blink cursor
WriteCmdXLCD(LCD_FUNCTION);                   // 4 bit interface, 2 lines, 5x8 font
}
Mod edit: code tags
I used the following codes and it works great.
C:
//==============  lcd.h ================================================

/*
*/

/* write a byte to the LCD in 4 bit mode */

extern void lcd_write(unsigned char);

/* Clear and home the LCD */

extern void lcd_clear(void);

/* write a string of characters to the LCD */

extern void lcd_puts(const char * s);

/* Go to the specified position */

extern void lcd_goto(unsigned char pos);

/* intialize the LCD - call before anything else */

extern void lcd_init(void);

extern void lcd_putch(char);

/* Set the cursor position */

#define lcd_cursor(x) lcd_write(((x)&0x7F)|0x80)

//================================================

#define DR1 0
#define DR2 64
#define DR3 20
#define DR4 84
//=========================================

//=========================================  driver ==================================

/*
* LCD interface example
* Uses routines from delay.c
* This code will interface to a standard LCD controller
* like the Hitachi HD44780. It uses it in 4 bit mode, with
* the hardware connected as follows (the standard 14 pin
* LCD connector is used):
*
* PORTE bits 0-3 are connected to the LCD data bits 4-7 (high nibble)
* PORTH2 bit 3 is connected to the LCD RS input (register select)
* PORTH0 bit 1 is connected to the LCD EN bit (enable)
*
* To use these routines, set up the port I/O (TRISA, TRISD) then
* call lcd_init(), then other routines as required.
*
*/

// #ifndef _XTAL_FREQ
// Unless specified elsewhere, 4MHz system frequency is assumed
#define _XTAL_FREQ 20000000
// #endif

#include "lcd.h"

// ------------- settings used in my pic 18f8722 ---------------------
#define LCD_RS PORTHbits.RH2
#define LCD_RW PORTHbits.RH1
#define LCD_EN PORTHbits.RH0
#define LCD_DATA PORTE

//#define LCD_STROBE() ((LCD_EN = 1),(LCD_EN=0))

//  write a byte to the LCD in 4 bit mode */

#define lcd_cursor(x) lcd_write(((x)&0x7F)|0x80)

//#define lcd_cursor(x) lcd_write(((x)&0x7F)|0x80)

//========== Proto types ======================
extern void lcd_puts(const char * s);
extern void lcd_clear(void);

void LCD_STROBE()
{
LCD_EN=0;
__delay_us(20);
LCD_EN=1;
}

void
lcd_write(unsigned char c)
{
__delay_us(40);
LCD_DATA = ( ( c >> 4 ) & 0x0F );
LCD_STROBE();
LCD_DATA = ( c & 0x0F );
LCD_STROBE();
__delay_us(20);
}

/*
*  Clear and home the LCD
*/

void
lcd_clear(void)
{
LCD_RS = 0;
lcd_write(0x1);
__delay_ms(2);
}

/* write a string of chars to the LCD */

void
lcd_puts(const char * s)
{
__delay_ms(2); // wait
LCD_RS = 1; // write characters
while(*s)
lcd_write(*s++);
}

/* write one character to the LCD */

void
lcd_putch(char c)
{
LCD_RS = 1; // write characters
lcd_write( c );
}

/*
* Go to the specified position
*/

void
lcd_goto(unsigned char pos)
{
LCD_RS = 0;
lcd_write(0x80+pos);
}

/* initialise the LCD - put into 4 bit mode */
void
lcd_init()
{
char init_value;

// ADCON1 = 0x06; // Disable analog pins on PORTA

init_value = 0x3;

LCD_RS = 0;
LCD_EN = 0;
LCD_RW = 0;

__delay_ms(15); // wait 15mSec after power applied,
LCD_DATA  = init_value;
LCD_STROBE();
__delay_ms(5);
LCD_STROBE();
__delay_us(200);
LCD_STROBE();
__delay_us(200);
LCD_DATA = 2; // Four bit mode
LCD_STROBE();

lcd_write(0x28); // Set interface length
lcd_write(0xC); // Display On, Cursor On, Cursor Blink was 0xE
lcd_clear(); // Clear screen
lcd_write(0x6); // Set entry Mode
}

Last edited by a moderator:

#### Hoylegj

Joined Mar 10, 2016
26
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

#### Picbuster

Joined Dec 2, 2013
1,026
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
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.

#### nigelwright7557

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