LCD Serial Backpack
If you need a Serial LCD but do not want to spend money, you can build it yourself.
It uses the DT_INTS to read the serial data on the USART of the PIC.
I know DT_INTS looks intimidating at the beginning, but it's really not that bad, and you don't need to learn assembly language to use it.
But I can understand why you might not want to try it out. The biggest obstacle is that you have to be using MPASM.
So whenever you get around to DT_INTS, you can come back to this thread and try out this program.
Tested it on a 16F877A
;---- Config settings for MPASM ----------------------------------------------
@ __config _HS_OSC & _WDT_OFF & _PWRTE_ON & _MCLRE_ON & _LVP_OFF & _CP_OFF
trisb = %00000010
trisA = %11110011
;----Added by DT--------------------------------------------------------------
INCLUDE "DT_INTS-14.bas"
INCLUDE "ReEnterPBP.bas" ; Include if using PBP interrupts
ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler RX_INT, _serialin, PBP, no
endm
INT_CREATE ; Creates the interrupt processor
ENDASM
@ INT_ENABLE RX_INT ; enable external (INT) interrupts
;-----------------------------------------------------------------------------
' Define LCD registers and bits
Define LCD_DREG PORTB
Define LCD_DBIT 4
Define LCD_RSREG PORTA
Define LCD_RSBIT 0
Define LCD_EREG PORTA
Define LCD_EBIT 1
DEFINE LCD_LINES 4 'Define using a 2 line LCD
DEFINE LCD_COMMANDUS 2000 'Define delay time between sending LCD commands
DEFINE LCD_DATAUS 50 'Define delay time between data sent.
DEFINE OSC 20
DEFINE HSER_RCSTA 90h ' Enable serial port & continuous receive
DEFINE HSER_TXSTA 20h ' Enable transmit, BRGH = 0
DEFINE HSER_SPBRG 32 ' FOR 20MHZ 129 = 2400, 32=9600,25 @ 4 for 2400
DEFINE HSER_CLROERR 1 ' Clear overflow automatically
RCIF VAR PIR1.5 ' Receive interrupt flag (1=full , 0=empty)
TXIF VAR PIR1.4 ' Transmit interrupt flag (1=empty, 0=full)
LED VAR PORTA.4
OERR VAR RCSTA.1 ' Alias OERR (USART Overrun Error Flag)
CREN VAR RCSTA.4 ' Alias CREN (USART Continuous Receive Enable)
buffer_size CON 64 ' Sets the size of the ring buffer, set up from 32
buffer VAR BYTE[buffer_size]' Array variable for holding received characters
index_in VAR BYTE ' Pointer - next empty location in buffer
index_out VAR BYTE ' Pointer - location of oldest character in buffer
bufchar VAR BYTE ' Stores the character retrieved from the buffer
i VAR BYTE ' loop counter
Col VAR BYTE ' Stores location on LCD for text wrapping
errflag VAR BYTE ' Holds error flags
index_in = 0
index_out = 0
i = 0
col = 1
'RxData var byte
CMCON = 7 ' PORTA is digital
Pause 100 ' Wait for LCD to startup
high PortA.2 ' power for backlight
low PortA.3 ' backlight ground
pause 1500
lcdout $FE,1
lcdout $FE,2
LCDOUT "Your Text Goes Here"
PAUSE 2000
' * * * * * * * * * * * * * Main program starts here - blink an LED at 1Hz
loop:
For i = 0 to 10 ' Delay for .02 seconds (10*2mS)
Pause 2 ' Use a short pause within a loop
Next i ' instead of one long pause
For i = 0 to 10 ' Delay for .02 seconds (10*2mS)
Pause 2 ' Use a short pause within a loop
Next i ' instead of one long pause
display: ' dump the buffer to the LCD
IF errflag Then error ' Handle error if needed
IF index_in = index_out Then loop ' loop if nothing in buffer
GoSub getbuf ' Get a character from buffer
LCDOut bufchar ' Send the character to LCD
IF col > 20 Then ' Check for end of line
col = 1 ' Reset LCD location
LCDOut $fe,$c0,REP " "\20 ' Clear line-2 of LCD
LCDOut $FE,2 ' Tell LCD to return home
EndIF
GoTo display ' Check for more characters in buffer
' Subroutines
getbuf: ' move the next character in buffer to bufchar
@ INT_DISABLE RX_INT
index_out = (index_out + 1) ' Increment index_out pointer (0 to 63)
' Reset pointer if outside of buffer
IF index_out > (buffer_size-1) Then index_out = 0
bufchar = buffer[index_out] ' Read buffer location
@ INT_ENABLE RX_INT
Return
error: ' Display error message if buffer has overrun
IF errflag.1 Then ' Determine the error
LCDOut $FE,$c0,"Clearing Display Buffer" ' Display buffer error on
' line-2 and 3 Buff overrun
Else
LCDOut $FE,$D4,"USART Overrun" ' Display usart error on line-4
EndIF
LCDOut $fe,2 ' Send the LCD cursor back to line-1 home
For i = 2 to col ' Loop for each column beyond 1
LCDOut $fe,$14 ' Move the cursor right to the right column
Next i ' $14 = 20 DEC.
errflag = 0 ' Reset the error flag
CREN = 0 ' Disable continuous receive to clear overrun flag
CREN = 1 ' Enable continuous receive
GoTo display ' Errors cleared, time to work.
' * * * * * * * * * * * * * * * Interrupt handler
serialin: ' Buffer the character received
IF OERR Then usart_error ' Check for USART errors
index_in = (index_in + 1) ' Increment index_in pointer (0 to 63)
IF index_in > (buffer_size-1) Then index_in = 0 'Reset pointer if outside of buffer
IF index_in = index_out Then buffer_error ' Check for buffer overrun
HSerin [buffer[index_in]] ' Read USART and store character to next empty location
IF RCIF Then serialin ' Check for another character while we're here
@ INT_RETURN ; Return to program
buffer_error:
errflag.1 = 1 ' Set the error flag for software
' Move pointer back to avoid corrupting the buffer. MIN insures that it ends up within the buffer.
index_in = (index_in - 1) MIN (buffer_size - 1)
HSerin [buffer[index_in]] ' Overwrite the last character stored (resets the interrupt flag)
usart_error:
errflag.0 = 1 ' Set the error flag for hardware
@ INT_RETURN ; Return to program
End
Addendum: By Joe S.
My contribution, aside from asking for help, is in the example below, it is the selectable baud rate. Darrel did the lion's share of the rest, the original program exists on MeLabs site without DT_INTS. Please read the original thread to see the progression of this code.
This is a version of the serial backpack ported to a 16F690 and it features selectable baud rates from a DIP switch attached to the A Port, change the switch, reboot and it works at a different serial baud rate. It continues to use the USART so it will require you to use a pullup resistor and send your data TRUE.
'****************************************************************
'* Name : MyLCD.BAS *
'* Author : Joe Stokes & Darrel Taylor *
'* Notice : [ Copyright (c) 2006 ] *
'* : use it freely, give us credit *
'* Date : 3/17/09 *
'* Version : 1.1 , baud selection added 7/1/09 *
'* Notes : Adapted for PIC 16F690 May 27 2009 *
'* LCD pins 1,3,5, and 16 to ground, pins 2 & 15 to Vcc *
'* D pins are 11,12,13,14, E bit pin 6, R/S bit pin 4 *
'* No contrast pot used. *
'* Dip Switch selectable baud rate from 1200 to 115200 on PortA *
'****************************************************************
@ __config _HS_OSC & _WDT_ON & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _FCMEN_OFF & _BOR_OFF
DEFINE OSC 20
TRISB = %00100000 'PortB.5 RX input
TRISA = %00001111
PORTC = %00000000
TRISC = %00000000
WPUA = %00000000 ; weak pull ups disabled
SSPCON.5 = 0 ' DISABLE ssp
INCLUDE "DT_INTS-14.bas" ; Darrel Taylors instant interrupts
ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler RX_INT, _serialin, ASM, no
endm
INT_CREATE ; Creates the interrupt processor
ENDASM
@ INT_ENABLE RX_INT ; enable external (INT) interrupts
' = = = = = Define LCD registers and bits = = = = = =
DEFINE LCD_DREG PORTC ' Set port C for the data lines
DEFINE LCD_DBIT 4 ' Set top 1/2 of port to use for data
DEFINE LCD_RSREG PORTC 'Set the RS Port and Pin
DEFINE LCD_RSBIT 3 ' Set PortC.0 as R/S bit
DEFINE LCD_EREG PORTB 'Set LCD Enable bit and pin
DEFINE LCD_EBIT 6
DEFINE LCD_BITS 4 ' Set number of data bits
DEFINE LCD_LINES 2 ' Set number of lines on LCD
DEFINE LCD_COMMANDUS 2000 ' Set command delay time in us
Flags = 0
DEFINE LCD_DATAUS 50 ' Set data delay time in us
' = = = = = Set analog functions to off condition = = =
ADCON0 = 0
ADCON1 = 0
ANSEL = 0
ANSELH = 0
CM1CON0 = 0
CM2CON0 = 0
SRCON = 0 ' COMPARATOR SET/RESET LATCH
OPTION_REG = %10000000
CCP1CON = %00000000 'BITS 7:6 DETERMINE HPWM CHANNEL
' 00 = P1A, 01P1D PWM P1A ACTIVE, P1B P1C INACTIVE,10
' P1A P1B PWM, P1C P1D AS PORT PINS
' 11 = P1B PWM, PIC ACTIVE , P1C P1D INACTIVE
' = = = = = Set up hardware usart serial port = = = = = =
' This Sets up the baud rate by setting the SPBRG, RCSTA, TXSTA As Variables
' Defined in the appropriate subdirectories.
' Variables for Usart and select case
A Var Word
B Var Word
C Var Word
D Var Word
E Var Byte
F Var byte
F = PortA
LCDOUT "SETUP"
Setup:
Select Case F
case 0
GoSub One
Case 1
GoSub Two
Case 2
GoSub Three
Case 3
Gosub Four
Case 4
Gosub Five
Case 5
GoSub Six
Case 6
Gosub Seven
Case 7
GoSub Eight
Case 8
GoSub Nine
Case else
GoTo Setup
end select
RCSTA = A ' Enable serial port & continuous receive
TXSTA = B ' Enable transmit, BRGH = 1
SPBRG = C ' 10 = 115200 Baud @ 20MHz, 20MHZ 129 = 2400, 32=9600,25 @ 4 for 2400
DEFINE HSER_CLROERR 1 ' Clear overflow automatically
RCIF VAR PIR1.5 ' Receive interrupt flag (1=full , 0=empty)
TXIF VAR PIR1.4 ' Transmit interrupt flag (1=empty, 0=full)
' = = = = = Setup variables and interrupt flags = = = = = =
buffer_size CON 64 ' Sets the size of the ring buffer.
OERR VAR RCSTA.1 ' Alias OERR (USART Overrun Error Flag)
CREN VAR RCSTA.4 ' Alias CREN (USART Continuous Receive Enable)
index_in VAR BYTE ' Pointer - next empty location in buffer
index_out VAR BYTE ' Pointer - location of oldest character in buffer
bufchar VAR BYTE ' Stores the character retrieved from the buffer
i VAR BYTE ' MainLoop counter
Col VAR BYTE ' Stores location on LCD for text wrapping
errflag VAR BYTE ' Holds error flags
buffer VAR BYTE[buffer_size]' Array variable for holding received characters
' = = = = = Set all index pointers to zero, Coloum to one = = = = = = = =
index_in = 0
index_out = 0
i = 0
col = 1
'PortB.4 = 1
pause 1500 ' Wait for LCD to startup
lcdout $FE,1 ' Clear LCD
lcdout $FE,2, " Copyright 2006 " ' Yeah this has value !
lcdout $fe,$C0,"Thanks Darrel & Joe" ' That would be us !
LCDOUT $FE,$94,#D,#E," BAUD 8 N 1 " '#D & #E hold value of Baud for Splash Display
PAUSE 3000 'Time to read splash screen
lcdout $FE,1 ' Clear LCD
MainLoop:
Pause 2 ' Use a short pause within a MainLoop
display: ' dump the buffer to the LCD
IF errflag Then error ' Handle error if needed
IF index_in = index_out Then MainLoop ' MainLoop if nothing in buffer
GoSub getbuf ' Get a character from buffer
LCDOut bufchar ' Send the character to LCD
IF col > 20 Then ' Check for end of line
col = 1 ' Reset LCD location
LCDOut $fe,$c0,REP " "\20 ' Clear line-2 of LCD
LCDOut $FE,2 ' Tell LCD to return home
EndIF
GoTo display ' Check for more characters in buffer
getbuf: ' move the next character in buffer to bufchar
@ INT_DISABLE RX_INT
index_out = (index_out + 1) ' Increment index_out pointer (0 to 63)
' Reset pointer if outside of buffer
IF index_out > (buffer_size-1) Then index_out = 0
bufchar = buffer[index_out] ' Read buffer location
@ INT_ENABLE RX_INT
Return
error: ' Display error message if buffer has overrun
IF errflag.1 Then ' Determine the error
LCDOut $FE,$c0,"Clearing Display Buffer"
' Display buffer error on
' line-2 and 3 Buff overrun
Else
LCDOut $FE,$D4,"USART Overrun" ' Display usart error on line-4
EndIF
LCDOut $fe,1 ' Reset lcd
For i = 2 to col ' MainLoop for each column beyond 1
LCDOut $fe,$14 ' Move the cursor right to the right column
Next i ' $14 = 20 DEC.
errflag = 0 ' Reset the error flag
CREN = 0 ' Disable continuous receive to clear overrun flag
CREN = 1 ' Enable continuous receive
GoTo display ' Errors cleared, time to work.
' * * * * * * * * * * * * * * * Interrupt handler
serialin:
' Buffer the character received
IF OERR Then usart_error ' Check for USART errors
index_in = (index_in + 1) ' Increment index_in pointer (0 to 63)
IF index_in > (buffer_size-1) Then index_in = 0 'Reset pointer if outside of buffer
IF index_in = index_out Then buffer_error ' Check for buffer overrun
HSerin [buffer[index_in]] ' Read USART and store character to next empty location
IF RCIF Then serialin ' Check for another character while we're here
@ INT_RETURN ; Return to program
buffer_error:
errflag.1 = 1 ' Set the error flag for software
' Move pointer back to avoid corrupting the buffer.
' MIN insures that it ends up within the buffer.
index_in = (index_in - 1) MIN (buffer_size - 1)
HSerin [buffer[index_in]]
' Overwrite the last character stored (resets the interrupt flag)
usart_error:
errflag.0 = 1 ' Set the error flag for hardware
@ INT_RETURN ; Return to program
End
One:
A = $90 ' 115200 Baud @ 20MHz, -1.36%
B = $24
C = 10
D = 11520
E = 0
Return
Two:
A = $90 ' 57600 Baud @ 20MHz, -1.36%
B = $24
C = 21
D = 5760
E = 0
Return
Three:
A = $90 ' 38400 Baud @ 20MHz, -1.36%
B = $24
C = 32
D = 3840
E = 0
Return
Four:
A = $90
B = $24 ' 19200 Baud @ 20MHz, 0.16%
C = 64
D = 1920
E = 0
Return
Five:
A = $90
B = $24 ' 9600 Baud @ 20MHz, 0.16%
C = 129
D = 960
E = 0
Return
Six:
A = $90 ' 4800 Baud @ 20MHz, 0.17%
B = $20
C = 64
D = 480
E = 0
Return
Seven:
A = $90 ' 2400 Baud @ 20MHz, 0.17%
b = $20
C = 129
D = 240
E = 0
Return
Eight:
A = $90 ' 1200 Baud @ 20MHz, 1.75%
B = $20
C = 255
D = 120
E = 0
'If PortA = 9 then GoSub SetLCDContrast
'If PortA = 0 Then Gosub SetLCDBackLightOFF
'If PortA = 11 Then Gosub SetLCDBackLight
Return
Nine:
LCDOut $FE, $80," Error, check baud"
LCDOut $FE, $C0," setting"
return
Ten:' Subroutine Sets LCD Contrast Level
