LCD Interface

LCD panels are popular peripherals for 8-bit systems. Those with
Hitachi controllers are easy to control, needing either 7 or 11 pins for
a 4- or 8-bit interface.

The 4-bit interface requires some extra software to split command and data words, and to send and receive bytes in two nibbles.

#pragma option v;
/********************************************************  
 *  Device driver for 4 bit LCD interface using         * 
 *  Hitachi H2570 controllers.  These displays are in   * 
 *  configurations from one line by 16 characters to    * 
 *  4 lines by 40 characters.                           * 
 *                                                      * 
 *  These routines may be adapted for any purpose when  * 
 *  used with the CDS Code Development System.    No    * 
 *  warranty is implied or given as to their usability  * 
 *  for any purpose.                                    * 
 *                                                      * 
 *       (c) Copyright 1990,96                          * 
 *       Byte Craft Limited                             * 
 *       Waterloo, Ontario                              * 
 *       Canada N2J 4E4                                 * 
 *       (519) 888-6911                                 * 
 *                                                      * 
 *       Walter Banks                                   * 
 ********************************************************/ 
 /* 
Please Note! 
The following example is configured for use on the Microchip PIC, 
however these routines are easily portable to other microcontrollers. 
Make sure you include the proper header file and set up the following 
#defines in the appropritea manner for your microcontroller: 

index
LCDdata
LCD_E
LCD_RS 

Furthermore, you must make sure that the ports are configured as outputs, 
consult your microcontroller literature for more information on this. In 
this example the PIC configures PORT and PORTD by setting the TRIS 
register to zero. 

With the inclusion of these changes, this code will run on any 8-bit micro! 
*/ 

#include <16c74.h>
#define index   FSR
#define LCDdata PORTD    /*  Data output         */
#define LCD_E   PORTA.4  /*  Clock bit           */
#define LCD_RS  PORTA.5  /*  Register select bit */ 
char ac;

/******************************************************** 
 *  wLCDdat - Write data word to LCD peripheral         * 
 * Enter with data word in accumulator                  * 
 *        Delay ~120uS after data write                 * 
 ********************************************************/ 

void wLCDdat(unsigned int tempa) 
{
   LCDdata = tempa >> 4;   /* Write HI nibble word to LCD */
   LCD_RS  = 1 ;   /* RS->1 */
   LCD_E   = 1 ;   /* E->1  */
   LCD_E   = 0 ;   /* E->0  */
   LCD_RS  = 0 ;   /* RS->0 */
   LCDdata = tempa & 0x0f; /* Write LO nibble word to LCD */
   LCD_RS  = 1 ;   /* RS->1 */
   LCD_E   = 1 ;   /* E->1  */
   LCD_E   = 0 ;   /* E->0  */
   LCD_RS  = 0 ;   /* RS->0 */ 
   index = 20;
   while (--index); /* 120usec $$$$*/
} 

/*************************************************************/
 
/********************************************************* 
 *  wLCDctrl - Write control word to LCD peripheral      * 
 *  Enter with control word in accumulator               * 
 *  Delay ~4.5mS if A=0x01 or 0x02 else delay ~120uS     * 
 *********************************************************/ 
void wLCDctrl(char ac) 
{
   PORTD   = ac ;
    LCD_E   =  1 ;
    LCD_E   =  0 ;         /* Pulse the eable line */
    index   = 20 ;
    while (--index) ;      /* ((6 * 19) + 2) 120 usec delay loop */
    if (ac <= 2)   {
        while (--index);   /* 4.6 ms or so delay */
        while (--index);
        while (--index);
    }
} 

/*************************************************************/ 

/********************************************************* 
 *  wLCDctrl4 - Write control word to LCD peripheral     * 
 *      configured as a 4 bit interface                  * 
 *     Enter with control word in accumulator               * 
 *       Delay ~4.5mS if A=0x01 or 0x02 else delay ~120uS     * 
 *********************************************************/ 

void wLCDctrl4(unsigned int tempa) 
{
  LCDdata = tempa >> 4; 
  /* Write HI nibble word to LCD */
  LCD_E   = 1 ;  /* E->1  */ 
  LCD_E   = 0 ;  /* E->0  */
  LCDdata = tempa &0x0f; /* Write LO nibble word to LCD */
  LCD_E   = 1 ;  /* E->1  */ 
  LCD_E   = 0 ;  /* E->0  */ 
  index = 20;
  while (--index);  /* 120usec $$$$*/
  if (ac <= 2)   {
    while (--index);   /* 4.6 ms or so delay */
    while (--index);
    while (--index);
  }
} 

