I'm using USART to pass info from one PIC to another. On the slave PIC, I want to read an incoming data stream which will tell me what PWM duty cycle to set on the slave's CCP module. The format of the data sent is this:

S0D3255~

The first character "S" is the 'sync' character (or start of new transmission); the 2nd is the Chip ID (since there will be a few slaves connected to one Master); third character is what option on the slave is going to change; the 4th character is the number of digits in the adjustment value ("255") and the last character is the termination.

I have an ISR attached to the Rc pin of the USART module on my PIC, so it fires overtime a character comes into the buffer. Here's the ISR:

Code:
' ***************************************************************
' [RX_INT - interrupt handler]
' ***************************************************************
GetBytes: 
' TODO: Update code to handle AdjVal > 1 character (an array?)

    HSERIN [Serialdata]                    ' Get the serial data (guaranteed here to have at

    IF Serialdata = SyncByte THEN          
        IF SyncRcvd THEN                   ' if it's a Sync byte,
            state = 0                      '   last command was corrupted; reset 'state'
            ERROR = 1                      '   and indicate error
        ENDIF
        SyncRcvd = 1                       '   indicate Sync was rcvd
    ELSE
        IF SyncRcvd THEN
            IF !ForMe THEN                 ' if we haven't rcvd the ID
                IF Serialdata = ThisChipID THEN 'and this byte matches the ID
                    ForMe = 1              '     indicate ID rcvd
                ELSE
                    state = 0               '    Not meant for this chip, reset and wait for next msg
                ENDIF                      
            ELSEIF !CmdRcvd THEN
                CmdVal = SerialData
                CmdRcvd = 1
            ELSEIF !LenAdjRcvd THEN
                LenAdjVal = SerialData                
                LenAdjRcvd = 1
                i = 0
            ELSEIF !AdjRcvd THEN
                AdjVal = SerialData
                myArray[i] = AdjVal
                i = i + 1
                If i = ArrayLength THEN
                    AdjRcvd = 1
                ENDIF
            ELSEIF !MsgRcvd THEN
                If SerialData = TxEndChar THEN
                    MsgRcvd = 1
                ENDIF
            ENDIF
        ENDIF
    ENDIF

@ INT_RETURN
In the Main loop:

Code:
Main:
    IF MsgRcvd THEN GOSUB ProcessCmdAdj    ' Process incomming data
.
.
.
GOT Main
And here's where I output the result (using MCSP's Serial Communicator):
Code:
'*********** Process received command **************************************
ProcessCmdAdj:
'    varResult = myArray[0]*100 + myArray[1]*10 + myArray[2]

    HSEROUT ["Cmd: ", CmdVal, _  ' send Command, Length of Adjustment & Adjustment value and CR/LF
        ", LenAdj: ", LenAdjVal, " [", DEC LenAdjVal, "]", _
           ", Adj: ", myArray[0], myArray[1], myArray[2], 13, 10]
        
        
        '   ", Adj: ", AdjVal, " [", DEC AdjVal,"]", 13, 10] 

    state      = 0               ' indicate CMD & ADJ has been processed

    cmdVal     = 0
    LenAdjVal  = 0
    AdjVal     = 0

    For i = 0 to (ArrayLength - 1) ' clear out array
        myArray[i] = 0
    NEXT i

RETURN
I can't figure out how to take the 3 characters stored in myArray and convert it to a numerical 255 value that I can then use to set PWM duty cycle. As you can see from the commented-out line above, I tried multiplying the first 2 characters by 100 & 10, but that just gives garbled results. I know the ISR is building the array properly because the above HSEROUT shows me the correct characters in each item of myArray[].

I've never had to do this kind of math/byte manipulation before, so I'd appreciate help here. The full code for the project is here:

Code:
' :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
' Based on Darrel Taylor's example
' http://www.picbasic.co.uk/forum/showthread.php?t=9932&p=65066#post65066
' :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

'  MPASM, LabX-1 , PBP3, Using PIC 16F877A @ 4mHz, 9600 Baud,
'  USART and MAX232 to MCS Serial Communicator on PC

' ***************************************************************
' >>>>>>>>>>>>>>>>>    Slave IC ID: 0    <<<<<<<<<<<<<<<<<<<<<<<
' ***************************************************************

ThisChipID CON "0"

DEFINE OSC 4

DEFINE HSER_RCSTA 90h ' enable serial port, 
DEFINE HSER_TXSTA 24h ' enable transmit, 
DEFINE HSER_BAUD 9600 ' set baudrate to 9600                   
DEFINE HSER_CLOERR  1 ' automatic clear overrun error  

TRISD  = %00000000    ' D to outputs for the LEDs
TRISC  = %10000000    ' PORTC.7 is the RX input, PORTC.6 is the TX output
ADCON1 = %00001111    ' Set up ADCON1 register no matter what yr doing!!!                      
        
':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
INCLUDE "DT_INTS-14.bas"     ' Base Interrupt System
INCLUDE "ReEnterPBP.bas"     ' Include if using PBP interrupts

