Best way to use USART/HSERIN
	
	
		I'm working on a project where there will be one PIC as a master controller to adjust LED brightness & motor control. I want to link this master PIC to the motor/LED chips via USART in a chain (all by wire on a PCB - no other components involved) and send the mode/speed changes down using a hard-coded ID; each chip down the line will check the ID and if it matches it's own then it acts on it, else it just passes it down the line.
My question is this - how best to set up HSERIN in a situation like this? Should I use something like this in a Main loop:
	Code:
	
Main:
    HserIN [WAIT("OK"),ID]
    IF ID="3" THEN 
        gosub updateLEDs
    ELSE
        HserOUT [data]
    ENDIF
    goto Main
 Or would it be better to use Darrel's Instant Interrupts with the Rx interrupt?
This will be my first time using HSERIN/HSEROUT apart from using it for LCD debugging.
	 
	
	
	
		Re: Best way to use USART/HSERIN
	
	
		Hi,
Why do you need to daisychain them like [Master Out] -> [Slave In - Slave Out] -> [Slave In - Slave Out] ?
Why not just wire the output of the master to the inputs of the slaves? That way the delay between the master and all the slaves will be equal and there will be less overhead in each of the slaves.
Also, your code seems to read the ID but then it doesn't read the actual data.
I'd probably send equally sized packets each time, perhaps something like sync, ID, 8 bytes of data, checksum. The slave then waits for the sync, grabs x number of bytes into an array, evaluates the checksum and if OK checks the ID. If ID matches it acts on the data otherwise it does nothing.
Using interrupts or not highly depends on what else your program needs to do. If it just needs to sit there and wait for serial data, act on that data and then go back to waiting then you should be fine without using interrupts. But if your program needs to do other things and receive the serial data in the background then you probably need to use interrupts - and DT-Ints is a great way to do it.
/Henrik.
	 
	
	
	
		Re: Best way to use USART/HSERIN
	
	
		Thanks very much, Henrik. I didn't put the whole code in but what you suggest is what I was thinking.
I didn't think I could hook up the Tx on the master controller to all the Rx pins on the other PICs, but that makes life a lot easier so I'll give it a go.
	 
	
	
	
		Re: Best way to use USART/HSERIN
	
	
		I've been using the PIC16F88 chip which has the 7 sequential pins I need for the code seen in this post. The problem is those 7 pins (PORTB.1-7) include the Rx pin, and I can't seem to find another chip which has 7 sequential pins where the USART Rx pin is somewhere else.
Should I use SERIN instead to communicate between PICs, or is there a PIC which has 7 sequential pin outputs (none of which are the USART Rx pin)?
	 
	
	
	
		Re: Best way to use USART/HSERIN
	
	
		Spending a little more time on the Microchip selector site, I think PIC16F687 might do the trick - 20 pin DIP, 18 I/O pins with Rx on RB5 and RC0-7 available.
	 
	
	
	
		Re: Best way to use USART/HSERIN
	
	
		Coming back to this thread after recovering from some encoder/code porting issues from last week, I'm still trying to figure out the best way to send/receive data from 1 Master chip to 3-4 slaves via USART. I've read over many threads here regarding HSEROUT/HSERIN and the permutations & combinations leave me confused.
As of last night, I've got a PIC12F1840 sending the following on the Tx pin based on a rotary encoder turn (there's an IOC ISR to determine the direction of turn which sets RotEncDir):
	Code:
	
DEFINE OSC 16                ' Set oscillator 16Mhz
DEFINE HSER_TXSTA 20h        ; Set transmit status and control register
DEFINE HSER_BAUD  2400       ; Set baud rate
DEFINE HSER_RCSTA 90h
DEFINE HSER_CLROERR 1        ; Clear overrun error upon
                             ; execution of every HSERIN
                             ; command
