' LCD Routines for 4 bit data bus
'
' Created: 8/2002 by Eric James
'  * Added XML comments 10/2002 by Eric James
'
' LHB mods by Larry Bradley, 2003.11.20
'  LCDPutC and LCDPuti modifed to use delays after the write rather
' than reading the BUSY bit. Don't need to use the R/W bit on the LCD
' thus saving a port bit.
'
' Setup:
' Before using these routines, you must setup the following variables as boolean
'
' LCD_DATA the port the LCD data bits are on (lower 4 bits of that port)
' LCD_DIR the TRIS register associated with LCD_DATA
' LCD_E
' LCD_RW
' LCD_RS
' LCD_E_DIR
' LCD_RW_DIR
' LCD_RS_DIR
'
' Example with the following setup
' LCD data bits 4-7 are connected to PORTD bits 0-3
' LCD E connected to PORTA.1
' LCD RW connected to PORTA.2
' LCD RS connected to PORTA.3
'
'
'Dim LCD_D4 @ PORTD.0 As Boolean, LCD_D4_DIR @ TRISD.0 As Boolean
'Dim LCD_D5 @ PORTD.1 As Boolean, LCD_D5_DIR @ TRISD.1 As Boolean
'Dim LCD_D6 @ PORTD.2 As Boolean, LCD_D6_DIR @ TRISD.2 As Boolean
'Dim LCD_D7 @ PORTD.3 As Boolean, LCD_D7_DIR @ TRISD.3 As Boolean
'Dim LCD_E  @ PORTA.1 As Boolean, LCD_E_DIR  @ TRISA.1 As Boolean
'Dim LCD_RW @ PORTA.2 As Boolean, LCD_RW_DIR @ TRISA.2 As Boolean
'Dim LCD_RS @ PORTA.3 As Boolean, LCD_RS_DIR @ TRISA.3 As Boolean

' Initialize the LCD module

Sub LCDinit()
' <summary>
' Initialize the LCD module.  The following variables MUST be defined
' in their proper places before using these routines
' <ul>
' <li> LCD_D4, LCD_D4_DIR
' <li> LCD_D5, LCD_D5_DIR
' <li> LCD_D6, LCD_D6_DIR
' <li> LCD_D7, LCD_D7_DIR
' <li> LCD_E,  LCD_E_DIR
' <li> LCD_RW, LCD_RW_DIR
' <li> LCD_RS, LCD_RS_DIR
' </ul>
' </summary>

LCD_E_DIR=0 'configure control lines
LCD_RW_DIR=0
LCD_RS_DIR=0

DelaymS(15)
LCD_RS=0
Call LCDWriteNibble(0b00110000) ' Send control sequence

DelaymS(4)
Call LCDWriteNibble(0b00110000) ' Send control sequence

DelayuS(100)
Call LCDWriteNibble(0b0011000) ' Send control sequence

DelayuS(100)
Call LCDWriteNibble(0b00100000) 'set 4-bit

Call LCDputi(0b0101000) ';#5   Function set
Call LCDputi(0b0000.1101) ';#6  Display = On
Call LCDputi(1) ';#7   Display Clear
Call LCDputi(0b0000.0110) ';#8   Entry Mode
Call LCDputi(0b1000.0000) ';DDRAM addresss 0000
Call LCDputi(0b0000.0010) ' return home

End Sub

' Write a nibble to the LCD
Sub LCDWriteNibble(WREG As uByte)

' <summary>
' Write a nibble to the LCD module.
' </summary>
'
' <param name="WREG"> Write the upper 4 bits of this parameter to the LCD</param>

Dim tmp As uByte

tmp=WREG
' LCD_RS=STATUS_C ' Set the register Select
LCD_RW=0 ' Set write mode

' set data as output
LCD_D4_DIR=0: LCD_D5_DIR=0: LCD_D6_DIR=0: LCD_D7_DIR=0

nop: nop ' wait
LCD_E=1 ' Clock high

' send data
LCD_D7=tmp.7: LCD_D6=tmp.6: LCD_D5=tmp.5: LCD_D4=tmp.4

nop: nop ' wait
LCD_E=0 ' Clock low
End Sub


Sub LCDWrite(WREG As uByte)

' <summary>
' Write a Byte To the LCD
' </summary>

' <param name="WREG">
' Write this value To the LCD module
' </param>