;-- Place a copy of these variables in your Main program -------------------
;--   The compiler will tell you which lines to un-comment                --
;--   Do Not un-comment these lines                                       --
;---------------------------------------------------------------------------
;wsave   VAR BYTE    $20     SYSTEM      ' location for W if in bank0
wsave   VAR BYTE    $70     SYSTEM      ' alternate save location for W 
                                         ' if using $70, comment wsave1-3

' --- IF any of these three lines cause an error ?? ------------------------
'       Comment them out to fix the problem ----
' -- Which variables are needed, depends on the Chip you are using -- 
wsave1  VAR BYTE    $A0     SYSTEM      ' location for W if in bank1
wsave2  VAR BYTE    $120    SYSTEM      ' location for W if in bank2
wsave3  VAR BYTE    $1A0    SYSTEM      ' location for W if in bank3
' --------------------------------------------------------------------------

' ***************************************************************
' ASM Interrupt Definitions
' ***************************************************************

ASM
INT_LIST  macro    ; IntSource,           Label,  Type, ResetFlag?
        INT_Handler   TMR1_INT,      ReloadTMR1,   ASM,  no       ; MUST be first
        INT_Handler   TMR1_INT,      _T1handler,   PBP,  yes
        INT_Handler     RX_INT,        _GetBytes,  PBP,  yes
    endm
    INT_CREATE     ; Creates the interrupt processor
ENDASM

':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
'   Variable definition
':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

ERROR_LED  VAR PORTD.1            ' rename the LED's
LATE_LED   VAR PORTD.2
HEART_LED  VAR PORTD.0

PORTD = 0

LEDonDELAY CON 4

TxEndChar   CON "~"
SyncByte    CON "S"

i           VAR BYTE

SerialData  VAR BYTE
CmdVal      VAR BYTE
LenAdjVal   VAR BYTE
AdjVal      VAR BYTE
ERRORtime   VAR BYTE
LATEtime    VAR BYTE
HEARTtime   VAR BYTE

state         VAR BYTE         
  SyncRcvd    VAR state.0      ' sync byte received
  ForMe       VAR state.1      ' packet is for this device
  CmdRcvd     VAR state.2      ' command has been received
  LenAdjRcvd  VAR state.3      ' decimal length of adjustment value to follow
  AdjRcvd     VAR state.4      ' adjustment factor has been received
  MsgRcvd     VAR state.5      ' compelte message received
  ERROR       VAR state.6      ' sync received out of order
  LATE        VAR state.7      ' command received before last one was processed

state      = 0                 ' Initialize default values

i          = 0

cmdVal     = 0
LenAdjVal  = 0
AdjVal     = 0
serialdata = 0                 

ArrayLength CON 3
myArray VAR BYTE[ArrayLength]
varResult VAR BYTE
                
' Example of received command from master chip:
' ============================================
'    SyncByte, Chip Id, Cmd Id, Length of modifier, <modifier>, TxEndChar
'HSEROUT ["S",     "0",    "A",                "3",      "155",    "~"] 


;--- Change these to match the desired interrupt frequency -------------------
;--- See http://DarrelTaylor.com/DT_INTS-14/TimerTemplate.html for more Info.
@Freq       = 10                  ; Frequency of Interrupts in Hz
@Prescaler  = 2                   ; Timers Prescaler setting
T1CON = $10                       ; $30 = Prescaler 1:8, TMR1 OFF
; $00=1:1, $10=1:2, $20=1:4, $30=1:8 --  Must match @Prescaler value

' Enable interrupts
@ INT_ENABLE  RX_INT        ; enable USART RX_INT interrupts
@ INT_ENABLE  TMR1_INT      ; enable Timer 1 interrupts
GOSUB StartTimer            ; Start Timer 1

Main:
    IF MsgRcvd THEN GOSUB ProcessCmdAdj    ' Process incomming data

    IF ERROR THEN                          ' if there's been an Error
        HIGH ERROR_LED                     '   Turn ON ERROR LED
        ERROR = 0                          '   reset the error flag
        ERRORtime = LEDonDELAY             '   start countdown till LED-OFF
        HSEROUT ["Error",13,10]
;        HSEROUT ["SyncRcvd: ", DEC SyncRcvd,", SyncIndx: ",DEC SyncIndx, _
;                ", ForMe: ", DEC ForMe,", CmdRcvd: ",DEC CmdRcvd, _
;                ", AdjRcvd: ",DEC AdjRcvd,", Cmd: ",CmdVal, ", Adj: ",DEC AdjVal,13,10] 
    ENDIF
    IF LATE THEN                           ' if command took too long
        HIGH LATE_LED                      '   Turn ON LATE LED
        LATE = 0                           '   reset the LATE flag
        LATEtime = LEDonDELAY              '   start countdown till LED-OFF
        HSEROUT ["Late",13,10]
    ENDIF
GOTO Main

