MEL PICBASIC Forum - LCD serial backpacks


  • LCD serial backpacks

    This LCD serial backpack code was not originally written by Joe S. It was modified by Darrel for use with DT_INTS. (Edited by Joe S.)

    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.
    It's your backpack program modified for Instant Interrupts.
    Tested it on a 16F877A
    Code:
    ;---- 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
    ' I removed some code here, it seems to require what's left
    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.
    Code:
    '****************************************************************
    '*  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
    This article was originally published in forum thread: LCD serial backpacks started by Joe S. View original post