LCD Serial Backpacks

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
Page last modified on March 05, 2018, at 10:09 PM