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.
Bookmarks