/* Delay routtines */
#define FOSC 16000000UL  // Using Internal Clock of 16 MHz
#define	delay_us(x) { unsigned char _dcnt; \
		       _dcnt = (x)/(24000000UL/FOSC)|1; \
		       while(--_dcnt != 0) continue; \
                    }void delay_ms(unsigned int cnt)
{
  unsigned char i;
  do {
    i = 5;
    do {
      delay_us(164);
    } while(--i);
  } while(--cnt);
}

4 bit code for a pic 18f lcd interface

/*
** LCD Routine
** LCD Data RB7,RB6,RB5,RB4
** LCD Control: RC7 -> E-Enable, RC6 -> RS-Register Select, R/W-Always 0
*/
void LCD_putcmd(unsigned char data,unsigned char cmdtype)
{
  // Put the Upper 4 bits data
  PORTB = data & 0xF0;
  RC6=0;         // RS = 0
  RC7=1;         // E = 1  // E=0; write data
  RC7=0;
  delay_us(1);    // Delay 1us for 16 MHz Internal Clock    

  // cmdtype = 0; One cycle write, cmdtype = 1; Two cycle writes
  if (cmdtype) {
    // Put the Lower 4 bits data
    PORTB = (data & 0x0F) << 4;
    RC6=0;       // RS = 0
    RC7=1;       // E = 1   

    // E=0; write data
    RC7=0;
    delay_us(1); // Delay 1us for 16 MHz Internal Clock
  }
  delay_ms(5);             // Wait for busy flag (BF)
}

void LCD_putch(unsigned char data)
{
  // Put the Upper 4 bits data
  PORTB = data & 0xF0;
  RC6=1;         // RS = 1
  RC7=1;         // E = 1  // E=0; write data
  RC7=0;
  delay_us(1);   // Delay 1us for 16 MHz Internal Clock       

  // Put the Lower 4 bits data
  PORTB = (data & 0x0F) << 4;
  RC6=1;         // RS = 1
  RC7=1;         // E = 1 

  // E=0; write data
  RC7=0;
  delay_ms(5);             // Wait for busy flag (BF)
}

void LCD_init(void)
{
  // Wait for more than 15 ms after VCC rises to 4.5 V
  delay_ms(30);  
// Send Command 0x30
  LCD_putcmd(0x30,LCD_1CYCLE);  
// Wait for more than 4.1 ms
  delay_ms(8);  // Send Command 0x30
  LCD_putcmd(0x30,LCD_1CYCLE); 
 // Wait for more than 100 us
  delay_us(200);        
  // Delay 250us for 16 MHz Internal Clock  ; 
 // Send Command 0x30
  LCD_putcmd(0x30,LCD_1CYCLE); 
 // Function set: Set interface to be 4 bits long (only 1 cycle write).
  LCD_putcmd(0x20,LCD_1CYCLE); 
 // Function set: DL=0;Interface is 4 bits, N=1; 2 Lines, F=0; 5x8 dots font)
  LCD_putcmd(0x28,LCD_2CYCLE); 
 // Display Off: D=0; Display off, C=0; Cursor Off, B=0; Blinking Off
  LCD_putcmd(0x08,LCD_2CYCLE); 
 // Display Clear
  LCD_putcmd(0x01,LCD_2CYCLE); 
 // Entry Mode Set: I/D=1; Increament, S=0; No shift
  LCD_putcmd(0x06,LCD_2CYCLE);
  // Display On, Cursor Off
  LCD_putcmd(0x0C,LCD_2CYCLE);
}

void LCD_puts(const char *s)
{
  while(*s != 0) {      // While not Null
    if (*s == '\n')
      LCD_putcmd(LCD_NEXT_LINE,LCD_2CYCLE);  // Goto Second Line
    else
      LCD_putch(*s);
    s++;
  }
}