.
.
.
Main:
    TOGGLE LED_0
    If ValueDirty = 1 THEN
        ' Send RotEncDir to receiving chip
        '    Chip Id,Itm Id,     <modifier>, "~"
        HSEROUT ["2",   "3", SDEC RotEncDir, TxEndChar]  ' use 'SDEC' if RotEncDir can be -1 for CCW
            
        ValueDirty = 0               ' Clear the flag
        #IFDEF USE_LCD_FOR_DEBUG
            HSEROUT [LCD_INST, LCD_CLR]
            pause 5
            '    Chip Id,Itm Id,     <modifier>,  "~"
            HSEROUT ["2",   "3", SDEC RotEncDir, TxEndChar]  ' use 'SDEC' if RotEncDir can be -1 for CCW
        #ENDIF
    ENDIF
 
    pause 500
 
    GOTO Main
 The output on my LCD shows this for a CW turn:
and this for CCW (RotEncDir actually gets set to 0 but I change it to -1 as on the slave I want to just add this value:
The first number represents the slave chip which is the intended target of the serial data (I'll have 2-3 slaves in this project). The second number represents what to change on that chip with the rotary encoder info. The next part is either '1' for CW or '-1' for CCW (I could go back to using '0' for CCW if that makes the overall serial data easier to interpret on the slaves).
- Should I have a sync character at the start of the serial data so that on the slave I can determine if new serial data is sent before processing the first message (or there's an error)?
 
- Should I convert the HSEROUT line to multiple lines?
 
For the slaves, I've decided I need to use a Rx interrupt as I have other code running in the Main loop.
	Code:
	
DEFINE OSC 16                ' Set oscillator 16Mhz
DEFINE HSER_TXSTA 20h        ; Set transmit status and control register
DEFINE HSER_BAUD  2400       ; Set baud rate
DEFINE HSER_RCSTA 90h
DEFINE HSER_CLROERR 1        ; Clear overrun error upon
                             ; execution of every HSERIN
                             ; command
.
.
.
' ***************************************************************
' ASM Interrupt Definitions
' ***************************************************************
ASM
INT_LIST  macro    ; IntSource,           Label,  Type, ResetFlag?
        INT_Handler     RX_INT,        _UsartRx,   PBP,  yes
    endm
    INT_CREATE     ; Creates the interrupt processor
ENDASM
' Enable interrupt
@ INT_ENABLE   RX_INT      ; USART Rx interrupt
.
.
.
 - Do I need to make the RX_INT a low priority interrupt, or is that only important if there are other time-sensitive interrupts (I am using SPWM_INT.bas for one slave)?
 
- As Henrik suggests above, should I make the serial data entirely consistent in terms of number of bytes to make the parsing here easier? If that's true, then I probably need to revert to using '0' for CCW rotary encoder changes.
 
- The code below is from DT on another thread but I can't see how the whole serial data (e.g. "231~" for slave chip #2 to increment item #3 by 1) will be pieced together.
 
- Does the ISR get 1 byte every time? i.e. the first time it goes into the above ISR, 'SerialData' will be "2" and then the next iteration will have "3"?
 
- Should the ISR have the ResetFlag set or not? I've seen both.
 
	Code:
	
'*********** 'ISR for RX_INT interrupt *************************************
Getbytes:       
    HSERIN [Serialdata]                    ' Get the serial data
    IF Serialdata = SyncByte THEN          ' if it's a Sync byte,
        IF Sync THEN ERROR = 1            '  last command was corrupted
        Sync = 1                          '  indicate Sync was rcvd
        ForMe = 0                          '  ID has not been rcvd
    ELSE
        IF Sync THEN
            IF !ForME THEN                ' if we haven't rcvd the ID
                IF Serialdata = ID THEN    '  and this byte matches the ID
                    ForMe = 1              '    indicate ID rcvd
                ELSE
                    Sync = 0              ' Not my packet
                    ForMe = 0              '  reset receive state   
                ENDIF                      '  and wait for next Sync
            ELSE
                CmdBuf = serialdata        ' store the command
                IF CmdRcvd THEN LATE = 1  '  last command not finished
                CmdRcvd = 1                '  indicate a command was rcvd
                Sync = 0                  '  reset receive state
                ForMe = 0                 
            ENDIF
        ENDIF
    ENDIF
@ INT_RETURN
 All slaves Rx pin will be connected to the master's Tx pin so each slave needs to determine if the serial data is for them or not (which the above code does).
	 
	
	
		6 Attachment(s)
	
	
		Re: Best way to use USART/HSERIN
	
	
		I've modified Darrel's sample code from this thread (switching to use TMR1 - I couldn't get TMR0 to work) and hooked up my LabX1 board with a PIC16F877A chip jumpered to 4Mhz. It would appear to work except for when the SYNC character appears twice and depending on where it yields a different result.
	Code:
	
':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
            'Based on Hserin with Darrel Taylor's Instant Interrupts
':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
'    Program to echo incoming serial data.
'  RX SYNC byte, if good: ChipID byte, if good: COMMAND, if good: ADJUSTMENT
'   MPASM, LabX-1 , PBP2.47, Using PIC 16F877A @ 4mHz, 9600 Baud
'   Using Hardware USART and MAX232 to MCS Serial Communicator on PC
' ***************************************************************
' >>>>>>>>>>>>>>>>>    Slave IC ID: 1    <<<<<<<<<<<<<<<<<<<<<<<
' ***************************************************************
ChipID          CON "1"
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
' --------------------------------------------------------------------------
':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    '   Variable definition
':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
        
led0       var     PORTD.0
led1       var     PORTD.1
led2       var     PORTD.2
led7       var     PORTD.7
ERROR_LED  VAR led7            ' rename the LED's
LATE_LED   VAR led2
HEART_LED  VAR led0
LEDonDELAY CON 4
TxEndChar   CON "~"
SyncByte    CON "S"
CmdBuf      VAR BYTE
AdjBuf      VAR BYTE
SerialData  VAR BYTE
ERRORtime   VAR BYTE
LATEtime    VAR BYTE
HEARTtime   VAR BYTE
state       VAR BYTE         
  Sync      VAR state.0      ' sync byte received
  ForMe     VAR state.1      ' packet is for this device
  CmdRcvd   VAR state.2      ' command has been received
  AdjRcvd   VAR state.3      ' adjustment factor has been received
  ERROR     VAR state.4      ' sync received out of order
  LATE      VAR state.5      ' command received before last one was processed
state = 0                    ' Initialize default value
' ***************************************************************
' 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,  no
    endm
    INT_CREATE     ; Creates the interrupt processor
ENDASM
;--- 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 ('MotorRPM' will be saved on every
                            ; interrupt if dirty
Main:
;        High HEART_LED    ' Turn on LED connected to PORTD.0
;        Pause 500       ' Delay for .5 seconds
;        Low HEART_LED         ' Turn off LED connected to PORTD.0
;        Pause 500       ' Delay for .5 seconds
    IF (CmdRcvd AND AdjRcvd) THEN GOSUB ProcessCmdAdj    ' Process any 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]
    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:
    hserout ["Cmd: ",CmdBuf, _ ' send ChipID, Command, Adjustment and CR/LF
             " [",DEC CmdBuf,"]",", Adj:",AdjBuf,_
             " [",DEC AdjBuf,"]",13,10] 
;    hserout ["Cmd: ",CmdBuf, " [", _
;            DEC CmdBuf,"]",13,10]        
    CmdRcvd = 0                            ' indicate CMD & ADJ has been processed
    AdjRcvd = 0
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: 
' Henrik's suggestion (http://www.picbasic.co.uk/forum/showthread.php?t=17685)
' I'd probably send equally sized packets each time, perhaps something like sync,
' ID, 8 bytes of data, checksum. The slave then waits for the sync, grabs x
' number of bytes into an array, evaluates the checksum and if OK checks the ID.
' If ID matches it acts on the data otherwise it does nothing.
' Darrel Taylor's code (http://www.picbasic.co.uk/forum/showthread.php?t=9932&p=65066#post65066)
    HSERIN [Serialdata]                    ' Get the serial data
    IF Serialdata = SyncByte THEN          ' if it's a Sync byte,
        IF Sync THEN ERROR = 1             '   last command was corrupted
        Sync = 1                           '   indicate Sync was rcvd
        ForMe = 0                          '   ID has not been rcvd
    ELSE
        IF Sync THEN
            IF !ForME THEN                 ' if we haven't rcvd the ID
                IF Serialdata = ChipID THEN'   and this byte matches the ID
                    ForMe = 1              '   indicate ID rcvd
                ELSE
                    Sync = 0               ' Not my packet
                    ForMe = 0              '   reset receive state    
                ENDIF                      '   and wait for next Sync
            ELSEIF !CmdRcvd THEN
                CmdBuf = serialdata        ' store the command
                IF CmdRcvd THEN LATE = 1   '   last command not finished
                CmdRcvd = 1                '   indicate a command was rcvd
                ;Sync = 0                   '   reset receive state
                ;ForMe = 0  
            ELSE
                AdjBuf = SerialData        ' store the command
                IF AdjRcvd THEN LATE = 1   '   last adjustment not finished
                AdjRcvd = 1                '   indicate an adjustment was rcvd
                Sync = 0                   '   reset receive state
                ForMe = 0                
            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
 I need to capture a 3rd byte (the adjustment to the command feature on the indicated chip) but something's not right - I get strange text in the receive window of the MCS serial window.
Serial window config:
Attachment 6937
Proper sequence yields correct result:
Attachment 6938
Correct error msg:
Attachment 6942
Weird error msg:
Attachment 6939
Weird error msg 2:
Attachment 6940
On a side note, any idea why some of the LEDs in the bargraph light up when they're not supposed to? Seems like every time I plug in the Lab X1, different ones light up.
Attachment 6941
	 
	
	
	
		Re: Best way to use USART/HSERIN
	
	
		The 2 LEDs which are on when they shouldn't be are still perplexing me, but this code works now if anyone's interested:
	Code:
	
' :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
' Based on Hserin with Darrel Taylor's Instant Interrupts
' :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
'  MPASM, LabX-1 , PBP3, Using PIC 16F877A @ 4mHz, 9600 Baud,
'  USART and MAX232 to MCS Serial Communicator on PC
' ***************************************************************
' >>>>>>>>>>>>>>>>>    Slave IC ID: 1    <<<<<<<<<<<<<<<<<<<<<<<
' ***************************************************************
ThisChipID CON "1"
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
':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
        
led0       var     PORTD.0
led1       var     PORTD.1
led2       var     PORTD.2
led7       var     PORTD.7
ERROR_LED  VAR led7            ' rename the LED's
LATE_LED   VAR led2
HEART_LED  VAR led0
LEDonDELAY CON 4
TxEndChar   CON "~"
SyncByte    CON "S"
SerialData  VAR BYTE
CmdVal      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
  AdjRcvd     VAR state.3      ' adjustment factor has been received
  MsgRcvd     VAR state.4      ' compelte message received
  ERROR       VAR state.5      ' sync received out of order
  LATE        VAR state.6      ' command received before last one was processed
  SyncIndx    VAR state.7      ' index # of incoming byte
state      = 0                 ' Initialize default values
cmdVal     = 0
AdjVal     = 0
serialdata = 0                 ' message sample: "S3B1~"
;--- 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 ('MotorRPM' will be saved on every
                            ; interrupt if dirty
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:
    HSEROUT ["Cmd: ", CmdVal, _ ' send ThisChipID, Command, Adjustment and CR/LF
             ", Adj: ",AdjVal,_
             " [",DEC AdjVal,"]",13,10]       
    
    state      = 0               ' indicate CMD & ADJ has been processed
    cmdVal     = 0
    AdjVal     = 0
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: 
' Darrel Taylor's code (http://www.picbasic.co.uk/forum/showthread.php?t=9932&p=65066#post65066)
    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               '   and wait for next Sync
                ENDIF                      
            ELSEIF !CmdRcvd THEN
                CmdVal = SerialData
                CmdRcvd = 1
            ELSEIF !AdjRcvd THEN
                AdjVal = SerialData
                AdjRcvd = 1
            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
 Any suggestions for improvement gratefully appreciated.
	 
	
	
	
		Re: Best way to use USART/HSERIN
	
	
		Did you set the pull-up/down jumper for the Lab X1 LEDs?
I remember I had to set "something".
Robert
	 
	
	
	
		Re: Best way to use USART/HSERIN
	
	
		No, I didn't Robert. Do I need to do that for all of them?
	 
	
	
	
		Re: Best way to use USART/HSERIN
	
	
		Check the Lab X1 schematic, I'm pretty sure there was a jumper for this.  It handled all the LEDs at once.
	 
	
	
	
		Re: Best way to use USART/HSERIN
	
	
		
	Quote:
	
		
		
			
				Originally Posted by 
Demon
				
			 
			Check the Lab X1 schematic, I'm pretty sure there was a jumper for this.  It handled all the LEDs at once.
			
		
	 
 Is this what you're referring to Robert?
	Quote:
	
		
		
			LED Bargraph
8 programmable LEDs connected to PORTD and 2 power LEDs are provided by
the LED bargraph.  Resistor pack RP4 provides the current limit series
resistors for the LEDs.  The LED bargraph may be inserted in the socket so
that the LEDs are lit when the PICmicro MCU pin is in either its high or low
state.
To make the LEDs light up when a PICmicro MCU pin is high, insert the LED
bargraph into the socket with pin 1 toward the edge of the board (this will
also line it up with pin 1 on the socket and is the default placement).
Jumper JP2 must have pins 2 and 3 connected (jumper on the top 2 JP2 pins).
When the LAB-X1 is powered up, the leftmost LED will light up to show that
power is on.  To make an LED light up, set the appropriate PORTD pin to
output high.
To make the LEDs light up when a PICmicro MCU pin is low, insert the LED
bargraph into the socket with pin 1 toward the center of the board.  Jumper
JP2 must have pins 1 and 2 connected (jumper on the bottom 2 JP2 pins).  When
the LAB-X1 is powered up, the second to the leftmost LED will light up to
show that power is on.  To make an LED light up, set the appropriate PORTD
pin to output low.
The LED bargraph shares PORTD with the LCD module data lines.  If the
program is not using the LCD module, it can effectively be ignored.  If the
LCD module is also being used, it may leave the LEDs in a different state
than it found them in.  If the LCD is operating on a 4-bit data bus, only the
top 4 LEDs, 4 - 8, will be affected.  If the LCD is using an 8-bit data bus,
all 8 LEDs will be affected.  The proper LED state will need to be reset
after each LCD access.
See BLINKX.BAS for a programming example.
			
		
	
 I'll check the jumpers tonight, but it seems like it's an all-or-nothing thing - on my board, the leftmost LED lights up when powered on and the ERROR LED from my code does blink, but a few of the other ones are always on.
	 
	
	
	
		Re: Best way to use USART/HSERIN
	
	
		Yup, JP2, that's the one.
	 
	
	
	
		Re: Best way to use USART/HSERIN
	
	
		Looking at the board with the power jack on the left and the 16F8777A on the bottom, the JP2 jumper has the top two pins tied together. The LED bargraph has the writing towards me. That would seem to be the pick-pin-HIGH-LED-On scenario described above, so I don't get why the LEDs which aren't referenced are on. <Sigh>
	 
	
	
	
		Re: Best way to use USART/HSERIN
	
	
		Dumb question, did you assign initial values to the pins, ADC, CONFIGs, etc?
	 
	
	
	
		Re: Best way to use USART/HSERIN
	
	
		Not a dumb question, Robert - I did not. Think I should add 'PORTD =0'?
	 
	
	
	
		Re: Best way to use USART/HSERIN
	
	
		I'd use the variables.
Why the renaming?
led1       var     PORTD.1
led2       var     PORTD.2
led7       var     PORTD.7
ERROR_LED  VAR led7            ' rename the LED's
LATE_LED   VAR led2t
HEART_LED  VAR led0
	 
	
	
	
		Re: Best way to use USART/HSERIN
	
	
		Problem solved:
	Code:
	
':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
'   Variable definition
':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
ERROR_LED  VAR PORTD.1            ' rename the LED's
LATE_LED   VAR PORTD.2
HEART_LED  VAR PORTD.0
PORTD = 0