• PC to PIC® bi-directional Dialogue

    Demonstration of PC to PIC® bi-directional Dialogue... PC User (using something like Hyperterminal) is able to control 5 LEDs using a number of Commands with sub-parameters shows a different approach to Comms in having the PIC parse a received command line rather than WAIT for something valid to arrive and latch on to. Written by Melanie Newman
    Comms1
    ' ======
    ' Melanie Newman
    ' 16 July 2004
    '
    ' Demonstration of PC to PIC bi-directional Dialogue
    ' PC User (using something like Hyperterminal) is able to
    ' to control 5 LEDs using a number of Commands with sub-parameters
    ' shows a different approach to Comms in having the PIC parse
    ' a received command line rather than WAIT for something valid
    ' to arrive and latch on to.

    ' ---------------------------------------------------------------------------
    ' This example for commection to PC at
    ' 300 baud, 8 Data Bits, No Parity, 1 stop Bit, No Flow Control
    ' Set Hyperterminal (or whatever) to above parameters on your chosen COM port
    ' ---------------------------------------------------------------------------

    ' Links with PC Comms Program such as Hyperterminal
    ' Echo's printable characters typed on keyboard back to PC
    ' Performs rudimentary editing with BACKSPACE character
    ' Executes the following Instructions;-
    '
    ' ON x y Turn ON LED on PortA where x=1 to 5 for LED1-LED5
    ' if y is specified (value 1-9), will turn ON for y Seconds an then OFF
    ' ON turn ON all LEDs
    ' ON 0 same as ON
    ' ON 0 y turn ON all LEDs for y Seconds then OFF
    '
    ' OFF x y Turn OFF LED on PortA where x=1 to 4 for LED1-LED4
    ' if y is specified (value 1-9), will turn OFF for y Seconds then ON
    ' OFF turn OFF all LEDs
    ' OFF 0 same as OFF
    ' OFF 0 y Turn OFF all LEDs for y Seconds then ON
    '
    ' BLINK x y
    ' Blink LED y number of times. If x=0 then Blink ALL LEDs y times
    ' valid range for y Blink is 1-60
    '
    ' SWEEP x
    ' valid range for x is 1-99. If omitted defaults to 1.
    '
    ' BEER just for fun!
    '
    ' Program will respond to PC with OK on executing valid command
    ' Program will respond to PC with Bad! if Bad Command, Parameter or Parameter out of range
    ' PC User can type in UPPERCASE or lowercase or any cOmBinATioN

    '
    ' CPU Hardware Layout
    ' -------------------
    '
    ' PortA.0 - LED1-k to PIC pin, LED1-a to VDD via Resistor
    ' PortA.1 - LED2-k to PIC pin, LED2-a to VDD via Resistor
    ' PortA.2 - LED3-k to PIC pin, LED3-a to VDD via Resistor
    ' PortA.3 - LED4-k to PIC pin, LED4-a to VDD via Resistor
    ' PortA.4 - LED5-k to PIC pin, LED5-a to VDD via Resistor
    ' PortA.5 - N/c
    ' PortA.6 - N/C
    ' PortA.7 - N/C
    '
    ' PortB.0 - N/C
    ' PortB.1 - RX cable via 1K5 Resistor to PC pin 3 on 9-Pin D Connector
    ' PortB.2 - TX cable via 1K5 Resistor to PC pin 2 on 9-Pin D Connector
    ' PortB.3 - N/C
    ' PortB.4 - N/C
    ' PortB.5 - N/C
    ' PortB.6 - N/C
    ' PortB.7 - N/C
    '
    ' Don't forget to connect Vss to PC pin 5 on 9-pin D Connector

    '
    Code:
        '     PIC Defines
        '     -----------
        @ DEVICE pic16F628, INTRC_OSC_NOCLKOUT
            ' System Clock Options    
        @ DEVICE pic16F628, WDT_ON
            ' Watchdog Timer
        @ DEVICE pic16F628, PWRT_ON
            ' Power-On Timer
        @ DEVICE pic16F628, MCLR_OFF
            ' Master Clear Options (Internal)
        @ DEVICE pic16F628, BOD_ON
            ' Brown-Out Detect
        @ DEVICE pic16F628, LVP_OFF
            ' Low-Voltage Programming
        @ DEVICE pic16F628, CPD_OFF
            ' Data Memory Code Protect
        @ DEVICE pic16F628, PROTECT_OFF
            ' Program Code Protection
    
        '
        '    Debug (Communication) Defines (Transmit)
        '    ----------------------------------------
        DEFINE DEBUG_REG PORTB
        DEFINE DEBUG_BIT 2
        DEFINE DEBUG_BAUD 300
        DEFINE DEBUG_MODE 1
    
        '
        '    DEBUG (Communication) Defines (Receive)
        '    ----------------------------------------
        DEFINE DEBUGIN_REG PORTB
        DEFINE DEBUGIN_BIT 1
        DEFINE DEBUGIN_BAUD 300
        DEFINE DEBUGIN_MODE 1
    
        '
        '    EEPROM Data 
        '    -----------
        '    The FIRST character of each line holds the Command Word LENGTH
        '    and the remaining 7 characters are the actual COMMAND WORD
        '    Space allocated for 10 commands although I'm only using the first five
        '    See CONSTANT CommandMax if you want to make the table larger or smaller
        '    Commands here should be in UPPERCASE although the PC can send aNyThiNg.
    
        '
        Data    @0,2,"ON",0,0,0,0,0
        Data    3,"OFF",0,0,0,0
        Data    5,"BLINK",0,0
        Data    5,"SWEEP",0,0
        Data    4,"BEER",0,0,0
        Data    0,0,0,0,0,0,0,0
        Data    0,0,0,0,0,0,0,0
        Data    0,0,0,0,0,0,0,0
        Data    0,0,0,0,0,0,0,0
        Data    0,0,0,0,0,0,0,0
    
        '
        '    RAM Assignments and Variables
        '    -----------------------------
        BadFlag var BIT            ' Flag for Bad Command
        CounterA var BYTE        ' Just a Counter
        CounterB var BYTE        ' Just a Counter
        CounterC var BYTE        ' Just a Counter
        CounterW var WORD        ' Word-sized Counter
        Command var BYTE        ' Holds the Command action to execute
        CommsBuffer var BYTE [10]    ' Max Comms Command Line size
        CommsPointer var BYTE        ' Pointer to data in Comms Buffer
        LEDStatus var BYTE
        DataA var BYTE            ' Usage as Data Byte
        Xvariable var BYTE        ' 1st Numeric Variable
        Yvariable var BYTE        ' 2nd Numeric Variable
    
        '
        '    Program Constants
        '    -----------------
        BufMax con 10            ' Max size of data Buffer
        CommandMax con 10        ' Max number of COMMANDS to be processed
    
    
        '
        '    Start - Initialise Processor
        '    ============================
        TRISA=%00000000
        TRISB=%00000010
        Xvariable=0:Gosub LEDsOFF    ' All LEDs OFF
        '
        '    Clear Buffer ready for start of New Command Line
        '    ------------------------------------------------
    RestartLine:
        For CounterA=1 to BufMax
            CommsBuffer[CounterA-1]=0
            Next CounterA
        CommsPointer=0            ' Set Pointer to Start of Buffer
        '
        '    Communications (Closed) Loop
        '    ----------------------------
    ReadLoop:
        DEBUGIN [DataA]
        If DataA<32 then 
            If DataA=8 then                 ' Process BACKSPACE Key
                If CommsPointer>0 then             ' ---------------------
                    CommsPointer=CommsPointer-1    ' Rewind one position
                    CommsBuffer(CommsPointer)=0    ' Erase character in Buffer
                    DEBUG $08,$20,$08        ' Echo Erase sequence to PC
                    Goto ReadLoop
                    endif
                endif
            If DataA=13 then goto ENTERKey
            Goto ReadLoop
            endif
        If DataA>126 then goto ReadLoop
        DEBUG DataA            ' Only Echo Printable Characters
        If DataA>96 then        ' Convert all alphabetics to UPPERCASE
            If DataA<123 then DataA=DataA-32
            endif
        CommsBuffer(CommsPointer)=DataA    ' Save to Buffer
        CommsPointer=CommsPointer+1    ' Bump Pointer
        If CommsPointer<10 then goto ReadLoop
                        ' Loop for next character
        '
        '    Process [ENTER] Key
        '    -------------------
        '    also execute if Command Buffer exceeded
    ENTERKey:
            '
            '    This section Parses the Command Line
            '    ====================================
                '
                '    Look for Command WORD 
                '    (scan through available Command vocabulary)
                '    -------------------------------------------
        Gosub LSpace            ' Remove Leading Blanks
        Gosub REnd            ' Locate Command Word End
        If CounterA=0 then goto EchoCRLF
                        ' Nothing to Process
        For Command=1 to CommandMax
            BadFlag=0
            CounterB=(Command-1)*8
            Read CounterB,DataA    ' Get Preset Command word Length
            If DataA=CounterA then    ' If Length correct, process entire word
                For CounterC=1 to CounterA
                    CounterB=CounterB+1
                    Read CounterB,DataA
                    If CommsBuffer(CounterC-1)<>DataA then BadFlag=1
                    Next CounterC
                If BadFlag=0 then goto GoodCommand
                endif
            Next Command
                '
                '    Bad Command Word
                '    ----------------
    BadMove:
        DEBUG REP $00\8,13,10,"Bad!"
                        ' Tell User No Cigar
        
    EchoCRLF:
        DEBUG 13,10            ' New Line
        Goto RestartLine        ' Loop Round and Do again
    
                '
                '    Scan for First Numeric Variable (if any)
                '    ----------------------------------------
    GoodCommand:
        Gosub ShuffleData        ' Advance Command Line to start of next Word (if any)
        Gosub REnd            ' Locate End of next word
        Gosub GetNumericWord        ' Get numeric value
        If BadFlag=1 then goto BadMove    ' Invalid Data
        Xvariable=DataA            ' Save 1st Numeric Variable
                '
                '    Now check for 2nd Numeric Variable (if any) on the Command Line
                '    ---------------------------------------------------------------
        Gosub ShuffleData        ' Advance Command Line to start of next (last) Word (if any)
        Gosub REnd            ' Locate End of word
        Gosub GetNumericWord
        If BadFlag=1 then goto BadMove    ' Invalid Data
        Yvariable=DataA            ' Save 2nd Numeric Variable
        '
        '    Execute Command
        '    ---------------
        If (Command<4 and Xvariable>5) then
            DEBUG REP $00\8,13,10,"No such LED!"
            goto EchoCRLF
            endif
        If Command<3 then
            If Yvariable>9 then goto BadMove
            If Yvariable>1 then gosub WaitMessage
            endif
        If Command=3 then
            If Yvariable>60 then goto BadMove
            If Yvariable>5 then gosub WaitMessage
            endif
        If Command=4 then
            If Xvariable>5 then gosub WaitMessage
            endif
            '
            '    ON LED Command
            '    --------------
        If Command=1 then 
            Gosub LEDsON
            If Yvariable>0 then
                CounterW=Yvariable*1000
                Pause CounterW
                Gosub LEDsOFF
                endif
            endif
            '
            '    OFF LED Command
            '    ---------------
        If Command=2 then 
            Gosub LEDsOFF
            If Yvariable>0 then
                CounterW=Yvariable*1000
                Pause CounterW
                Gosub LEDsON
                endif
            endif
            '
            '    BLINK LED Command
            '    -----------------
        If Command=3 then
            For CounterA=1 to Yvariable
                Gosub LEDsON
                Pause 200
                Gosub LEDsOFF
                Pause 200
                Next CounterA
            endif
            '
            '    SWEEP Command
            '    -------------
        If Command=4 then
            CounterB=Xvariable
            If CounterB<1 then CounterB=1
            For CounterA=1 to CounterB
                For Xvariable=1 to 5
                    Gosub LEDsON
                    Pause 100
                    Gosub LEDsOFF
                    Next XVariable
                Next CounterA
            endif
            '
            '    BEER Command
            '    ------------
        If Command=5 then DEBUG REP $00\8,13,10,"Yes Please!"
        '
        '    Tell User all executed OK
        '    -------------------------
        DEBUG REP $00\8,13,10,"OK"
        Goto EchoCRLF
    
        '
        '    Subroutine Area
        '    ===============
    
        '
        '    Subroutine extracts Numeric Value from Command Line
        '    ---------------------------------------------------
    GetNumericWord:
        DataA=0
        BadFlag=0
        If CounterA>2 then Goto BadWord
        If CounterA>0 then
            CounterB=CommsBuffer(0)
            If CounterB<48 then goto BadWord
            DataA=CounterB-48
            If DataA>9 then goto BadWord
            If CounterA=2 then
                CounterB=CommsBuffer(1)
                If CounterB<48 then goto BadWord
                CounterB=CounterB-48
                If CounterB>9 then goto BadWord
                DataA=DataA*10+CounterB
                endif
            endif
        Return
    BadWord:
        BadFlag=1
        Return
    
        '
        '    Shuffle Data to remove processed word
        '    -------------------------------------
    ShuffleData:
        For CounterB=0 to 9
            CounterC=CounterA+CounterB
            If CounterC<=9 then
                CommsBuffer(CounterB)=CommsBuffer(CounterC)
                else
                CommsBuffer(CounterB)=0
                endif
            Next CounterB
        '
        '    Subroutine removes leading SPACES (Blanks) from Buffer
        '    ------------------------------------------------------
    LSpace:
        If CommsBuffer(0)=32 then
            For CounterA=1 to 9
                CommsBuffer(CounterA-1)=CommsBuffer(CounterA)
                Next CounterA
            CommsBuffer(9)=0
            Goto LSpace
            endif
        Return
    
        '
        '    Subroutine Locates end of Dataword in Comms Buffer
        '    --------------------------------------------------
        '    CounterA on exit End Point
    REnd:    
        For CounterA=0 to 9
            If CommsBuffer(CounterA)=32 then goto REndExit
            If CommsBuffer(CounterA)=0 then goto REndExit
            Next CounterA
        CounterA=10
    REndExit:
        Return
    
        '
        '    Subroutine tells User to Wait
        '    -----------------------------
    WaitMessage:
        DEBUG REP $00\8,13,10,"Wait..."
        Return
    
        '
        '    Subroutine DISABLES LEDs
        '    ------------------------
    LEDsOFF:
        If Xvariable=0 then
            LEDStatus=$1F
            else
            LEDStatus.0(Xvariable-1)=1
            endif
        PortA=LEDStatus
        Return
    
        '
        '    Subroutine ENABLES LEDs
        '    -----------------------
    LEDsON:
        If Xvariable=0 then
            LEDStatus=$0
            else
            LEDStatus.0(Xvariable-1)=0
            endif
        PortA=LEDStatus
        Return
    
        End