/*************************************************************/ 

void initLCD(void) 
/* LCD display peripheral initialization */
{  
   wLCDctrl(0x03) ;   /*  8 Bit mode  */
   wLCDctrl(0x03) ;   /*  8 Bit mode  */
   wLCDctrl(0x03) ;   /*  8 Bit mode  */
   wLCDctrl(0x02) ;   /*  Home        */
   wLCDctrl4(0x24);   /*  Function Set- 4-bit,1-line,5X7 */
   wLCDctrl4(0x0c);   /*  Display on, Cursor off         */
   wLCDctrl4(0x06);   /*  entry mode- Inc addr, no shift */
   wLCDctrl4(0x01);   /*  Clear Display */
} 

/*************************************************************/ 

void putcharLCD(char sci_char)  
/* Send a character to the LCD display */ 
{   
    if ((sci_char == 0x0a) || (sci_char == 0x0d))
    /* Look for a LF */
    {     
        wLCDctrl(0x02) ;        /*  Home        */
        wLCDctrl4(0x01); /*  Clear Display */
    }
    else
        wLCDdat(sci_char);
} 

/*************************************************************/ 

void cputsLCD(char far *__putstr) 
{
    char __ps;
    while((__ps = *__putstr))
    {
        __putstr++;
        if (__ps== 0) break;
        putcharLCD(__ps);
    } 
}
 
/*************************************************************/ 

void main(void) 
{   
    TRISD = 0x00; //this is specific to the PIC! Setting the ports to
    TRISA = 0x00; //outputs! 
    initLCD();
    cputsLCD ("Walter Banks");
    for (;;) ;
}

/*************************************************************/ 

The 8-bit interface to a Hitachi 44780 is straightforward.

 /******************************************************** 
 *  Device driver for 8 bit LCD interface using         * 
 *  Hitachi HD44780 controllers. These displays are in  * 
 *  configurations from one line by 16 characters to    * 
 *  4 lines by 40 characters                            * 
 *                                                     * 
 *  This routines may be adapted for any purpose when   * 
 *  used with the Byte Craft Limited Code Development   * 
 *  systems.  No warranty is implied or given as to     * 
 *  their usability for any purpose.                    * 
 *                                                      * 
 *       (c) Copyright 1990                             * 
 *       Byte Craft Limited                             * 
 *       Waterloo, Ontario                              * 
 *       Canada N2J 4E4                                 * 
 *       (519) 888-6911                                 * 
 *                                                      * 
 *       Walter Banks                                   * 
 ********************************************************/ 
 
registerx index;
#pragma option p ;

 /* 
Please Note! 
The following example easily portable to many microcontrollers. Make 
sure you include the proper header file and set up the following 
#defines in the approprite manner for your microcontroller: 


LCDdata
LCD_E
LCD_RS
LCD_RW  

Furthermore you must make sure that the ports are configured as outputs, 
consult your microcontroller literature for more information on this. 
With the inclusion of these changes, this code will run on any 8-bit 
micro! 
*/ 

#define LCDdata PORTB     /*  Data output         */ 
#define LCD_RS PORTA.0    /*  Register select bit */ 
#define LCD_E  PORTA.2    /*  Clock bit           */ 
#define LCD_RW PORTA.1    /*  Read/Write bit      */
 
/******************************************************** 
 * wLCDdat - Write data word to LCD peripheral          * 
 * Enter with data word in accumulator                  * 
 * Delay ~120uS after data write                        * 
 ********************************************************/ 
 
void wLCDdat(unsigned int tempa)   
{        
    LCD_RW  = 0 ;           /* RW = 0 */
    LCDdata = tempa ;       /* Write word to LCD */
    LCD_RS  = 1 ;           /* RS->1 */
    LCD_E   = 1 ;           /* E->1  */
    LCD_E   = 0 ;           /* E->0  */
    LCD_RS  = 0 ;           /* RS->0 */
    LCD_RW  = 1 ;           /* RW = 1 */ 
    index = 20;
    while (--index);        /* 120usec */   
}
 
/******************************************************** 
 * rLCDdat - Read data word from LCD peripheral         * 
 * Returns data value                                   * 
 * Delay ~120uS after data write                        * 
 ********************************************************/ 
char rLCDdat (void)   
{        
    LCD_RW  = 0 ;           /* RW = 0 */
    LCD_RS  = 1 ;           /* RS->1 */
    LCD_E   = 1 ;           /* E->1  */
    char tempa   = LCDdata;      /* Read from LCD */
    LCD_E   = 0 ;           /* E->0  */
    LCD_RS  = 0 ;           /* RS->0 */
    LCD_RW  = 1 ;           /* RW = 1 */ 
    index = 20;
    while (--index);        /* 120usec */
    return tempa;
}
 