Dim tmp As uByte

tmp=WREG
LCD_RS=STATUS_C
Call LCDWriteNibble(tmp)
swapf tmp,F
Call LCDWriteNibble(tmp)
End Sub

' Read a byte from the LCD
Function LCDRead()
Dim ret As uByte

' <summary>
' Read a byte from the LCD module
' </summary>
'
' <return name="ret">
' The byte read from the LCD module
' </return>

' Set data direction
LCD_D4_DIR=1: LCD_D5_DIR=1: LCD_D6_DIR=1: LCD_D7_DIR=1

LCD_RS=STATUS_C
LCD_RW=1

nop: nop ' wait

LCD_E=1 ' Clock high

nop: nop: nop: nop ' wait

' Get high nibble
ret.7=LCD_D7: ret.6=LCD_D6: ret.5=LCD_D5: ret.4=LCD_D4

LCD_E=0 ' Clock Low

nop: nop: nop: nop ' wait
nop: nop: nop: nop

LCD_E=1 ' Clock high for next nibble

nop: nop ' wait

' Get low nibble
ret.3=LCD_D7: ret.2=LCD_D6: ret.1=LCD_D5: ret.0=LCD_D4

LCD_E=0 ' Clock low

End Function ret


Sub LCDWait()
Dim x As uByte

' <summary>
' Wait on the last command to finish executing on the LCD
' <summary>

x=0xFF
While x.7=1
STATUS_C=0
x=LCDRead()
End While

End Sub

' Return WREG=1 if the LCD is busy, Wreg=0 otherwise
Function LCDisBusy()

' <summary>
' Check To see If the LCD is still busy executing a previous command
' </summary>
'
' <return name="WREG">
' <ul> <li> 1 if the LCD is busy
'  <li> 0 if the LCD is not busy
' </ul>
' </return>

STATUS_C=0
WREG=LCDRead()

If WREG.7=1 Then
WREG=1
Else
WREG=0
End If

End Function WREG


Function LCDgetc()
' <summary>
'   Get the character at the current cursor location
' </summary>

LCDWait()
STATUS_C=1
WREG = LCDRead()

End Function WREG



Sub LCDputc(wreg As uByte)
' <summary>
' Display a character on the LCD
' </summary>
'
' <param name="WREG">
' The value to displayed on the LCD
' </param>

' LHB mod - for WRITE operations, just use a delay after the write

'Call LCDWait() ' WREG is not modified here
STATUS_C=1
Call LCDWrite(wreg)

DelayuS(50) 'LHB MOD
End Sub


Sub LCDputi(wreg As uByte)
' <summary>
' Write an instruction to the LCD
' </summary>
'
' <param name="WREG">
' The instruction to send to the LCD
' </param>

' LHB mod - for  WRITE operations, use a delay
'Call LCDWait() ' WREG is not modified here
STATUS_C=0
Call LCDWrite(wreg)
DelayuS(2000) ' LHB mod
End Sub

' Write a string to the LCD
Sub LCDputs(s As String)
' <summary>
' Display a string on the LCD
' </summary>
'
' <param name="s">
' The string to displayed on the LCD
' </param>

FSR2=Addr(s)

While INDF2<>0
Call LCDputc(POSTINC2)
End While
End Sub

Sub LCDcls()
' <summary> Clear the LCD display </summary>

Call LCDputi(1)
End Sub

Sub LCDLine1()
' <summary>Move the cursor to line 1 of the LCD </summary>
Call LCDputi(128)
End Sub

Sub LCDLine2()
' <summary>Move the cursor to line 2 of the LCD </summary>
Call LCDputi(192)
End Sub

Sub LCDLine3()
' <summary>Move the cursor to line 3 of the LCD </summary>
Call LCDputi(144)
End Sub

Sub LCDLine4()
' <summary>Move the cursor to line 4 of the LCD </summary>
Call LCDputi(208)
End Sub

Sub LCDpos(p As uByte)
' <summary>
' Position the cursor on the LCD
' </summary>

' <param name="p">
' The position on the LCD screen to place the cursor
' <ul>
' <li> Line 1 starts at 128
' <li> Line 2 starts at 192
' <li> Line 3 starts at 144
' <li> Line 4 starts at 208
' </ul>
' </param>
Call LCDWait()
Call lcdputi(128+p)
End Sub