'*********** Process received command **************************************
ProcessCmdAdj:
'    varResult = myArray[0]*100 + myArray[1]*10 + myArray[2]

    HSEROUT ["Cmd: ", CmdVal, _  ' send Command, Length of Adjustment & Adjustment value and CR/LF
        ", LenAdj: ", LenAdjVal, " [", DEC LenAdjVal, "]", _
           ", Adj: ", myArray[0], myArray[1], myArray[2], 13, 10]
        
        
        '   ", Adj: ", AdjVal, " [", DEC AdjVal,"]", 13, 10] 

    state      = 0               ' indicate CMD & ADJ has been processed

    cmdVal     = 0
    LenAdjVal  = 0
    AdjVal     = 0

    For i = 0 to (ArrayLength - 1) ' clear out array
        myArray[i] = 0
    NEXT i

RETURN

' ***************************************************************
' [TMR1_INT - interrupt handler]
' ***************************************************************
T1handler:
    IF ERRORtime > 0 THEN                  ' if the Error LED is ON
        ERRORtime = ERRORtime - 1          '   decrement the count
        IF ERRORtime = 0 THEN              '   when it reaches 0
            LOW ERROR_LED                  '   turn the Error LED OFF
        ENDIF
    ENDIF        
    IF LATEtime > 0 THEN                   ' if the LATE LED is ON
        LATEtime = LATEtime - 1            '   decrement the count
        IF LATEtime = 0 THEN               '   when it reaches 0
            LOW LATE_LED                   '   turn the LATE LED OFF
        ENDIF
    ENDIF
    HEARTtime = HEARTtime + 1              ' Toggle heartbeat ~.5sec
    IF HEARTtime = 7 THEN
        HEARTtime = 0
        TOGGLE HEART_LED
    ENDIF       
@ INT_RETURN

' ***************************************************************
' [RX_INT - interrupt handler]
' ***************************************************************
GetBytes: 
' TODO: Update code to handle AdjVal > 1 character (an array?)

    HSERIN [Serialdata]                    ' Get the serial data (guaranteed here to have at

    IF Serialdata = SyncByte THEN          
        IF SyncRcvd THEN                   ' if it's a Sync byte,
            state = 0                      '   last command was corrupted; reset 'state'
            ERROR = 1                      '   and indicate error
        ENDIF
        SyncRcvd = 1                       '   indicate Sync was rcvd
    ELSE
        IF SyncRcvd THEN
            IF !ForMe THEN                 ' if we haven't rcvd the ID
                IF Serialdata = ThisChipID THEN 'and this byte matches the ID
                    ForMe = 1              '     indicate ID rcvd
                ELSE
                    state = 0               '    Not meant for this chip, reset and wait for next msg
                ENDIF                      
            ELSEIF !CmdRcvd THEN
                CmdVal = SerialData
                CmdRcvd = 1
            ELSEIF !LenAdjRcvd THEN
                LenAdjVal = SerialData                
                LenAdjRcvd = 1
                i = 0
            ELSEIF !AdjRcvd THEN
                AdjVal = SerialData
                myArray[i] = AdjVal
                i = i + 1
                If i = ArrayLength THEN
                    AdjRcvd = 1
                ENDIF
            ELSEIF !MsgRcvd THEN
                If SerialData = TxEndChar THEN
                    MsgRcvd = 1
                ENDIF
            ENDIF
        ENDIF
    ENDIF

@ INT_RETURN

;---[TMR1 reload - interrupt handler]-----------------------------------------
ASM                               ; Calculate Timer Reload Constant
ReloadInst  = 8                   ; # of Intructions used to reload timer
  if ((Prescaler == 1)||(Prescaler == 2)||(Prescaler == 4)||(Prescaler == 8))
MaxCount    = 65536 + (ReloadInst / Prescaler)
TimerReload = MaxCount - (OSC*1000000/4/Prescaler/Freq)
    if ((TimerReload < 0) || (TimerReload > (65535-ReloadInst)))
        error Invalid Timer Values - check "OSC", "Freq" and "Prescaler"
    endif
  else
      error Invalid Prescaler
  endif
ENDASM

@Timer1 = TMR1L                   ; map timer registers to a word variable
Timer1       VAR WORD EXT
TimerReload  CON EXT              ; Get the External Constant
TMR1ON       VAR T1CON.0          ; Alias the Timers ON/OFF bit

;---Reload Timer1------
ASM
ReloadTMR1
    MOVE?CT  0, T1CON, TMR1ON     ;  1     stop timer
    MOVLW    LOW(TimerReload)     ;  1     Add TimerReload to the 
    ADDWF    TMR1L,F              ;  1     value in Timer1
    BTFSC    STATUS,C             ;  1/2
    INCF     TMR1H,F              ;  1
    MOVLW    HIGH(TimerReload)    ;  1
    ADDWF    TMR1H,F              ;  1
    MOVE?CT  1, T1CON, TMR1ON     ;  1     start timer
  INT_RETURN
ENDASM

;---Start/Stop controls -----
StartTimer:
    Timer1  = TimerReload         ; Load Timer
    TMR1ON = 1                    ; start timer
RETURN

StopTimer:
    TMR1ON = 0                    ; stop timer
RETURN