/******************************************************** 
 * rLCDram - Read data word from LCD ram area           * 
 *  Returns data value                              * 
 *    Delay ~120uS after data write                   * 
 ********************************************************/ 
 
char rLCDram (void)
{
    LCD_RW  = 1 ;           /* RW = 1 */
    LCD_RS  = 1 ;           /* RS->1 */
    LCD_E   = 1 ;           /* E->1  */
    char tempa = LCDdata;        /* Read from LCD */
    LCD_E   = 0 ;           /* E->0  */
    LCD_RS  = 0 ;           /* RS->0 */
    LCD_RW  = 0 ;           /* RW = 1 */ 
    index = 20;
    while (--index);        /* 120usec */
    return tempa;
} 

/******************************************************** 
 * wLCDram - Write data word from LCD ram area          * 
 *  Returns data value                              * 
 *    Delay ~120uS after data write                   * 
 ********************************************************/
 
void wLCDram (char tempa)
{
    LCD_RW  = 1 ;           /* RW = 1 */
    LCD_RS  = 1 ;           /* RS->1 */
    LCD_E   = 1 ;           /* E->1  */
    LCDdata = tempa;        /* Read from LCD */
    LCD_E   = 0 ;           /* E->0  */
    LCD_RS  = 0 ;           /* RS->0 */
    LCD_RW  = 0 ;           /* RW = 1 */ 
    index = 20;
    while (--index);        /* 120usec */
}
 
/******************************************************** 
 * rLCDstatus - Read status from LCD peripheral         * 
 *  Returns data value                              * 
 *    Delay ~120uS after data write                   * 
 ********************************************************/ 

char wLCDstatus(void)   
{
    LCD_RW  = 0 ;           /* RW = 0 */
    LCD_E   = 0 ;           /* E->0  */
    LCD_RS  = 0 ;           /* RS->0 */
    LCD_E   = 0 ;           /* E->0  */
    char tempa   = LCDdata;      /* Read from LCD */
    LCD_E   = 1 ;           /* E->1  */
    LCD_RS  = 1 ;           /* RS->1 */
    LCD_RW  = 1 ;           /* RW = 1 */ 
    index = 20;
    while (--index);        /* 120usec 
    return tempa;
}
 
/********************************************************* 
 * wLCDctrl8 - Write control word to LCD peripheral      * 
 *      configured as a 8 bit interface                  * 
 *     Enter with control word in accumulator           * 
 *   Delay ~4.5mS if A=0x01 or 0x02 else delay ~120uS * 
 *********************************************************/

void wLCDctrl8(unsigned int tempa)   
{
    LCD_RW  = 0 ;           /* RW = 0 */
    LCDdata = tempa;        /* Write HI nybble to LCD */
    LCD_E   = 1 ;           /* E->1   */
    LCD_E   = 0 ;           /* E->0   */
    LCD_RW  = 1 ;           /* RW = 1 */
    index = 20;
    while (--index);        /* 120usec */
    if (tempa <= 2)
       {
       while (--index);   /* 4.6 ms or so delay */
       while (--index);
       while (--index);
       }
}
 
void initLCD(void)   
{
    /* LCD display peripheral initialization */
    wLCDctrl8(0x38); /*  Function Set- 4-bit,1-line,5X7 */
    wLCDctrl8(0x38);
    wLCDctrl8(0x38);
    wLCDctrl8(0x0C); /*  Display on, Cursor off        */
    wLCDctrl8(0x01); /*  entry mode- Inc addr, no shift */
    wLCDctrl8(0x06); /*  Clear Display */
} 

void putcharLCD(char sci_char)
/* Send a character to the LCD display */    
{
    if ((sci_char == 0x0a) || (sci_char == 0x0d))   /* Look for a LF */
        wLCDctrl8(0x01); /*  Clear Display */
    else
        wLCDdat(sci_char);
} 

void cputsLCD(char *__putstr)   
{
    while(*__putstr != 0x0)
    {
        wLCDdat((*__putstr));
        ++__putstr;
    }
    /*
    for(int i = 0; i < 5; i++)
    {
        wLCDdat((*__putstr));
        ++__putstr;
    }       
    */
}       

/* Many embedded microcomputers handle arrays better than pointers */

/* #define cputsLCD(s) {char i=0; while(1){ch = s[i++]; \
                     if(ch==0)break;putcharLCD(ch); }} 
*/