text: /*****************************************************************************
  Title  :   HD44780 Library
  Author :   SA Development
  Version:   1.11
  *****************************************************************************/
  
  #include "avr\pgmspace.h"
  #include "hd44780.h"
  #include "avr\sfr_defs.h"
  #if (USE_ADELAY_LIBRARY==1)
    #include "adelay.h"
  #else
    #define Delay_ns(__ns) \
      if((unsigned long) (F_CPU/1000000000.0 * __ns) != F_CPU/1000000000.0 * __ns)\
            __builtin_avr_delay_cycles((unsigned long) ( F_CPU/1000000000.0 * __ns)+1);\
      else __builtin_avr_delay_cycles((unsigned long) ( F_CPU/1000000000.0 * __ns))
    #define Delay_us(__us) \
      if((unsigned long) (F_CPU/1000000.0 * __us) != F_CPU/1000000.0 * __us)\
            __builtin_avr_delay_cycles((unsigned long) ( F_CPU/1000000.0 * __us)+1);\
      else __builtin_avr_delay_cycles((unsigned long) ( F_CPU/1000000.0 * __us))
    #define Delay_ms(__ms) \
      if((unsigned long) (F_CPU/1000.0 * __ms) != F_CPU/1000.0 * __ms)\
            __builtin_avr_delay_cycles((unsigned long) ( F_CPU/1000.0 * __ms)+1);\
      else __builtin_avr_delay_cycles((unsigned long) ( F_CPU/1000.0 * __ms))
    #define Delay_s(__s) \
      if((unsigned long) (F_CPU/1.0 * __s) != F_CPU/1.0 * __s)\
            __builtin_avr_delay_cycles((unsigned long) ( F_CPU/1.0 * __s)+1);\
      else __builtin_avr_delay_cycles((unsigned long) ( F_CPU/1.0 * __s))
  #endif
  
  #if !defined(LCD_BITS) || (LCD_BITS!=4 && LCD_BITS!=8)
    #error LCD_BITS is not defined or not valid.
  #endif
  
  #if !defined(WAIT_MODE) || (WAIT_MODE!=0 && WAIT_MODE!=1)
    #error WAIT_MODE is not defined or not valid.
  #endif
  
  #if !defined(RW_LINE_IMPLEMENTED) || (RW_LINE_IMPLEMENTED!=0 && RW_LINE_IMPLEMENTED!=1)
    #error RW_LINE_IMPLEMENTED is not defined or not valid.
  #endif
  
  #if (WAIT_MODE==1 && RW_LINE_IMPLEMENTED!=1)
    #error WAIT_MODE=1 requires RW_LINE_IMPLEMENTED=1.
  #endif
  
  #if !defined(LCD_DISPLAYS) || (LCD_DISPLAYS<1) || (LCD_DISPLAYS>4)
    #error LCD_DISPLAYS is not defined or not valid.
  #endif
  
  // Constants/Macros
  #define PIN(x) (*(&x - 2))           // Address of Data Direction Register of Port X
  #define DDR(x) (*(&x - 1))           // Address of Input Register of Port X
  
  //PORT defines
  #define lcd_rs_port_low() LCD_RS_PORT&=~_BV(LCD_RS_PIN)
  #if RW_LINE_IMPLEMENTED==1
    #define lcd_rw_port_low() LCD_RW_PORT&=~_BV(LCD_RW_PIN)
  #endif
  #define lcd_db0_port_low() LCD_DB0_PORT&=~_BV(LCD_DB0_PIN)
  #define lcd_db1_port_low() LCD_DB1_PORT&=~_BV(LCD_DB1_PIN)
  #define lcd_db2_port_low() LCD_DB2_PORT&=~_BV(LCD_DB2_PIN)
  #define lcd_db3_port_low() LCD_DB3_PORT&=~_BV(LCD_DB3_PIN)
  #define lcd_db4_port_low() LCD_DB4_PORT&=~_BV(LCD_DB4_PIN)
  #define lcd_db5_port_low() LCD_DB5_PORT&=~_BV(LCD_DB5_PIN)
  #define lcd_db6_port_low() LCD_DB6_PORT&=~_BV(LCD_DB6_PIN)
  #define lcd_db7_port_low() LCD_DB7_PORT&=~_BV(LCD_DB7_PIN)
  
  #define lcd_rs_port_high() LCD_RS_PORT|=_BV(LCD_RS_PIN)
  #if RW_LINE_IMPLEMENTED==1
    #define lcd_rw_port_high() LCD_RW_PORT|=_BV(LCD_RW_PIN)
  #endif
  #define lcd_db0_port_high() LCD_DB0_PORT|=_BV(LCD_DB0_PIN)
  #define lcd_db1_port_high() LCD_DB1_PORT|=_BV(LCD_DB1_PIN)
  #define lcd_db2_port_high() LCD_DB2_PORT|=_BV(LCD_DB2_PIN)
  #define lcd_db3_port_high() LCD_DB3_PORT|=_BV(LCD_DB3_PIN)
  #define lcd_db4_port_high() LCD_DB4_PORT|=_BV(LCD_DB4_PIN)
  #define lcd_db5_port_high() LCD_DB5_PORT|=_BV(LCD_DB5_PIN)
  #define lcd_db6_port_high() LCD_DB6_PORT|=_BV(LCD_DB6_PIN)
  #define lcd_db7_port_high() LCD_DB7_PORT|=_BV(LCD_DB7_PIN)
  
  #define lcd_rs_port_set(value) if (value) lcd_rs_port_high(); else lcd_rs_port_low();
  #if RW_LINE_IMPLEMENTED==1
    #define lcd_rw_port_set(value) if (value) lcd_rw_port_high(); else lcd_rw_port_low();
  #endif
  #define lcd_db0_port_set(value) if (value) lcd_db0_port_high(); else lcd_db0_port_low();
  #define lcd_db1_port_set(value) if (value) lcd_db1_port_high(); else lcd_db1_port_low();
  #define lcd_db2_port_set(value) if (value) lcd_db2_port_high(); else lcd_db2_port_low();
  #define lcd_db3_port_set(value) if (value) lcd_db3_port_high(); else lcd_db3_port_low();
  #define lcd_db4_port_set(value) if (value) lcd_db4_port_high(); else lcd_db4_port_low();
  #define lcd_db5_port_set(value) if (value) lcd_db5_port_high(); else lcd_db5_port_low();
  #define lcd_db6_port_set(value) if (value) lcd_db6_port_high(); else lcd_db6_port_low();
  #define lcd_db7_port_set(value) if (value) lcd_db7_port_high(); else lcd_db7_port_low();
  
  //PIN defines
  #define lcd_db0_pin_get() (((PIN(LCD_DB0_PORT) & _BV(LCD_DB0_PIN))==0)?0:1)
  #define lcd_db1_pin_get() (((PIN(LCD_DB1_PORT) & _BV(LCD_DB1_PIN))==0)?0:1)
  #define lcd_db2_pin_get() (((PIN(LCD_DB2_PORT) & _BV(LCD_DB2_PIN))==0)?0:1)
  #define lcd_db3_pin_get() (((PIN(LCD_DB3_PORT) & _BV(LCD_DB3_PIN))==0)?0:1)
  #define lcd_db4_pin_get() (((PIN(LCD_DB4_PORT) & _BV(LCD_DB4_PIN))==0)?0:1)
  #define lcd_db5_pin_get() (((PIN(LCD_DB5_PORT) & _BV(LCD_DB5_PIN))==0)?0:1)
  #define lcd_db6_pin_get() (((PIN(LCD_DB6_PORT) & _BV(LCD_DB6_PIN))==0)?0:1)
  #define lcd_db7_pin_get() (((PIN(LCD_DB7_PORT) & _BV(LCD_DB7_PIN))==0)?0:1)
  
  //DDR defines
  #define lcd_rs_ddr_low() DDR(LCD_RS_PORT)&=~_BV(LCD_RS_PIN)
  #if RW_LINE_IMPLEMENTED==1
    #define lcd_rw_ddr_low() DDR(LCD_RW_PORT)&=~_BV(LCD_RW_PIN)
  #endif
  #define lcd_db0_ddr_low() DDR(LCD_DB0_PORT)&=~_BV(LCD_DB0_PIN)
  #define lcd_db1_ddr_low() DDR(LCD_DB1_PORT)&=~_BV(LCD_DB1_PIN)
  #define lcd_db2_ddr_low() DDR(LCD_DB2_PORT)&=~_BV(LCD_DB2_PIN)
  #define lcd_db3_ddr_low() DDR(LCD_DB3_PORT)&=~_BV(LCD_DB3_PIN)
  #define lcd_db4_ddr_low() DDR(LCD_DB4_PORT)&=~_BV(LCD_DB4_PIN)
  #define lcd_db5_ddr_low() DDR(LCD_DB5_PORT)&=~_BV(LCD_DB5_PIN)
  #define lcd_db6_ddr_low() DDR(LCD_DB6_PORT)&=~_BV(LCD_DB6_PIN)
  #define lcd_db7_ddr_low() DDR(LCD_DB7_PORT)&=~_BV(LCD_DB7_PIN)
  
  #define lcd_rs_ddr_high() DDR(LCD_RS_PORT)|=_BV(LCD_RS_PIN)
  #if RW_LINE_IMPLEMENTED==1
    #define lcd_rw_ddr_high() DDR(LCD_RW_PORT)|=_BV(LCD_RW_PIN)
  #endif
  #define lcd_db0_ddr_high() DDR(LCD_DB0_PORT)|=_BV(LCD_DB0_PIN)
  #define lcd_db1_ddr_high() DDR(LCD_DB1_PORT)|=_BV(LCD_DB1_PIN)
  #define lcd_db2_ddr_high() DDR(LCD_DB2_PORT)|=_BV(LCD_DB2_PIN)
  #define lcd_db3_ddr_high() DDR(LCD_DB3_PORT)|=_BV(LCD_DB3_PIN)
  #define lcd_db4_ddr_high() DDR(LCD_DB4_PORT)|=_BV(LCD_DB4_PIN)
  #define lcd_db5_ddr_high() DDR(LCD_DB5_PORT)|=_BV(LCD_DB5_PIN)
  #define lcd_db6_ddr_high() DDR(LCD_DB6_PORT)|=_BV(LCD_DB6_PIN)
  #define lcd_db7_ddr_high() DDR(LCD_DB7_PORT)|=_BV(LCD_DB7_PIN)
  
  #define lcd_rs_ddr_set(value) if (value) lcd_rs_ddr_high(); else lcd_rs_ddr_low();
  #if RW_LINE_IMPLEMENTED==1
    #define lcd_rw_ddr_set(value) if (value) lcd_rw_ddr_high(); else lcd_rw_ddr_low();
  #endif
  #define lcd_db0_ddr_set(value) if (value) lcd_db0_ddr_high(); else lcd_db0_ddr_low();
  #define lcd_db1_ddr_set(value) if (value) lcd_db1_ddr_high(); else lcd_db1_ddr_low();
  #define lcd_db2_ddr_set(value) if (value) lcd_db2_ddr_high(); else lcd_db2_ddr_low();
  #define lcd_db3_ddr_set(value) if (value) lcd_db3_ddr_high(); else lcd_db3_ddr_low();
  #define lcd_db4_ddr_set(value) if (value) lcd_db4_ddr_high(); else lcd_db4_ddr_low();
  #define lcd_db5_ddr_set(value) if (value) lcd_db5_ddr_high(); else lcd_db5_ddr_low();
  #define lcd_db6_ddr_set(value) if (value) lcd_db6_ddr_high(); else lcd_db6_ddr_low();
  #define lcd_db7_ddr_set(value) if (value) lcd_db7_ddr_high(); else lcd_db7_ddr_low();
  
  #if (WAIT_MODE==1 && RW_LINE_IMPLEMENTED==1)
  static unsigned char PrevCmdInvolvedAddressCounter=0;
  #endif
  
  #if (LCD_DISPLAYS>1)
  static unsigned char ActiveDisplay=1;
  #endif
  
  static inline void lcd_e_port_low()
  {
    #if (LCD_DISPLAYS>1)
    switch (ActiveDisplay)
      {
        case 2 : LCD_E2_PORT&=~_BV(LCD_E2_PIN);
                 break;
        #if (LCD_DISPLAYS>=3)
        case 3 : LCD_E3_PORT&=~_BV(LCD_E3_PIN);
                 break;
        #endif
        #if (LCD_DISPLAYS==4)
        case 4 : LCD_E4_PORT&=~_BV(LCD_E4_PIN);
                 break;
        #endif
        default :
    #endif
                  LCD_E_PORT&=~_BV(LCD_E_PIN);
    #if (LCD_DISPLAYS>1)
      }
    #endif
  }
  
  static inline void lcd_e_port_high()
  {
    #if (LCD_DISPLAYS>1)
    switch (ActiveDisplay)
      {
        case 2 : LCD_E2_PORT|=_BV(LCD_E2_PIN);
                 break;
        #if (LCD_DISPLAYS>=3)
        case 3 : LCD_E3_PORT|=_BV(LCD_E3_PIN);
                 break;
        #endif
        #if (LCD_DISPLAYS==4)
        case 4 : LCD_E4_PORT|=_BV(LCD_E4_PIN);
                 break;
        #endif
        default :
    #endif
                  LCD_E_PORT|=_BV(LCD_E_PIN);
    #if (LCD_DISPLAYS>1)
      }
    #endif
  }
  
  static inline void lcd_e_ddr_low()
  {
    #if (LCD_DISPLAYS>1)
    switch (ActiveDisplay)
      {
        case 2 : DDR(LCD_E2_PORT)&=~_BV(LCD_E2_PIN);
                 break;
        #if (LCD_DISPLAYS>=3)
        case 3 : DDR(LCD_E3_PORT)&=~_BV(LCD_E3_PIN);
                 break;
        #endif
        #if (LCD_DISPLAYS==4)
        case 4 : DDR(LCD_E4_PORT)&=~_BV(LCD_E4_PIN);
                 break;
        #endif
        default :
    #endif
                  DDR(LCD_E_PORT)&=~_BV(LCD_E_PIN);
    #if (LCD_DISPLAYS>1)
      }
    #endif
  }
  
  static inline void lcd_e_ddr_high()
  {
    #if (LCD_DISPLAYS>1)
    switch (ActiveDisplay)
      {
        case 2 : DDR(LCD_E2_PORT)|=_BV(LCD_E2_PIN);
                 break;
        #if (LCD_DISPLAYS>=3)
        case 3 : DDR(LCD_E3_PORT)|=_BV(LCD_E3_PIN);
                 break;
        #endif
        #if (LCD_DISPLAYS==4)
        case 4 : DDR(LCD_E4_PORT)|=_BV(LCD_E4_PIN);
                 break;
        #endif
        default :
    #endif
                  DDR(LCD_E_PORT)|=_BV(LCD_E_PIN);
    #if (LCD_DISPLAYS>1)
      }
    #endif
  }
  
  
  /*************************************************************************
  loops while lcd is busy, returns address counter
  *************************************************************************/
  #if (WAIT_MODE==1 && RW_LINE_IMPLEMENTED==1)
  static uint8_t lcd_read(uint8_t rs);
  
  static void lcd_waitbusy(void)
    {
      register uint8_t c;
      unsigned int ul1=0;
  
      while ( ((c=lcd_read(0)) & (1<<LCD_BUSY)) && ul1<((F_CPU/16384>=16)?F_CPU/16384:16))     // Wait Until Busy Flag is Cleared
        ul1++;
    }
  #endif
  
  
  /*************************************************************************
  Low-level function to read byte from LCD controller
  Input:    rs     1: read data
                   0: read busy flag / address counter
  Returns:  byte read from LCD controller
  *************************************************************************/
  #if RW_LINE_IMPLEMENTED==1
  static uint8_t lcd_read(uint8_t rs)
    {
      uint8_t data;
      
      #if (WAIT_MODE==1 && RW_LINE_IMPLEMENTED==1)
      if (rs)
        lcd_waitbusy();
        if (PrevCmdInvolvedAddressCounter)
          {
            Delay_us(5);
            PrevCmdInvolvedAddressCounter=0;
          }
      #endif
  
      if (rs)
        {
          lcd_rs_port_high();                             // RS=1: Read Data
          #if (WAIT_MODE==1 && RW_LINE_IMPLEMENTED==1)
          PrevCmdInvolvedAddressCounter=1;
          #endif
        }
      else lcd_rs_port_low();                           // RS=0: Read Busy Flag
  
      
      lcd_rw_port_high();                               // RW=1: Read Mode
  
      #if LCD_BITS==4
        lcd_db7_ddr_low();                              // Configure Data Pins as Input
        lcd_db6_ddr_low();
        lcd_db5_ddr_low();
        lcd_db4_ddr_low();
  
        lcd_e_port_high();                              // Read High Nibble First
        Delay_ns(500);
  
        data=lcd_db4_pin_get() << 4 | lcd_db5_pin_get() << 5 |
             lcd_db6_pin_get() << 6 | lcd_db7_pin_get() << 7;
  
        lcd_e_port_low();
        Delay_ns(500);
  
        lcd_e_port_high();                              // Read Low Nibble
        Delay_ns(500);
  
        data|=lcd_db4_pin_get() << 0 | lcd_db5_pin_get() << 1 |
              lcd_db6_pin_get() << 2 | lcd_db7_pin_get() << 3;
  
        lcd_e_port_low();
  
        lcd_db7_ddr_high();                             // Configure Data Pins as Output
        lcd_db6_ddr_high();
        lcd_db5_ddr_high();
        lcd_db4_ddr_high();
  
        lcd_db7_port_high();                            // Pins High (Inactive)
        lcd_db6_port_high();
        lcd_db5_port_high();
        lcd_db4_port_high();
      #else //using 8-Bit-Mode
        lcd_db7_ddr_low();                              // Configure Data Pins as Input
        lcd_db6_ddr_low();
        lcd_db5_ddr_low();
        lcd_db4_ddr_low();
        lcd_db3_ddr_low();
        lcd_db2_ddr_low();
        lcd_db1_ddr_low();
        lcd_db0_ddr_low();
  
        lcd_e_port_high();
        Delay_ns(500);
  
        data=lcd_db7_pin_get() << 7 | lcd_db6_pin_get() << 6 |
             lcd_db5_pin_get() << 5 | lcd_db4_pin_get() << 4 |
             lcd_db3_pin_get() << 3 | lcd_db2_pin_get() << 2 |
             lcd_db1_pin_get() << 1 | lcd_db0_pin_get();
  
        lcd_e_port_low();
  
        lcd_db7_ddr_high();                             // Configure Data Pins as Output
        lcd_db6_ddr_high();
        lcd_db5_ddr_high();
        lcd_db4_ddr_high();
        lcd_db3_ddr_high();
        lcd_db2_ddr_high();
        lcd_db1_ddr_high();
        lcd_db0_ddr_high();
  
        lcd_db7_port_high();                            // Pins High (Inactive)
        lcd_db6_port_high();
        lcd_db5_port_high();
        lcd_db4_port_high();
        lcd_db3_port_high();
        lcd_db2_port_high();
        lcd_db1_port_high();
        lcd_db0_port_high();
      #endif
      
      lcd_rw_port_low();
  
      #if (WAIT_MODE==0 || RW_LINE_IMPLEMENTED==0)
      if (rs)
        Delay_us(40);
      else Delay_us(1);
      #endif
      return data;
    }
  
  uint8_t lcd_getc()
    {
      return lcd_read(1);
    }
  
  #endif
  
  /*************************************************************************
  Low-level function to write byte to LCD controller
  Input:    data   byte to write to LCD
            rs     1: write data
                   0: write instruction
  Returns:  none
  *************************************************************************/
  static void lcd_write(uint8_t data,uint8_t rs)
    {
      #if (WAIT_MODE==1 && RW_LINE_IMPLEMENTED==1)
        lcd_waitbusy();
        if (PrevCmdInvolvedAddressCounter)
          {
            Delay_us(5);
            PrevCmdInvolvedAddressCounter=0;
          }
      #endif
  
      if (rs)
        {
          lcd_rs_port_high();                            // RS=1: Write Character
          #if (WAIT_MODE==1 && RW_LINE_IMPLEMENTED==1)
          PrevCmdInvolvedAddressCounter=1;
          #endif
        }
      else
        {
          lcd_rs_port_low();                          // RS=0: Write Command
          #if (WAIT_MODE==1 && RW_LINE_IMPLEMENTED==1)
          PrevCmdInvolvedAddressCounter=0;
          #endif
        }
  
      #if LCD_BITS==4
        lcd_db7_port_set(data&_BV(7));                  //Output High Nibble
        lcd_db6_port_set(data&_BV(6));
        lcd_db5_port_set(data&_BV(5));
        lcd_db4_port_set(data&_BV(4));
  
        Delay_ns(100);
        lcd_e_port_high();
  
        Delay_ns(500);
        lcd_e_port_low();
  
        lcd_db7_port_set(data&_BV(3));                  //Output High Nibble
        lcd_db6_port_set(data&_BV(2));
        lcd_db5_port_set(data&_BV(1));
        lcd_db4_port_set(data&_BV(0));
  
        Delay_ns(100);
        lcd_e_port_high();
  
        Delay_ns(500);
        lcd_e_port_low();
  
        lcd_db7_port_high();                            // All Data Pins High (Inactive)
        lcd_db6_port_high();
        lcd_db5_port_high();
        lcd_db4_port_high();
  
      #else //using 8-Bit_Mode
        lcd_db7_port_set(data&_BV(7));                  //Output High Nibble
        lcd_db6_port_set(data&_BV(6));
        lcd_db5_port_set(data&_BV(5));
        lcd_db4_port_set(data&_BV(4));
        lcd_db3_port_set(data&_BV(3));                  //Output High Nibble
        lcd_db2_port_set(data&_BV(2));
        lcd_db1_port_set(data&_BV(1));
        lcd_db0_port_set(data&_BV(0));
  
        Delay_ns(100);
        lcd_e_port_high();
        Delay_ns(500);
        lcd_e_port_low();
  
        lcd_db7_port_high();                            // All Data Pins High (Inactive)
        lcd_db6_port_high();
        lcd_db5_port_high();
        lcd_db4_port_high();
        lcd_db3_port_high();
        lcd_db2_port_high();
        lcd_db1_port_high();
        lcd_db0_port_high();
      #endif
  
      #if (WAIT_MODE==0 || RW_LINE_IMPLEMENTED==0)
        if (!rs && data<=((1<<LCD_CLR) | (1<<LCD_HOME))) // Is command clrscr or home?
          Delay_us(1640);
        else Delay_us(40);
      #endif
    }
  
  /*************************************************************************
  Send LCD controller instruction command
  Input:   instruction to send to LCD controller, see HD44780 data sheet
  Returns: none
  *************************************************************************/
  void lcd_command(uint8_t cmd)
    {
      lcd_write(cmd,0);
    }
  
  /*************************************************************************
  Set cursor to specified position
  Input:    pos position
  Returns:  none
  *************************************************************************/
  void lcd_goto(uint8_t pos)
    {
      lcd_command((1<<LCD_DDRAM)+pos);
    }
  
  
  /*************************************************************************
  Clear screen
  Input:    none
  Returns:  none
  *************************************************************************/
  void lcd_clrscr()
    {
      lcd_command(1<<LCD_CLR);
    }
  
  
  /*************************************************************************
  Return home
  Input:    none
  Returns:  none
  *************************************************************************/
  void lcd_home()
    {
      lcd_command(1<<LCD_HOME);
    }
  
  
  /*************************************************************************
  Display character
  Input:    character to be displayed
  Returns:  none
  *************************************************************************/
  void lcd_putc(char c)
    {
      lcd_write(c,1);
    }
  
  
  /*************************************************************************
  Display string
  Input:    string to be displayed
  Returns:  none
  *************************************************************************/
  void lcd_puts(const char *s)
    {
      register char c;
  
      while ((c=*s++)) 
        lcd_putc(c);
    }
  
  
  /*************************************************************************
  Display string from flash
  Input:    string to be displayed
  Returns:  none
  *************************************************************************/
  void lcd_puts_P(const char *progmem_s)
    {
      register char c;
  
      while ((c=pgm_read_byte(progmem_s++))) 
        lcd_putc(c);
    }
  
  /*************************************************************************
  Initialize display
  Input:    none
  Returns:  none
  *************************************************************************/
  void lcd_init()
    {
      //Set All Pins as Output
      lcd_e_ddr_high();
      lcd_rs_ddr_high();
      #if RW_LINE_IMPLEMENTED==1
        lcd_rw_ddr_high();
      #endif
      lcd_db7_ddr_high();
      lcd_db6_ddr_high();
      lcd_db5_ddr_high();
      lcd_db4_ddr_high();
      #if LCD_BITS==8
        lcd_db3_ddr_high();
        lcd_db2_ddr_high();
        lcd_db1_ddr_high();
        lcd_db0_ddr_high();
      #endif
  
      //Set All Control Lines Low
      lcd_e_port_low();
      lcd_rs_port_low();
      #if RW_LINE_IMPLEMENTED==1
        lcd_rw_port_low();
      #endif
  
      //Set All Data Lines High
      lcd_db7_port_high();
      lcd_db6_port_high();
      lcd_db5_port_high();
      lcd_db4_port_high();
      #if LCD_BITS==8
        lcd_db3_port_high();
        lcd_db2_port_high();
        lcd_db1_port_high();
        lcd_db0_port_high();
      #endif
  
      //Startup Delay
      Delay_ms(DELAY_RESET);
  
      //Initialize Display
      lcd_db7_port_low();
      lcd_db6_port_low();
      Delay_ns(100);
      lcd_e_port_high();
      Delay_ns(500);
      lcd_e_port_low();
  
      Delay_us(4100);
  
      lcd_e_port_high();
      Delay_ns(500);
      lcd_e_port_low();
  
      Delay_us(100);
  
      lcd_e_port_high();
      Delay_ns(500);
      lcd_e_port_low();
  
      Delay_us(40);
  
      //Init differs between 4-bit and 8-bit from here
      #if (LCD_BITS==4)
        lcd_db4_port_low();
        Delay_ns(100);
        lcd_e_port_high();
        Delay_ns(500);
        lcd_e_port_low();
        Delay_us(40);
  
        lcd_db4_port_low();
        Delay_ns(100);
        lcd_e_port_high();
        Delay_ns(500);
        lcd_e_port_low();
        Delay_ns(500);
  
        #if (LCD_DISPLAYS==1)
          if (LCD_DISPLAY_LINES>1)
            lcd_db7_port_high();
        #else
          unsigned char c;
  
           switch (ActiveDisplay)  {
              case 1 : c=LCD_DISPLAY_LINES; break;
              case 2 : c=LCD_DISPLAY2_LINES; break;
  
              #if (LCD_DISPLAYS>=3)
              case 3 : c=LCD_DISPLAY3_LINES; break;
              #endif
  
              #if (LCD_DISPLAYS==4)
              case 4 : c=LCD_DISPLAY4_LINES; break;
              #endif
           }
          if (c>1)
            lcd_db7_port_high();
        #endif
  
        Delay_ns(100);
        lcd_e_port_high();
        Delay_ns(500);
        lcd_e_port_low();
        Delay_us(40);
      #else
        #if (LCD_DISPLAYS==1)
          if (LCD_DISPLAY_LINES<2)
            lcd_db3_port_low();
        #else
          unsigned char c;
          switch (ActiveDisplay)
            {
              case 1 : c=LCD_DISPLAY_LINES; break;
              case 2 : c=LCD_DISPLAY2_LINES; break;
              #if (LCD_DISPLAYS>=3)
              case 3 : c=LCD_DISPLAY3_LINES; break;
              #endif
              #if (LCD_DISPLAYS==4)
              case 4 : c=LCD_DISPLAY4_LINES; break;
              #endif
            }
          if (c<2)
            lcd_db3_port_low();
        #endif
  
        lcd_db2_port_low();
        Delay_ns(100);
        lcd_e_port_high();
        Delay_ns(500);
        lcd_e_port_low();
        Delay_us(40);
      #endif
  
      //Display Off
      lcd_command(_BV(LCD_DISPLAYMODE));
  
      //Display Clear
      lcd_clrscr();
  
      //Entry Mode Set
      lcd_command(_BV(LCD_ENTRY_MODE) | _BV(LCD_ENTRY_INC));
  
      //Display On
      lcd_command(_BV(LCD_DISPLAYMODE) | _BV(LCD_DISPLAYMODE_ON));
    }
  
  #if (LCD_DISPLAYS>1)
  
  void lcd_use_display(int ADisplay)
  {
     if (ADisplay>=1 && ADisplay<=LCD_DISPLAYS)
        ActiveDisplay=ADisplay;
  }
  #endif
  
  
  