There are many, many queries on this forum about why LCD_NO_RW seems to cause LCD display corruption.
Having spent many hours coding the AVR (arduino Mega 2560) using GCBasic a solution has emerged.
There is a popular 5 pin LCD Arduino shield that requires LCD_NO_RW to be defined.
A secondary problem is that port direction setting for Ports H,I,J,K,L etc does not work. The Arduino LCD shield needs some pins from Port H to work.
As expected the LCD display was corrupting horribly.
This has been solved with the code submitted below.
The modification is in the 4 I/O line subroutines as they are most popular.
Many project developers choose to save 5 pins by defining LCD_NO_RW and LCD_IO 4
The problem lies in the fact that without the nice, crisp LCD_RW control line the LCD controller needs to allowed
sufficient time to process the data/cursor control nibbles being sent.
Having examined the datasheet for the popular Hitachi HD44780 and checking the time delays in the lcd.h library it became clear that the time delays are out by a factor of 15.
In the code below the changes have been commented.
There is a problem with copying 'codified' text in some browsers - all the code is copied without line breaks.
Simply right-click anywhere on the code and select 'View Page source'.
The code will appear in a new window towards the bottom in a useable format.
Just backup your original LCD.h file , create a new LCD.h file and paste this code into it.
' Liquid Crystal Display routines for Great Cow BASIC'Copyright(C)2006-2009HughConsidine,StefanoBonomi' This library is free software; you can redistribute it and/or'modifyitunderthetermsoftheGNULesserGeneralPublic' License as published by the Free Software Foundation; either'version2.1oftheLicense,or(atyouroption)anylaterversion.' This library is distributed in the hope that it will be useful,'butWITHOUTANYWARRANTY;withouteventheimpliedwarrantyof' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU'LesserGeneralPublicLicenseformoredetails.' You should have received a copy of the GNU Lesser General Public'Licensealongwiththislibrary;ifnot,writetotheFreeSoftware' Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA'********************************************************************************'IMPORTANT:'THISFILEISESSENTIALFORSOMEOFTHECOMMANDSINGCBASIC.DONOTALTERTHISFILE'UNLESS YOU KNOW WHAT YOU ARE DOING. CHANGING THIS FILE COULD RENDER SOME GCBASIC'COMMANDSUNUSABLE!'********************************************************************************'Credits:' 4 and 8 bit routines Hugh Considine'2bitroutinesStefanoBonomi' Testing Stefano Adami'ArduinoMODadded10/05/2013.PORTHnothandledcorrectlyinGCbasicsoLCDcorrupting' Added code to ensure display is properly initalized after watchdog reset'FORLCD_NO_RWCHANGEDELAYTIMESIN"LCD NORMAL BYTE WRITE"AND"LCD CURSOR"ROUTINESTO700uS#startupInitLCD'I/O Ports#define LCD_IO 4 'NumberofpinsusedforLCDdatabus(2,4or8)'Sub used to write to LCD. Can be altered to allow custom LCD interfaces.#define LCDWriteByte LCDNormalWriteByte#define LCDReadByte LCDNormalReadByte#define LCD_DB SysLCDTemp.0 'Databit.Usedin2-bitmode#defineLCD_CBSysLCDTemp.0'Clock bit. Used in 2-bit mode#define LCD_DATA_PORT SysLCDTemp 'PorttoconnecttoLCDdatabus.Usedin8-bitmode#defineLCD_DB4SysLCDTemp.0'Output bit to interface with LCD data bus. Used in 4-bit mode#define LCD_DB5 SysLCDTemp.0 'OutputbittointerfacewithLCDdatabus.Usedin4-bitmode#defineLCD_DB6SysLCDTemp.0'Output bit to interface with LCD data bus. Used in 4-bit mode#define LCD_DB7 SysLCDTemp.0 'OutputbittointerfacewithLCDdatabus.Usedin4-bitmode#defineLCD_RSSysLCDTemp.1'Output bit to control LCD Register Select. Used as variable by 2-bit mode, and as a pin in 4 and 8 bit mode. DO NOT CHANGE FOR 2-BIT MODE.#define LCD_RW SysLCDTemp.0 'Outputbittoselectread/write#defineLCD_EnableSysLCDTemp.0'Output bit to enable/disable LCD#define LCD_RSTemp SysLCDTemp.2'MiscSettings#defineLCD_Write_Delay5010us#defineFLASH2'#define LCD_NO_RW'Linesforbargraph#defineLCD_BAR_EMPTYb'00010001'#defineLCD_BAR_FULL255SubPUT(InLCDPutLine,InLCDPutColumn,InLCDChar)LOCATELCDPutLine,LCDPutColumnSetLCD_RSonLCDWriteByte(LCDChar)EndSub'GET not available in 2-bit modeFunction GET (LCDPutLine, LCDPutColumn) Locate LCDPutLine, LCDPutColumn Set LCD_RS on GET = LCDReadByteEnd Function'LCDColumnis0toscreenwidth-1,LCDLineis0toscreenheight-1SubLOCATE(InLCDLine,InLCDColumn)SetLCD_RSOffIfLCDLine>1ThenLCDLine=LCDLine-2LCDColumn=LCDColumn+20EndIfLCDWriteByte(0x80or0x40*LCDLine+LCDColumn)Wait510usEndSubSubCLSSETLCD_RSOFF'Clear screen LCDWriteByte (b'00000001') Wait 2 ms 'MovetostartofvisibleDDRAMLCDWriteByte(0x80)Wait1010usEndSub'Compatibility with older programs#define LCDInt Print#define LCDWord Print'StringoutputsubPrint(PrintDataAsString)'PrintLen = LEN(PrintData$) PrintLen = PrintData(0) If PrintLen = 0 Then Exit Sub Set LCD_RS On 'WriteDataForSysPrintTemp=1ToPrintLenLCDWriteBytePrintData(SysPrintTemp)NextEndSubSubPrint(InLCDValue)LCDValueTemp=0SetLCD_RSOnIFLCDValue>=100ThenLCDValueTemp=LCDValue/100LCDValue=SysCalcTempXLCDWriteByte(LCDValueTemp+48)EndIfIfLCDValueTemp>0Then'**new code because or command doesn'tworkonAVRLCDValueTemp=LCDValue/10LCDValue=SysCalcTempXLCDWriteByte(LCDValueTemp+48)EndIfgotoskip_or_thingyIfLCDValue>=10Then'**new or command doesn'tworkonAVRLCDValueTemp=LCDValue/10LCDValue=SysCalcTempXLCDWriteByte(LCDValueTemp+48)EndIfskip_or_thingy:
LCDWriteByte(LCDValue+48)EndSubSubPrint(InLCDValueAsWord)DimSysCalcTempXAsWordSetLCD_RSOnLCDValueTemp=0IfLCDValue>=10000thenLCDValueTemp=LCDValue/10000[word]LCDValue=SysCalcTempXLCDWriteByte(LCDValueTemp+48)GotoLCDPrintWord1000EndIfIfLCDValue>=1000thenLCDPrintWord1000:
LCDValueTemp=LCDValue/1000[word]LCDValue=SysCalcTempXLCDWriteByte(LCDValueTemp+48)GotoLCDPrintWord100EndIfIfLCDValue>=100thenLCDPrintWord100:
LCDValueTemp=LCDValue/100[word]LCDValue=SysCalcTempXLCDWriteByte(LCDValueTemp+48)GotoLCDPrintWord10EndIfIfLCDValue>=10thenLCDPrintWord10:
LCDValueTemp=LCDValue/10[word]LCDValue=SysCalcTempXLCDWriteByte(LCDValueTemp+48)EndIfLCDWriteByte(LCDValue+48)EndSubSubPrint(InLCDValueIntAsInteger)DimLCDValueAsWord'If sign bit is on, print - sign and then negate If LCDValueInt.15 = On Then LCDWriteChar("-") LCDValue = -LCDValueInt 'Signbitoff,sojustcopyvalueElseLCDValue=LCDValueIntEndIf'Use Print(word) to display value Print LCDValueEnd Subsub LCDHex(In LCDValue) LCDValueTemp = 0 Set LCD_RS On IF LCDValue >= 0x10 then LCDValueTemp = LCDValue / 0x10 LCDValue = SysCalcTempX LCDHexValueTemp = LCDValueTemp if LCDHexValueTemp > 9 then LCDHexValueTemp = LCDHexValueTemp + 7 LCDWriteByte(LCDHexValueTemp + 48) end if LCDHexValueTemp = LCDValue if LCDHexValueTemp > 9 then LCDHexValueTemp = LCDHexValueTemp + 7 LCDWriteByte (LCDHexValueTemp + 48)end subsub LCDWriteChar(In LCDChar) set LCD_RS on LCDWriteByte(LCDChar)end subfunction LCDReady #IFDEF LCD_NO_RW Wait 10 ms LCDReady = TRUE exit function #ENDIF #IFNDEF LCD_NO_RW #IFDEF LCD_IO 2 LCDReady = TRUE exit function #ENDIF #IFDEF LCD_IO 4,8 LCDReady = FALSE LCD_RSTemp = LCD_RS SET LCD_RW ON SET LCD_RS OFF Wait 5 10us SET LCD_Enable ON Wait 5 10us #IFDEF LCD_IO 4 dir LCD_DB7 IN '**newcode#IFDEFAVRTHEN'added this poke routine as port H is not handeled properly on Arduino tweak = peek(0x101) 'changesporth.4toinputwhilepreservingotherportbitdirectionstweak.4=0'this is specifically for the Arduino to work with an LCD poke (0x101,tweak) 'b'01101000'setportHpindirections(DDRHregister)manually*NEEDtoPOKEthisvalue.compileruseofDIRdoesn't work 'useportH3,4,5,6asoutputforLCD.1=output,0=input' porth.3 = LCD bit 6 'porth.4=LCDbit7' porth.5 = LCD RS 'porth.6=LCDenable' portb.4 = LCD backlight ("0" = off) #ENDIF if LCD_DB7 OFF THEN LCDReady = TRUE #ENDIF #IFDEF LCD_IO 8 dir LCD_DATA_PORT In if LCD_DATA_PORT.7 OFF THEN LCDReady = TRUE #ENDIF SET LCD_Enable OFF wait 25 10us LCD_RS = LCD_RSTemp #ENDIF #ENDIFend functionsub LCDNormalWriteByte(In LCDByte) '***USELONGERDELAYSETTINGSIFLCD_NO_RWISDEFINED#IFNDEFLCD_NO_RW#IFDEFLCD_IO4,8waituntilLCDReadysetLCD_RWOFF'Write mode #ENDIF #ENDIF #IFDEF LCD_IO 2 LCD2_NIBBLEOUT Swap4(LCDByte) 'Swapbyte;MostsignificantNIBBLEsentfirstLCD2_NIBBLEOUTLCDByte'Less Significant NIBBLE output #ENDIF #IFDEF LCD_IO 4 'SetpinstooutputDIRLCD_DB4OUTDIRLCD_DB5OUTDIRLCD_DB6OUTDIRLCD_DB7OUT#IFDEFAVR'added this routine as port H is not handled properly on AVR 2560/arduino. Specifically added for Arduino LCD 5 button shield tweak = peek(0x101) 'peekintoregisterforporthpindirectiontweak.3=1'copy register byte to variable and modify bits 3 and 4 to be outputs. preserve direction of other pins tweak.4=1 'pokenewbytebackintoporthpindirectionregisterpoke(0x101,tweak)' b'01111000' set port H pin directions (DDRH register) manually *NEED to POKE this value. compiler use of DIR doesn'twork' use portH 3,4,5,6 as output for LCD . 1= output, 0 = input 'porth.3=LCDbit6' porth.4 = LCD bit 7 'porth.5=LCDRS' porth.6 = LCD enable 'portb.4=LCDbacklight("0"=off)#ENDIF'Write upper nibble to output pins set LCD_DB4 OFF set LCD_DB5 OFF set LCD_DB6 OFF set LCD_DB7 OFF if LCDByte.7 ON THEN SET LCD_DB7 ON if LCDByte.6 ON THEN SET LCD_DB6 ON if LCDByte.5 ON THEN SET LCD_DB5 ON if LCDByte.4 ON THEN SET LCD_DB4 ON 'Pulseenablepin'*** new code added this IFDEF to lengthen delay #IFDEF LCD_NO_RW 'whenLCD_NO_RWisdefined.otherwisedisplaycorruptsWait7010us'300 uS is too fast so use 700 us PULSEOUT LCD_Enable, 70 10us Wait 70 10us #ENDIF #IFNDEF LCD_NO_RW 'IFLCD_RWpinisinusethenuseshortdelaysWait510us'i.e LCD_NO_RW not defined PULSEOUT LCD_Enable, 5 10us Wait 5 10us #ENDIF 'WritelowernibbletooutputpinssetLCD_DB4OFFsetLCD_DB5OFFsetLCD_DB6OFFsetLCD_DB7OFFifLCDByte.3ONTHENSETLCD_DB7ONifLCDByte.2ONTHENSETLCD_DB6ONifLCDByte.1ONTHENSETLCD_DB5ONifLCDByte.0ONTHENSETLCD_DB4ON'Pulse enable pin '***newcodeaddedthisIFDEFtolengthendelay#IFDEFLCD_NO_RW'when LCD_NO_RW is defined. otherwise display corrupts Wait 70 10us '300uSistoofastsouse700usPULSEOUTLCD_Enable,7010usWait7010us#ENDIF#IFNDEFLCD_NO_RW'IF LCD_RW pin is in use then use short delays Wait 5 10us 'i.eLCD_NO_RWnotdefinedPULSEOUTLCD_Enable,510usWait510us#ENDIF'Set data pins low again SET LCD_DB7 OFF SET LCD_DB6 OFF SET LCD_DB5 OFF SET LCD_DB4 OFF #ENDIF #IFDEF LCD_IO 8 'Setdataporttooutput,andwriteavaluetoitDIRLCD_DATA_PORToutLCD_DATA_PORT=LCDByte'Pulse enable pin Wait 5 10us PULSEOUT LCD_Enable, 5 10us Wait 5 10us 'Clearportagain,incaseitissharedwithsomethingelseLCD_DATA_PORT=0#ENDIFendsubSUBLCD2_NIBBLEOUT(InLCD2BYTE)'Set Data and Clock bits off SET LCD_DB OFF SET LCD_CB OFF 'ClearShiftRegisterWithsix0spriortoloadingFORLCDTemp=1TO6SETLCD_CBON' STROBE SET LCD_CB OFF '======NEXTSETLCD_DBON' First bit out to Shift register, always 1 for E gate SET LCD_CB ON 'STROBESETLCD_CBOFF' ====== IF LCD_RS OFF THEN SET LCD_DB OFF 'SecondbitoutequaltoR/SSETLCD_CBON' STROBE SET LCD_CB OFF '======'4 bits Data out to Shift register, starting from Nibble most significant bit FOR LCDTemp = 1 to 4 SET LCD_DB OFF IF LCD2Byte.3 ON THEN SET LCD_DB ON SET LCD_CB ON SET LCD_CB OFF ROTATE LCD2Byte LEFT NEXTSET LCD_DB ON 'LastpulseforNibbleoutput.NotforShiftregisterWAIT1MS' Put E pin on LCD to one through an AND operation SET LCD_DB OFF 'withthefirstbitoutputted(E)ENDSUBfunctionLCDNormalReadByte#IFDEFLCD_NO_RWLCDReadByte=0ExitFunction#ENDIF#IFNDEFLCD_NO_RWsetLCD_RWON'Read mode LCDReadByte = 0 #IFDEF LCD_IO 4 'SetpinstoinputDIRLCD_DB4INDIRLCD_DB5INDIRLCD_DB6INDIRLCD_DB7IN'** new code #IFDEF AVR THEN 'addedthispokeroutineasportHisnothandeledproperlyonArduinotweak=peek(0x101)'changes porth.4 to input while preserving other port bit directions tweak.4 = 0 'thisisspecificallyfortheArduinotoworkwithanLCDpoke(0x101,tweak)' b'01101000' set port H pin directions (DDRH register) manually *NEED to POKE this value. compiler use of DIR doesn'twork' use portH 3,4,5,6 as output for LCD . 1= output, 0 = input 'porth.3=LCDbit6' porth.4 = LCD bit 7 'porth.5=LCDRS' porth.6 = LCD enable 'portb.4=LCDbacklight("0"=off)#ENDIF'Read upper nibble from input pins SET LCD_Enable ON Wait LCD_Write_Delay if LCD_DB7 ON then SET LCDReadByte.7 ON if LCD_DB6 ON THEN SET LCDReadByte.6 ON if LCD_DB5 ON then SET LCDReadByte.5 ON if LCD_DB4 ON THEN SET LCDReadByte.4 ON SET LCD_Enable OFF Wait 2 10us 'ReadlowernibblefrominputpinsSETLCD_EnableONWaitLCD_Write_DelayifLCD_DB7ONthenSETLCDReadByte.3ONifLCD_DB6ONTHENSETLCDReadByte.2ONifLCD_DB5ONthenSETLCDReadByte.1ONifLCD_DB4ONTHENSETLCDReadByte.0ONSETLCD_EnableOFFWait210us#ENDIF#IFDEFLCD_IO8DIRLCD_DATA_PORT255SETLCD_EnableONWaitLCD_Write_DelayLCDReadByte=LCD_DATA_PORTSETLCD_EnableOFFWait210us#ENDIF#ENDIFendfunctionsubInitLCD'copied from source forge to ensure lcd is initialized properly after watchdog reset #IFDEF LCD_IO 2 DIR LCD_DB OUT DIR LCD_CB OUT SET LCD_DB OFF SET LCD_CB OFF Wait 35 ms SET LCD_RS OFF LCD2_NIBBLEOUT 0X03 Wait 5 ms LCD2_NIBBLEOUT 0X03 Wait 1 MS LCD2_NIBBLEOUT 0X03 Wait 1 MS LCD2_NIBBLEOUT 0X02 Wait 1 MS LCDWriteByte 0x28 Wait 1 MS LCDWriteByte 0x08 Wait 1 MS LCDWriteByte 0x01 Wait 5 MS LCDWriteByte 0x06 WAIT 1 MS LCDWriteByte 0x0C WAIT 1 MS #ENDIF #IFDEF LCD_IO 4,8 DIR LCD_DB4 OUT DIR LCD_DB5 OUT DIR LCD_DB6 OUT DIR LCD_DB7 OUT #IFDEF AVR 'addedthisroutineasportHisnothandledproperlyonAVR2560/arduino.SpecificallyaddedforArduinoLCD5buttonshieldtweak=peek(0x101)'peek into register for porth pin direction tweak.3=1 'copyregisterbytetovariableandmodifybits3and4tobeoutputs.preservedirectionofotherpinstweak.4=1'poke new byte back into porth pin direction register poke (0x101,tweak) 'b'01111000'setportHpindirections(DDRHregister)manually*NEEDtoPOKEthisvalue.compileruseofDIRdoesn't work 'useportH3,4,5,6asoutputforLCD.1=output,0=input' porth.3 = LCD bit 6 'porth.4=LCDbit7' porth.5 = LCD RS 'porth.6=LCDenable' portb.4 = LCD backlight ("0" = off) #ENDIF DIR LCD_RS OUT #IFNDEF LCD_NO_RW DIR LCD_RW OUT #ENDIF DIR LCD_Enable OUT SET LCD_RS OFF SET LCD_RW OFF SET LCD_Enable OFF SET LCD_DB4 OFF SET LCD_DB5 OFF SET LCD_DB6 OFF SET LCD_DB7 OFF 'waitformorethan15msafterpowerupWait35ms' Function set (Interface is 8 bits long.) SET LCD_DB4 ON SET LCD_DB5 ON PulseOut LCD_Enable, LCD_Write_Delay Wait 6 ms 'Functionset(Interfaceis8bitslong.)SETLCD_DB4ONSETLCD_DB5ONPulseOutLCD_Enable,LCD_Write_DelayWait6ms' Function set (Interface is 8 bits long.) SET LCD_DB4 ON SET LCD_DB5 ON PulseOut LCD_Enable, LCD_Write_Delay Wait 6 ms #IFDEF LCD_IO 8 LCDWriteByte(b'00111000') #ENDIF #IFDEF LCD_IO 4 'setIOmodeto4bitSETLCD_DB4OFFSETLCD_DB5ONPulseOutLCD_Enable,LCD_Write_DelaySETLCD_RSOFFLCDWriteByte(b'00101000')' function set: display 2 lines wait LCD_Write_Delay #ENDIF LCDWriteByte(b'00001000') '0x08 : displayoffwaitLCD_Write_DelayLCDWriteByte(b'00000001')' 0x01 : display clear wait LCD_Write_Delay LCDWriteByte(b'00000110') 'xx06 : setentrymode(incrementby1,noshift)waitLCD_Write_DelayLCDWriteByte(b'00001100')' 0x0C : display on /cursor off control wait LCD_Write_Delay #endifend subsub LCDCursor(In LCDCRSR) 'CanbeON,FLASHorOFFSetLCD_RWOFFLCDTemp=12'0 or 12 If LCDCRSR = ON Then LCDTemp = 14 '2or12IfLCDCRSR=FLASHThenLCDTemp=15'3 or 12 'IfLCDCRSR=OFFThenLCDTemp=0or12LCDWriteByte(LCDTemp)'(LCDTemp or 12) #IFDEF LCD_NO_RW 'uselongerdelayWait7010us'300 uS is too fast so use 700 us #ENDIF #IFNDEF LCD_NO_RW Wait 5 10us #ENDIFend sub'CreateacustomcharacterinCGRAMsubLCDCreateChar(InLCDCharLoc,LCDCharData())'Store old location #IFDEF LCD_IO 4,8 Set LCD_RS Off LCDLoc = LCDReadByte Set LCDLoc.7 On #ENDIF 'SelectlocationSetLCD_RSOffLCDWriteByte(64+LCDCharLoc*8)wait510us'Write char Set LCD_RS On For LCDTemp = 1 to 8 LCDWriteByte LCDCharData(LCDTemp) wait 5 10us Next 'Restorelocation#IFDEFLCD_IO2setLCD_RSoffLCDWriteByte(0x80)wait510us#ENDIF#IFDEFLCD_IO4,8SetLCD_RSOffLCDWriteByte(LCDLoc)wait510us#ENDIFendsub'Create a graph character in CGRAMSub LCDCreateGraph(In LCDCharLoc, In LCDValue) 'Storeoldlocation#IFDEFLCD_IO4,8SetLCD_RSOffLCDLoc=LCDReadByteSetLCDLoc.7On#ENDIF'Select location Set LCD_RS Off LCDWriteByte (64 + LCDCharLoc * 8) wait 5 10us 'WritecharforgraphSetLCD_RSOnForLCDTemp=8to1IfLCDTemp>LCDValueThenLCDWriteByteLCD_BAR_EMPTYElseLCDWriteByteLCD_BAR_FULLEndIfwait510usNext'Restorelocation#IFDEFLCD_IO2setLCD_RSoffLCDWriteByte(0x80)wait510us#ENDIF#IFDEFLCD_IO4,8SetLCD_RSOffLCDWriteByte(LCDLoc)wait510us#ENDIFEndSub
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I am newbie to GCBasic. This post has helped me in fixing up problem with LCD in Proteus. I was unable to print to 2nd line of the LCD. This lcd.h file have resolve it. Thanks :)
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
There are many, many queries on this forum about why LCD_NO_RW seems to cause LCD display corruption.
Having spent many hours coding the AVR (arduino Mega 2560) using GCBasic a solution has emerged.
There is a popular 5 pin LCD Arduino shield that requires LCD_NO_RW to be defined.
A secondary problem is that port direction setting for Ports H,I,J,K,L etc does not work. The Arduino LCD shield needs some pins from Port H to work.
As expected the LCD display was corrupting horribly.
This has been solved with the code submitted below.
The modification is in the 4 I/O line subroutines as they are most popular.
Many project developers choose to save 5 pins by defining LCD_NO_RW and LCD_IO 4
The problem lies in the fact that without the nice, crisp LCD_RW control line the LCD controller needs to allowed
sufficient time to process the data/cursor control nibbles being sent.
Having examined the datasheet for the popular Hitachi HD44780 and checking the time delays in the lcd.h library it became clear that the time delays are out by a factor of 15.
In the code below the changes have been commented.
There is a problem with copying 'codified' text in some browsers - all the code is copied without line breaks.
Simply right-click anywhere on the code and select 'View Page source'.
The code will appear in a new window towards the bottom in a useable format.
Just backup your original LCD.h file , create a new LCD.h file and paste this code into it.
I am newbie to GCBasic. This post has helped me in fixing up problem with LCD in Proteus. I was unable to print to 2nd line of the LCD. This lcd.h file have resolve it. Thanks :)