SMst.asm
; Final Project - Terman Pond Flotilla
; ME218B
; By Allen Cheung
; -----------------------------------------------------------------
;
;
; Pins used:
; RB<7, 5> as transmit/receive lines for EUSART to Xbee radio
; RC<7> RB<4, 6> for SPI to slaves
; RC<0:2> as SS lines to slaves
; RA<0> for ibutton
; RA<1> for debug LED
; RC<5> as PWM for pump
;
list P=PIC16F690
#include "p16F690.inc"
__config (_CP_OFF & _WDT_OFF & _PWRTE_ON & _INTOSCIO)
;
; Variable Definitions
; ---------------------------------------------------------------
#include vars.h
; Beginning of Program
; --------------------------------------------------------------------
org 0
goto Main
org 5
goto Interrupt
;
; Tables
; --------------------------------------------------------------------
; Lookup table for bit pattern to write to Port C output
END_TBL:
; make sure address is less than 0xff
#include xbee_comm.h
#include shipinits.h
#include ibutton.h
#include synch.h
#include wait.h
;
; Initialize routine.
; --------------------------------------------------------------------
Initialize:
; Setup Clock
CALL Clock_Init
; Setup EUSART
CALL EUSART_Init
; Setup PWM
CALL PWM_Init
; Setup SPI
CALL SPI_Init
; Setup LEDs
CALL LED_Init
; Enable Interrupts
banksel INTCON
BSF INTCON, GIE
BSF INTCON, PEIE
RETURN
InitializeGameState:
banksel PORTA
CLRF COM_frameid
MOVLW 0x01
MOVWF COM_options
CLRF COM_rxFlag
CLRF COM_rxIndex
CLRF StateMachine
BSF StateMachine, Waiting
; Setup ping data to respond
MOVLW 0x01
MOVWF PingData1
CLRF PingData2
RETURN
; ****************************************************************************
; ****************************************************************************
; Main Loop
; --------------------------------------------------------------------
; Continuously loops and handles the program
; Looks for a button press, looks for a received message on EUSART
; If slave select raised transmits message or ack
; ****************************************************************************
; ****************************************************************************
Main:
CALL Initialize
CALL InitializeGameState
CALL ToggleLED
CALL Waiting_for_iButton
; Setup ping data
MOVLW 0x02
MOVWF PingData1
CALL ToggleLED
CALL Waiting_for_Sync
CALL ToggleLED
CALL SendFlag
;; SIMULATION
; MOVLW 0xBC
; MOVWF HelmAddrH
; MOVLW 0x0A
; MOVWF HelmAddrL
; Main Loop, we're going to enter a state machine, depending on the state of
; certain variables, it will dictate what we do
Play_Game:
banksel PORTA
; Are we gonna hard reset?
BTFSC StateMachine, Waiting
GOTO Main
; Have we received an API packet?
CALL APIRx
GOTO Play_Game
CheckTimer0Flag:
banksel PORTA
BTFSS Timer0Flag, 0
RETURN
; Flag is set, then clear it
BCF Timer0Flag, 0
DECFSZ TimeOutTimer
RETURN
GOTO ShutOffActuation
ToggleLED:
banksel PORTC
BTFSS PORTC, 4
GOTO $+3
BCF PORTC, 4
RETURN
BSF PORTC, 4
RETURN
APIRx:
banksel PORTA
; Check whether an API packet is received
BTFSS COM_rxFlag, COM_rxDone
RETURN
BCF COM_rxFlag, COM_rxDone
; Toggle LED
CALL ToggleLED
; A packet has been received, what is it?
MOVLW COM_nav
SUBWF COM_rxData1, W
BTFSC STATUS, Z
; It's navigation
GOTO API_Navigation
MOVLW COM_adm
SUBWF COM_rxData1, W
BTFSC STATUS, Z
; It's admiral
GOTO API_Admiral
; It's nothing we're interested in, return
RETURN
; We've received a navigation command from the helm. Interpret the data
; to water speed, speed, and direction, then apply those parameters
API_Navigation:
; First, is it from our helm?
CALL CheckHelmAddr
ADDLW 0x00
BTFSS STATUS, Z
RETURN
; Ok, it is from our helm
; Reset TimeOutTimer
MOVLW TimeOutTimerMax
MOVWF TimeOutTimer
; Direction
MOVLW 0xF0
ANDWF COM_rxData2, W
MOVWF ShipDirection
; Speed
RLF COM_rxData2, F
RLF COM_rxData2, F
RLF COM_rxData2, F
RLF COM_rxData2, F
MOVLW 0xF0
ANDWF COM_rxData2, W
MOVWF ShipSpeed
; Divide speed by two
; RRF ShipSpeed, F
; MOVLW 0x7F
; ANDWF ShipSpeed, F
; WaterSpeed
RLF COM_rxData3, F
RLF COM_rxData3, F
RLF COM_rxData3, F
RLF COM_rxData3, F
MOVLW 0xF0
ANDWF COM_rxData3, W
MOVWF ShipWaterSpd
; All the parameters are copied over, send them to slaves
CALL SetParameters
CALL ToggleLED
RETURN
SetParameters:
banksel PORTA
; Send Rudder direction information
CALL SendDirectionInfo
; Move motor speed to registers, differential
MOVF ShipSpeed, W
MOVWF LeftMotor
MOVWF RightMotor
MOVLW 0x60
SUBWF ShipSpeed, W
BTFSC STATUS, Z
GOTO DoneTurn
MOVLW 0x70
SUBWF ShipSpeed, W
BTFSC STATUS, Z
GOTO DoneTurn
MOVLW 0x80
SUBWF ShipSpeed, W
BTFSC STATUS, Z
GOTO DoneTurn
MOVLW 0x90
SUBWF ShipSpeed, W
BTFSC STATUS, Z
GOTO DoneTurn
; Turning right or left?
BTFSS ShipDirection, 7
GOTO LeftTurn
RightTurn: MOVLW 0x08
SUBWF ShipDirection, F
RRF ShipDirection, F ; Divide by two
BCF ShipDirection, 7
MOVF ShipDirection, W
ADDWF LeftMotor, F
MOVLW 0xF0
BTFSC STATUS, C
MOVWF LeftMotor
MOVF ShipDirection, W
SUBWF RightMotor, F
BTFSS STATUS, C
CLRF RightMotor
GOTO DoneTurn
LeftTurn: COMF ShipDirection, F
MOVLW 0x08
SUBWF ShipDirection, F
RRF ShipDirection, F ; Divide by two
BCF ShipDirection, 7
MOVF ShipDirection, W
ADDWF RightMotor, F
MOVLW 0xF0
BTFSC STATUS, C
MOVWF RightMotor
MOVF ShipDirection, W
SUBWF LeftMotor, F
BTFSS STATUS, C
CLRF LeftMotor
; Send Motor speed information
DoneTurn:
MOVLW 0xF0
ANDWF LeftMotor, F
ANDWF RightMotor, F
CALL SendMotorInfo
; Activate the pump ourselves
banksel CCPR1L
MOVF ShipWaterSpd, W
MOVWF CCPR1L
banksel PORTA
RETURN
SendDirectionInfo:
banksel PORTA
MOVF ShipDirection, W
MOVWF SPI_TXDATA
BSF SPI_TXDATA, 0 ; mark as direction
BSF SPI_TXDATA, 1 ; mark as slave left
BCF SPI_SlaveLft ; pull slave select low
CALL SPI_Transmit
BSF SPI_SlaveLft ; pull slave select high
RETURN
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SendFlag:
banksel PORTA
MOVF Team, W
MOVWF SPI_TXDATA
BSF SPI_TXDATA, 0 ; mark as direction
BCF SPI_TXDATA, 1 ; mark as slave right
BCF SPI_SlaveRt ; pull slave select low
CALL SPI_Transmit
BSF SPI_SlaveRt ; pull slave select high
RETURN
SendWhiteFlag:
banksel PORTA
MOVLW 0x80
MOVWF SPI_TXDATA
BSF SPI_TXDATA, 0 ; mark as direction
BCF SPI_TXDATA, 1 ; mark as slave right
BCF SPI_SlaveRt ; pull slave select low
CALL SPI_Transmit
BSF SPI_SlaveRt ; pull slave select high
RETURN
SendMotorInfo:
banksel PORTA
; Left motor
MOVF LeftMotor, W
MOVWF SPI_TXDATA
BCF SPI_TXDATA, 0 ; mark as speed
BSF SPI_TXDATA, 1 ; mark as slave left
BCF SPI_SlaveLft ; pull slave select low
CALL SPI_Transmit
BSF SPI_SlaveLft ; pull slave select high
; Right motor
MOVF RightMotor, W
MOVWF SPI_TXDATA
BCF SPI_TXDATA, 0 ; mark as speed
BCF SPI_TXDATA, 1 ; mark as slave right
BCF SPI_SlaveRt ; pull slave select low
CALL SPI_Transmit
BSF SPI_SlaveRt ; pull slave select high
RETURN
API_Admiral:
; Command is from the admiral, now we need to check the admiral address
CALL CheckAdmAddr
ADDLW 0x00
BTFSS STATUS, Z
RETURN
; Address matches admiral, now which command is sent?
MOVF COM_rxData2, W
BTFSS STATUS, Z
RETURN
MOVLW COM_ping
SUBWF COM_rxData3, W
BTFSC STATUS, Z
GOTO AdmPing
MOVLW COM_standdown
SUBWF COM_rxData3, W
BTFSC STATUS, Z
GOTO AdmStanddown
MOVLW COM_hardreset
SUBWF COM_rxData3, W
BTFSC STATUS, Z
GOTO AdmHardreset
MOVLW COM_softreset
SUBWF COM_rxData3, W
BTFSC STATUS, Z
GOTO AdmSoftreset
; Not a valid command
RETURN
; Respond to admiral's ping by sending back the ping data correctly
AdmPing:
CALL SetAddressToAdmiral
MOVLW COM_pingresp
MOVWF COM_data1
MOVF PingData1, W
MOVWF COM_data2
MOVF PingData2, W
MOVWF COM_data3
CALL API_TxPacket
RETURN
; Respond to standdown by shutting off everything, sending ack to admiral,
; passing it on to helm, and then block until helm acknowledges
AdmStanddown:
; Shut off everythng
CALL ShutOffActuation
; Send ack to admiral
CALL SendAckToAdmiral
; Pass it on to helm
CALL SetAddressToHelm
MOVLW COM_craft
MOVWF COM_data1
CLRF COM_data2
MOVLW COM_sdreceived
MOVWF COM_data3
CALL API_TxPacket
; Now block until helm acknowledges
ASD1: BTFSS COM_rxFlag, COM_rxDone
GOTO $-1
BCF COM_rxFlag, COM_rxDone
; Is it a helm ack???
; Check helm addr
CALL CheckHelmAddr
ADDLW 0x00
BTFSS STATUS, Z
GOTO ASD1
; It's from the helm, is it an ack?
MOVLW COM_ack
SUBWF COM_rxData1, W
BTFSS STATUS, Z
GOTO ASD1
MOVF COM_rxData2, W
BTFSS STATUS, Z
GOTO ASD1
MOVLW COM_sdreceived
SUBWF COM_rxData3, W
BTFSS STATUS, Z
GOTO ASD1
; It is a helm ack, sweet, now just return
RETURN
SendAckToAdmiral:
CALL SetAddressToAdmiral
MOVLW COM_ack
MOVWF COM_data1
MOVF COM_rxData2, W
MOVWF COM_data2
MOVF COM_rxData3, W
MOVWF COM_data3
CALL API_TxPacket
RETURN
; Respond to soft reset by shutting off everything and then acknowledging
; to admiral
AdmSoftreset:
CALL ShutOffActuation
; Send ack to the admiral
CALL SendAckToAdmiral
RETURN
ShutOffActuation:
MOVLW 0x80
MOVWF ShipDirection
MOVWF RightMotor
MOVWF LeftMotor
CALL SendDirectionInfo
CALL SendMotorInfo
RETURN
; Respond to hard reset by shutting off everything and then return to waiting
; for ibutton state
AdmHardreset:
CALL ShutOffActuation
CLRF StateMachine
BSF StateMachine, Waiting
RETURN
; SPI_Transmit
; --------------------------------------------------------------------
; Transmits to SPI, no slave select
SPI_Transmit:
; Ensure Bank 1
BSF STATUS,RP0
BCF STATUS,RP1
BTFSS SSPSTAT, BF ; Has data been received(transmit complete)?
GOTO $-1
; Bank 0
BCF STATUS,RP0
MOVF SSPBUF, W ; WREG reg = contents of SSPBUF
MOVWF SPI_RXDATA ; Save in user RAM, if data is meaningful
MOVF SPI_TXDATA, W ; W reg = contents of TXDATA
MOVWF SSPBUF ; New data to xmit
RETURN
;
; Interrupt Service Routine
; ***********************************************************************
; ***** The PIC's one and only ISR... =( ******************************
; ***********************************************************************
Interrupt:
; PUSH
MOVWF W_TEMP ; Copy W to TEMP register
SWAPF STATUS, W ; Swap status to be saved into W
banksel PORTA
MOVWF STATUS_TEMP ; Save status to STATUS_TEMP register
; ISR
banksel PIR1
BTFSC PIR1, RCIF
CALL EUSART_Rx_Int
BTFSC INTCON, T0IF
CALL Timer0_Int
; POP
banksel PORTA
SWAPF STATUS_TEMP, W ; Swap nibbles in STATUS_TEMP register
; and place result into W
MOVWF STATUS ; Move W into STATUS register
; (sets bank to original state)
SWAPF W_TEMP, F ; Swap nibbles in W_TEMP and place result in W_TEMP
SWAPF W_TEMP, W ; Swap nibbles in W_TEMP and place result into W
RETFIE
EUSART_Rx_Int:
; Clear flag first
BCF PIR1, RCIF
BTFSC COM_rxFlag, 3
GOTO AllFlagsClear
BTFSC COM_rxFlag, 2
GOTO CheckFor0x81
BTFSC COM_rxFlag, 1
GOTO CheckFor0x08
BTFSC COM_rxFlag, 0
GOTO CheckFor0x00
CheckFor0x7E: MOVLW 0x7E
SUBWF RCREG, W
BTFSS STATUS, Z
GOTO SomethingWrong
BSF COM_rxFlag, 0
RETURN
CheckFor0x00: MOVF RCREG, F
BTFSS STATUS, Z
GOTO SomethingWrong
BSF COM_rxFlag, 1
RETURN
CheckFor0x08: MOVLW 0x08
SUBWF RCREG, W
BTFSS STATUS, Z
GOTO SomethingWrong
BSF COM_rxFlag, 2
RETURN
CheckFor0x81: MOVLW 0x81
SUBWF RCREG, W
BTFSS STATUS, Z
GOTO SomethingWrong
BSF COM_rxFlag, 3
RETURN
AllFlagsClear:
; Read data into appropriate index of receiving buffer
MOVLW COM_rxBuffAddr
ADDWF COM_rxIndex, W
MOVWF FSR
; Read data
MOVF RCREG, W
MOVWF INDF
; Increment the index
INCF COM_rxIndex, F
MOVF COM_rxIndex, W
SUBLW COM_rxLn
; result is positive or zero, now check if it's zero
BTFSS STATUS, Z
; index is not equal to array length, just return
RETURN
; index is equal to array length, API frame is done
CLRF COM_rxFlag
CLRF COM_rxIndex
BSF COM_rxFlag, COM_rxDone
RETURN
SomethingWrong:
CLRF COM_rxIndex
CLRF COM_rxFlag
RETURN
Timer0_Int:
BCF INTCON, T0IF
DECFSZ Timer0Count, F
RETURN
; If the counter finished, reset it and set a flag
MOVLW Timer0Max
MOVWF Timer0Count
BSF Timer0Flag, 0
RETURN
END
ibutton.h
; ******************************************************************************
; ******************************************************************************
; Functions for iButton
; ******************************************************************************
; ******************************************************************************
iWAIT:
BTFSS PIR1, TMR1IF
GOTO iWAIT
RETURN
TIMER1_Init:
banksel OSCCON
BSF OSCCON, IRCF0
BSF OSCCON, IRCF1
BSF OSCCON, IRCF2
banksel T1CON
BCF T1CON, TMR1CS ; use internal clock (Fosc/4)
BCF T1CON, T1CKPS0 ; set prescale value as 1:1
BCF T1CON, T1CKPS1
BSF T1CON, TMR1ON ; Enable Timer 1
; BCF T1CON, TMR1GE
RETURN
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
iButton_Init:
banksel ANSEL
BCF ANSEL, ANS0
RETURN
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
READ_iButton:
; Have we received something? All we care about is admiral ping
BTFSC COM_rxFlag, COM_rxDone
CALL CheckIfAdmiralPingIbutton
; banksel TRISA ; set the pin as an output
BCF STATUS, RP1
BSF STATUS, RP0
BCF TRISA, 0
; banksel PORTA ; set the line low
BCF STATUS, RP1
BCF STATUS, RP0
BCF iButtonPin
; banksel TMR1L ; wait for 500 usec
BCF STATUS, RP1
BCF STATUS, RP0
MOVLW 0xd5 ;232-19
XORLW 0xFF
MOVWF TMR1L
MOVLW 0xFC ; 768
MOVWF TMR1H
BCF PIR1, TMR1IF
CALL iWAIT
; banksel TRISA ; set the pin as an input
BCF STATUS, RP1
BSF STATUS, RP0
BSF TRISA, 0
; banksel TMR1L ; wait for 50 usec
BCF STATUS, RP1
BCF STATUS, RP0
MOVLW 0x4e ; 100-22
XORLW 0xFF
MOVWF TMR1L
MOVLW 0xFF
MOVWF TMR1H
BCF PIR1, TMR1IF
CALL iWAIT
; banksel PORTA ; read the pin
BCF STATUS, RP1
BCF STATUS, RP0
BTFSC iButtonPin
GOTO READ_iButton ; if no iButton found, repeat
RETURN ; if iButton is found, proceed to reset
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
CheckIfAdmiralPingIbutton:
MOVLW COM_adm
SUBWF COM_rxData1, W
BTFSS STATUS, Z
; It's not admiral command
RETURN
; It is admiral
CALL CheckAdmAddr
ADDLW 0x00
BTFSS STATUS, Z
RETURN
; Address matches admiral, now is it ping?
MOVF COM_rxData2, W
BTFSS STATUS, Z
RETURN
MOVLW COM_ping
SUBWF COM_rxData3, W
BTFSS STATUS, Z
CALL AdmPing
RETURN
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
RESET_iButton:
; banksel TRISA ; set the pin as an output
BCF STATUS, RP1
BSF STATUS, RP0
BCF TRISA, 0
; banksel PORTA ; set the line low
BCF STATUS, RP1
BCF STATUS, RP0
BCF iButtonPin
; banksel TMR1L ; wait for 500 usec
MOVLW 0xd5 ;232-19
XORLW 0xFF
MOVWF TMR1L
MOVLW 0xFC ; 768
MOVWF TMR1H
BCF PIR1, TMR1IF
CALL iWAIT
NOP
NOP
NOP
NOP
NOP
NOP
; banksel PORTA ; set the line high
BCF STATUS, RP1
BCF STATUS, RP0
BSF iButtonPin
; banksel TMR1L ; wait for 500 usec
MOVLW 0xd5 ;232-19
XORLW 0xFF
MOVWF TMR1L
MOVLW 0xFC ; 768
MOVWF TMR1H
BCF PIR1, TMR1IF
CALL iWAIT
NOP
;goto RESET_iButton
RETURN
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SEND_READ_COMMAND:
; banksel TMR1L
BCF STATUS, RP1
BCF STATUS, RP0
MOVLW 0x33
; MOVLW 0xff
MOVWF readROMcommand
MOVLW 8
MOVWF CNT
SEND_LOOP: ; send read ROM command
RRF readROMcommand, f
BTFSS STATUS, C
GOTO WRITE_0
GOTO WRITE_1
CHECK_END_OF_SEND_LOOP:
DECFSZ CNT, f
GOTO SEND_LOOP
;goto SEND_READ_COMMAND
RETURN
WRITE_1:
; banksel TRISA ; set the pin as an output
BCF STATUS, RP1
BSF STATUS, RP0
BCF TRISA, 0
; banksel PORTA ; set the line low
BCF STATUS, RP1
BCF STATUS, RP0
BCF iButtonPin
; banksel TMR1L ; wait for 5 usec
; MOVLW 5
; XORLW 0xFF
; MOVWF TMR1L
; MOVLW 0xFF
; MOVWF TMR1H
; BCF PIR1, TMR1IF
; CALL iWAIT
NOP
NOP
NOP
banksel TRISA ; set the pin as an input
BSF TRISA, 0
; banksel TMR1L ; wait for 70 usec
BCF STATUS, RP1
BCF STATUS, RP0
MOVLW 0x70 ;140-28
XORLW 0xFF
MOVWF TMR1L
MOVLW 0xFF
MOVWF TMR1H
BCF PIR1, TMR1IF
CALL iWAIT
NOP
NOP
NOP
GOTO CHECK_END_OF_SEND_LOOP
WRITE_0:
; banksel TRISA ; set the pin as an output
BCF STATUS, RP1
BSF STATUS, RP0
BCF TRISA, 0
; banksel PORTA ; set the line low
BCF STATUS, RP1
BCF STATUS, RP0
BCF iButtonPin
; banksel TMR1L ; wait for 60 usec
MOVLW 0x68 ;120-16
XORLW 0xFF
MOVWF TMR1L
MOVLW 0xFF
MOVWF TMR1H
BCF PIR1, TMR1IF
CALL iWAIT
; banksel TRISA ; set the pin as an input
BCF STATUS, RP1
BSF STATUS, RP0
BSF TRISA, 0
; banksel TMR1L ; wait for 15 usec
BCF STATUS, RP1
BCF STATUS, RP0
MOVLW 0x04 ;30-26
XORLW 0xFF
MOVWF TMR1L
MOVLW 0xFF
MOVWF TMR1H
BCF PIR1, TMR1IF
CALL iWAIT
NOP
NOP
GOTO CHECK_END_OF_SEND_LOOP
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
READ_iButton_data:
; banksel TMR1L
BCF STATUS, RP1
BCF STATUS, RP0
MOVLW 0x18 ;24
MOVWF CNT
READ_LOOP:
; banksel TRISA ; set the pin as an output
BCF STATUS, RP1
BSF STATUS, RP0
BCF TRISA, 0
; banksel PORTA ; set the line low
BCF STATUS, RP1
BCF STATUS, RP0
BCF iButtonPin
; banksel TMR1L ; wait for 5 usec
NOP
NOP
NOP
NOP
; banksel PORTA ; set the line high
; BCF STATUS, RP1
; BCF STATUS, RP0
; BSF iButtonPin
; banksel TRISA ; set the pin as an input
BCF STATUS, RP1
BSF STATUS, RP0
BSF TRISA, 0
; banksel TMR1L ; wait for 10 usec
NOP
NOP
NOP
NOP
NOP
NOP
NOP
;NOP
;NOP
;NOP
; banksel TMR1L
BCF STATUS, RP1
BCF STATUS, RP0
RRF iButtonReadingM, f ; shift the reading to get it ready for the next bit
RRF iButtonReadingH, f
BTFSC STATUS, C
GOTO SETHI
BCF iButtonReadingM, 7
GOTO NEXT
SETHI BSF iButtonReadingM, 7
; RRF iButtonReadingL, f ; shift the reading to get it ready for the next bit
; RRF iButtonReadingM, f
; BTFSC STATUS, C
; BSF iButtonReadingL, 7
; RRF iButtonReadingH, f
; BTFSC STATUS, C
; BSF iButtonReadingM, 7
; banksel PORTA ; set the line low
; BCF STATUS, RP1
; BCF STATUS, RP0
; BCF iButtonPin
; banksel PORTA ; read the pin
NEXT BCF STATUS, RP1
BCF STATUS, RP0
BTFSC iButtonPin
GOTO READ_1 ; if high, reading is 1
BCF iButtonReadingH, 7 ; if low, reading is 0
CHECK_END_OF_READ_LOOP:
; banksel TMR1L ; wait for 60 usec
BCF STATUS, RP1
BCF STATUS, RP0
MOVLW 0x5c ;120-28
XORLW 0xFF
MOVWF TMR1L
MOVLW 0xFF
MOVWF TMR1H
BCF PIR1, TMR1IF
CALL iWAIT
NOP
NOP
NOP
NOP
NOP
NOP
DECFSZ CNT, f
GOTO READ_LOOP
;goto READ_iButton_data
;goto READ_LOOP
RETURN
READ_1:
BSF iButtonReadingH, 7
GOTO CHECK_END_OF_READ_LOOP
Waiting_for_iButton:
CALL TIMER1_Init
CALL iButton_Init
start_iButton:
CALL READ_iButton
CALL RESET_iButton
CALL SEND_READ_COMMAND
CALL READ_iButton_data
; check if read right
; MOVLW 0xeb
MOVLW 0xff
SUBWF iButtonReadingM, w
BTFSC STATUS, Z
GOTO start_iButton
; MOVLW 0x4b
MOVLW 0xff
SUBWF iButtonReadingH, w
BTFSC STATUS, Z
GOTO start_iButton
RETURN
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
shipinits.h
;
; Clock_Init
;
;
Clock_Init:
banksel OSCCON
BSF OSCCON, IRCF0
BSF OSCCON, IRCF1
BSF OSCCON, IRCF2
RETURN
;
; SPI_Init
; --------------------------------------------------------------------
; Routine to initialize SPI on the PIC.
SPI_Init:
; Handle all the ANSEL and TRIS pins for SPI
banksel ANSELH
BCF ANSELH, ANS8; Turn off AD on SS
BCF ANSELH, ANS9; Turn off AD on SDO
BCF ANSELH, ANS10; Turn off AD on SDI/SDA
banksel TRISA
BSF TRISB, TRISB4; Set SDI/SDA line as input
BCF TRISC, TRISC7; Set SDO line as output
; Are we master or slave
BCF TRISB, TRISB6; Set SCK line as output for Master
banksel SSPSTAT
CLRF SSPSTAT; SMP = 0, CKE = 0, clear status bits
BSF SSPSTAT, CKE; CKE = 1
banksel SSPCON
MOVLW 0x31 ; Set up SPI port, Master mode, CLK/16
MOVWF SSPCON ; Mode 3 (CKE = 1, CKP = 1)
; Data sampled in middle (SMP = 0, Master mode)
; Set up the Slave Select lines as outputs raised high
banksel PORTC
BSF PORTC, 0
BSF PORTC, 1
BSF PORTC, 2
banksel TRISC
BCF TRISC, TRISC0; Set SS line as output
BCF TRISC, TRISC1; Set SS line as output
BCF TRISC, TRISC2; Set SS line as output
; Should be ready to transmit
banksel SSPBUF
MOVLW 0x80
MOVWF SSPBUF ; New data to xmit
RETURN
;
; EUSART_Init routine.
; --------------------------------------------------------------------
; Routine to initialize the EUSART peripheral on the PIC
EUSART_Init:
; Clear analog for RB5
banksel ANSEL
BCF ANSELH, ANS11
banksel TXSTA
; Choose 8 bit asynchronous /16
BCF TXSTA, SYNC
BSF TXSTA, BRGH
BCF BAUDCTL, BRG16
; Choose a 9600 Baud rate (10 MHz clock)
; MOVLW 0x0C
; MOVLW 0x40
; Choose a 9600 Baud rate (8 MHz clock)
MOVLW 0x33
MOVWF SPBRG
; Enable 8-bit tx
BCF TXSTA, TX9
; Enable transmit
BSF TXSTA, TXEN
; Enable serial port
banksel RCSTA
BSF RCSTA, SPEN
; Enable 8-bit rx
BCF RCSTA, RX9
; Enable receive
BSF RCSTA, CREN
; Enable interrupt
banksel PIE1
BSF PIE1, RCIE
RETURN
;
; PWM_Init routine
; --------------------------------------------------------------------
; Routine to initialize PWM on the PIC
PWM_Init:
; Ensure Bank 1
BSF STATUS, RP0
BCF STATUS, RP1
; Disable PWM pin
BSF TRISC, TRISC5 ; Set C5 to input
; Set PWM Period
MOVLW 0xF0
MOVWF PR2
; Configure CCP for PWM
BCF STATUS, RP0 ; Select bank 0
MOVLW 0x3E
MOVWF CCP1CON
; Set PWM duty cycle
MOVLW 0x00
MOVWF CCPR1L
; Configure and start Timer2
BCF PIR1, TMR2IF ; Clear Timer2 interrupt flag
BSF T2CON, T2CKPS1 ; Set Timer2 prescale value to 16
BSF T2CON, TMR2ON ; Turn Timer2 on
; Enable PWM output after new PWM cycle started
PWM_Pt_1:
BTFSS PIR1, TMR2IF
GOTO PWM_Pt_1
BSF STATUS, RP0 ; Select bank 1
BCF TRISC, TRISC5 ; Set C5 to output
RETURN
;
; Timer0_Init routine
; --------------------------------------------------------------------
; Routine to initialize Timer0 on the PIC
Timer0_Init:
banksel OPTION_REG
; Set as timer
BCF OPTION_REG, T0CS
; Set prescaler to timer 0
BCF OPTION_REG, PSA
; 1:256 prescaler
BSF OPTION_REG, PS0
BSF OPTION_REG, PS1
BSF OPTION_REG, PS2
; Clear the flag
banksel INTCON
BCF INTCON, T0IF
; Enable the interrupt
BSF INTCON, T0IE
; Reset the counter and flag
MOVLW Timer0Max
MOVWF Timer0Count
CLRF Timer0Flag
RETURN
LED_Init:
banksel PORTC
BSF PORTC, 4
banksel TRISC
BCF TRISC, 4
RETURN
synch.h
; We're waiting to synch up. We're waiting until we
; receive a broadcast message from the helm, at which
; point we want to check whether their ibutton data
; matches up well with ours
Waiting_for_Sync:
banksel PORTA
BTFSS COM_rxFlag, COM_rxDone
GOTO $-1
BCF COM_rxFlag, COM_rxDone
; We've received an API packet, is it ibutton?
MOVLW COM_ibutton
SUBWF COM_rxData1, W
BTFSS STATUS, Z
; Not ibutton, is it ping?
GOTO IsItPing
MOVF iButtonReadingH, W
SUBWF COM_rxData2, W
BTFSS STATUS, Z
GOTO Waiting_for_Sync
MOVF iButtonReadingM, W
SUBWF COM_rxData3, W
BTFSS STATUS, Z
GOTO Waiting_for_Sync
; It is an ibutton command! Now we store the address
; and send a matched response
; Store the address of helm
MOVF COM_rxAddrH, W
MOVWF HelmAddrH
MOVF COM_rxAddrL, W
MOVWF HelmAddrL
; Setup ping data to respond
MOVWF PingData2
MOVLW 0x04
MOVWF PingData1
; Send matched command to the helm
CALL SetAddressToHelm
MOVLW COM_craft
MOVWF COM_data1
MOVLW 0x00
MOVWF COM_data2
MOVLW COM_matched
MOVWF COM_data3
xxx: CALL API_TxPacket
CALL Wait
CALL API_TxPacket
CALL Wait
; Save Team
BTFSC iButtonReadingM, 0
GOTO $+3
CLRF Team ; Team Blue if iButton reading is even
RETURN
MOVLW 0xF0
MOVWF Team ; Team Red if iButton reading is odd
; Get out of waiting mode
BCF StateMachine, Waiting
RETURN
IsItPing:
MOVLW COM_adm
SUBWF COM_rxData1, W
BTFSS STATUS, Z
; It's not admiral
GOTO Waiting_for_Sync
; It's admiral
; Command is from the admiral, now we need to check the admiral address
CALL CheckAdmAddr
ADDLW 0x00
BTFSS STATUS, Z
GOTO Waiting_for_Sync
; Address matches admiral, now which command is sent?
MOVF COM_rxData2, W
BTFSS STATUS, Z
GOTO Waiting_for_Sync
MOVLW COM_ping
SUBWF COM_rxData3, W
BTFSS STATUS, Z
CALL AdmPing
GOTO Waiting_for_Sync
vars.h
; Utility Variables
BIT0HI equ 0x01
BIT1HI equ 0x02
BIT2HI equ 0x04
#define SPI_SlaveRt PORTC,2
#define SPI_SlaveLft PORTC,1
#define SPI_Slave3 PORTC,0
Timer0Max equ 0x0A
AdmiralAddrH equ 0xBC
AdmiralAddrL equ 0xFF
; Locations in memory
SPI_RXDATA equ 0x20
SPI_TXDATA equ 0x21
Timer1 equ 0x22
Timer2 equ 0x23
W_TEMP equ 0x24
STATUS_TEMP equ 0x25
COM_addrs_msb equ 0x26
COM_addrs_lsb equ 0x27
COM_data1 equ 0x28
COM_data2 equ 0x29
COM_data3 equ 0x2A
COM_checksum equ 0x2B
COM_frameid equ 0x2C
COM_options equ 0x2D
COM_rxBuffAddr equ 0x2E
COM_rxAddrH equ 0x2E
COM_rxAddrL equ 0x2F
COM_rxData1 equ 0x32
COM_rxData2 equ 0x33
COM_rxData3 equ 0x34
COM_rxIndex equ 0x3B
COM_rxFlag equ 0x3C
COM_rxDone equ 7
Timer0Count equ 0x3D
Timer0Flag equ 0x3E
ShipDirection equ 0x3F
ShipSpeed equ 0x41
ShipWaterSpd equ 0x42
DirMod equ 0x43
LeftMotor equ 0x44
RightMotor equ 0x45
PortAGhost equ 0x46
HelmAddrH equ 0x47
HelmAddrL equ 0x48
PingData1 equ 0x49
PingData2 equ 0x4A
TimeOutFlag equ 0x4C
TimeOutTimer equ 0x4D
TimeOutTimerMax equ 0x09
; State machine variables
; ------------------------
StateMachine equ 0x4B
Waiting equ 1
; variables for iButton
readROMcommand equ 0x50
CNT equ 0x51
iButtonReadingH equ 0x52
iButtonReadingM equ 0x53
iButtonReadingL equ 0x54
Team equ 0x55
TeamRed equ 1
TeamBlue equ 0
#define iButtonPin PORTA, 0
wait.h
Wait:
banksel Timer1
MOVLW 0xFF; setup the first counter for waiting
MOVWF Timer2
Wait2:
MOVLW 0xFF; setup the second counter for waiting
MOVWF Timer1
Wait1:
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
DECFSZ Timer1, F; decrement first counter, if zero loop
GOTO Wait1; is done
DECFSZ Timer2, F; decrement second counter, if zero loop
GOTO Wait2; is done
RETURN
xbee_comm.h
API_Start equ 0x7E
API_TxData equ 0x01
API_NoRsp equ 0x00
API_Tx16b equ 0x01
API_TxResult equ 0x89
API_Rx16b equ 0x81
API_Broadcast equ 0xFF
COM_lnth_msb equ 0x00
COM_lnth_lsb equ 0x08
COM_rxLn equ 0x08
; Types of messages
COM_nav equ 0x02
COM_adm equ 0x04
COM_ibutton equ 0x01
COM_craft equ 0x08
COM_pingresp equ 0x10
COM_ack equ 0x80
; Ship to helm message tags
COM_matched equ 0x01
COM_sdreceived equ 0x02
; Admiral to ship message tags
COM_standdown equ 0x01
COM_ping equ 0x80
COM_hardreset equ 0x40
COM_softreset equ 0x20
EUSART_txL macro byte
CALL Wt_USART_TxRdy
banksel TXREG
MOVLW byte
MOVWF TXREG
endm
EUSART_txF macro file
CALL Wt_USART_TxRdy
banksel TXREG
MOVF file, W
MOVWF TXREG
endm
ChecksumCalc macro
; Ensure Bank 0
BCF STATUS,RP0
BCF STATUS,RP1
; Start setting up the checksum
MOVLW API_Tx16b
MOVWF COM_checksum
MOVF COM_frameid, W
ADDWF COM_checksum, F
MOVF COM_options, W
ADDWF COM_checksum, F
MOVF COM_addrs_msb, W
ADDWF COM_checksum, F
MOVF COM_addrs_lsb, W
ADDWF COM_checksum, F
MOVF COM_data1, W
ADDWF COM_checksum, F
MOVF COM_data2, W
ADDWF COM_checksum, F
MOVF COM_data3, W
ADDWF COM_checksum, F
COMF COM_checksum, F
endm
; Deprecated, do NOT use
SetToSend macro frameID, options, d1, d2, d3
; Ensure Bank 0
BCF STATUS,RP0
BCF STATUS,RP1
; Setup frame id, options, rf data
MOVLW frameID
MOVWF COM_frameid
MOVLW options
MOVWF COM_options
MOVLW d1
MOVWF COM_data1
MOVLW d2
MOVWF COM_data2
MOVLW d3
MOVWF COM_data3
endm
; Wait til the transfer buffer is ready
; --------------------------------------------------------------------
; Routine that waits until the EUSART is ready to transmit another byte of data
Wt_USART_TxRdy:
banksel TXSTA ; wait til tranfer register ready
BTFSS TXSTA, TRMT ; check state of transmit buffer
GOTO $-1
RETURN
API_TxPacket:
ChecksumCalc
EUSART_txL API_Start
EUSART_txL COM_lnth_msb
EUSART_txL COM_lnth_lsb
EUSART_txL API_Tx16b
EUSART_txF COM_frameid
EUSART_txF COM_addrs_msb
EUSART_txF COM_addrs_lsb
EUSART_txF COM_options
EUSART_txF COM_data1
EUSART_txF COM_data2
EUSART_txF COM_data3
EUSART_txF COM_checksum
RETURN
SetAddressToBroadcast:
banksel PORTA
MOVLW 0xFF
MOVWF COM_addrs_msb
MOVWF COM_addrs_lsb
RETURN
SetAddressToAdmiral:
banksel PORTA
MOVLW AdmiralAddrH
MOVWF COM_addrs_msb
MOVLW AdmiralAddrL
MOVWF COM_addrs_lsb
RETURN
SetAddressToHelm:
banksel PORTA
MOVF HelmAddrH, W
MOVWF COM_addrs_msb
MOVF HelmAddrL, W
MOVWF COM_addrs_lsb
RETURN
CheckHelmAddr:
banksel PORTA
MOVF HelmAddrH, W
SUBWF COM_rxAddrH, W
BTFSS STATUS, Z
RETLW 0xFF
MOVF HelmAddrL, W
SUBWF COM_rxAddrL, W
BTFSS STATUS, Z
RETLW 0xFF
RETLW 0x00
CheckAdmAddr:
banksel PORTA
MOVLW AdmiralAddrH
SUBWF COM_rxAddrH, W
BTFSS STATUS, Z
RETLW 0xFF
MOVLW AdmiralAddrL
SUBWF COM_rxAddrL, W
BTFSS STATUS, Z
RETLW 0xFF
RETLW 0x00
SSlvL.asm
; Final Project - Terman Pond Flotilla
; ME218B
; By Allen Cheung
; -----------------------------------------------------------------
;
;
; Pins used:
; RB<7, 5> as transmit/receive lines for EUSART
;
list P=PIC16F690
#include "p16F690.inc"
#include pwm.h
__config (_CP_OFF & _WDT_OFF & _PWRTE_ON & _INTOSCIO)
;
; Variable Definitions
; ---------------------------------------------------------------
; Utility Variables
BIT0HI equ 0x01
BIT1HI equ 0x02
BIT2HI equ 0x04
Tmr0ServMax equ 0x3F
Timer0Max equ 0xFF
#define ServoPin PORTA,1
MotorSpeedMask equ 0xE0
; Locations in memory
SPI_RXDATA equ 0x20
SPI_TXDATA equ 0x21
Timer1 equ 0x22
Timer2 equ 0x23
W_TEMP equ 0x24
STATUS_TEMP equ 0x25
Timer0Count equ 0x26
Timer0Flag equ 0x27
Tmr0ServCount equ 0x28
ServoPulse equ 0x29
PORTAghost equ 0x2A
; Beginning of Program
; --------------------------------------------------------------------
org 0
goto Main
org 5
goto Interrupt
;
; Tables
; --------------------------------------------------------------------
; Lookup table for bit pattern to write to Port C output
END_TBL:
; make sure address is less than 0xff
ServoTable:
ADDWF PCL, F
RETLW 0x2C
RETLW 0x2D
RETLW 0x2E
RETLW 0x2F
RETLW 0x30
RETLW 0x31
RETLW 0x32
RETLW 0x34
RETLW 0x34
RETLW 0x36
RETLW 0x37
RETLW 0x38
RETLW 0x39
RETLW 0x3A
RETLW 0x3B
RETLW 0x3C
;
; Clock_Init
;
;
Clock_Init:
banksel OSCCON
BSF OSCCON, IRCF0
BSF OSCCON, IRCF1
BSF OSCCON, IRCF2
RETURN
;
; SPI_Init
; --------------------------------------------------------------------
; Routine to initialize SPI on the PIC.
SPI_Init:
; Handle all the ANSEL and TRIS pins for SPI
banksel ANSELH
BCF ANSELH, ANS8; Turn off AD on SS
BCF ANSELH, ANS9; Turn off AD on SDO
BCF ANSELH, ANS10; Turn off AD on SDI/SDA
banksel TRISA
BSF TRISB, TRISB4; Set SDI/SDA line as input
BCF TRISC, TRISC7; Set SDO line as output
BSF TRISC, TRISC6; Set SS line as input
; Are we master or slave
BSF TRISB, TRISB6; Set SCK line as input for Slave
banksel SSPSTAT
CLRF SSPSTAT; SMP = 0, CKE = 0, clear status bits
BSF SSPSTAT, CKE; CKE = 1
banksel SSPCON
MOVLW 0x35 ; Set up SPI port, Slave mode (SS), enable
MOVWF SSPCON ; Mode 3 (CKE = 1, CKP = 1)
; (SMP cleared for slave mode)
banksel PIE1
BSF PIE1, SSPIE ; Enable SSP interrupt
banksel PIR1
BCF PIR1, SSPIF ; Clear interrupt flag
; Should be ready to transmit
RETURN
;
; PWM_Init routine
; --------------------------------------------------------------------
; Routine to initialize PWM on the PIC
PWM_Init:
; Ensure Bank 1
BSF STATUS, RP0
BCF STATUS, RP1
; Disable PWM pin
BSF TRISC, TRISC5 ; Set C5 to input
; Set PWM Period
MOVLW 0xE0
MOVWF PR2
; Configure CCP for PWM
BCF STATUS, RP0 ; Select bank 0
MOVLW 0x0C ; Active High
MOVWF CCP1CON
; Set PWM duty cycle
MOVLW 0x00
MOVWF CCPR1L
; Configure and start Timer2
BCF PIR1, TMR2IF ; Clear Timer2 interrupt flag
BSF T2CON, T2CKPS0 ; Set Timer2 prescale value to 4
BSF T2CON, TMR2ON ; Turn Timer2 on
; Enable PWM output after new PWM cycle started
PWM_Pt_1: BTFSS PIR1, TMR2IF
GOTO PWM_Pt_1
BSF STATUS, RP0 ; Select bank 1
BCF TRISC, TRISC5 ; Set C5 to output
RETURN
PWM_ActiveHi:
banksel CCP1CON
MOVLW 0x0C
MOVWF CCP1CON
RETURN
PWM_ActiveLo:
banksel CCP1CON
MOVLW 0x0E
MOVWF CCP1CON
RETURN
;
; Timer0_Init routine
; --------------------------------------------------------------------
; Routine to initialize Timer0 on the PIC
Timer0_Init:
banksel OPTION_REG
; Set as timer
BCF OPTION_REG, T0CS
; Set prescaler to WDT
BSF OPTION_REG, PSA
; Clear the flag
banksel INTCON
BCF INTCON, T0IF
; Enable the interrupt
BSF INTCON, T0IE
; Reset the counter and flag
MOVLW Timer0Max
MOVWF Timer0Count
MOVLW Tmr0ServMax
MOVWF Tmr0ServCount
CLRF Timer0Flag
RETURN
LED_Init:
banksel PORTA
CLRF PORTAghost
BSF PORTA, 0
BSF PORTAghost, 0
banksel TRISA
BCF TRISA, 0
RETURN
HbridgeCtrlInit:
CALL PWM_Init
banksel PORTC
BCF PORTC, 4
banksel TRISC
BCF TRISC, TRISC4
RETURN
Servo_Init:
banksel PORTA
BCF ServoPin
banksel TRISA
BCF TRISA, 1
RETURN
;
; Initialize routine.
; --------------------------------------------------------------------
Initialize:
; Setup Clock
CALL Clock_Init
; Setup Timer0
CALL Timer0_Init
; Setup Hbridge control lines
CALL HbridgeCtrlInit
; Setup SPI
CALL SPI_Init
; Setup LEDs
CALL LED_Init
; Setup Servo
CALL Servo_Init
; Enable Interrupts
banksel INTCON
BSF INTCON, GIE
BSF INTCON, PEIE
RETURN
;********************************************************************************
;********************************************************************************
; Main Loop
; --------------------------------------------------------------------
; Continuously loops and handles the program
; Looks for a button press, looks for a received message on EUSART
; If slave select raised transmits message or ack
;********************************************************************************
;********************************************************************************
Main:
CALL Initialize
banksel PORTA
; Initialize starting values to neutral motor/rudder
MOVLW 0x34
MOVWF ServoPulse
SetPWMDuty 0x00
banksel PORTC
BCF PORTC, 4
; This is the main loop, here we just do nothing, checking the timer0 flag
; to control the LED. All responses are handled in SPI interrupt
PNT_2:
NOP
CALL CheckTimer0Flag
GOTO PNT_2
CheckTimer0Flag:
banksel PORTA
BTFSS Timer0Flag, 0
RETURN
BCF Timer0Flag, 0
; Toggle LED
BTFSS PORTAghost, 0
GOTO $+4
BCF PORTAghost, 0
BCF PORTA, 0
RETURN
BSF PORTAghost, 0
BSF PORTA, 0
RETURN
;
; Interrupt Service Routine
; ***********************************************************************
; ***** The PIC's one and only ISR... =( ******************************
; ***********************************************************************
Interrupt:
; PUSH
MOVWF W_TEMP ; Copy W to TEMP register
SWAPF STATUS, W ; Swap status to be saved into W
banksel PORTA
MOVWF STATUS_TEMP ; Save status to STATUS_TEMP register
; ISR
banksel PIR1
BTFSC PIR1, SSPIF
CALL SPI_Int
BTFSC INTCON, T0IF
CALL Timer0_Int
; POP
banksel PORTA
SWAPF STATUS_TEMP, W ; Swap nibbles in STATUS_TEMP register
; and place result into W
MOVWF STATUS ; Move W into STATUS register
; (sets bank to original state)
SWAPF W_TEMP, F ; Swap nibbles in W_TEMP and place result in W_TEMP
SWAPF W_TEMP, W ; Swap nibbles in W_TEMP and place result into W
RETFIE
; SPI_Int
; --------------------------------------------------------------------
; ISR that receives/transmits from SPI, but primary purpose is to receive
SPI_Int:
BCF PIR1, SSPIF
banksel PORTA
MOVF SSPBUF, W ; WREG reg = contents of SSPBUF
MOVWF SPI_RXDATA ; Save in user RAM, if data is meaningful
MOVF SPI_TXDATA, W ; W reg = contents of TXDATA
MOVWF SSPBUF ; New data to xmit
; Is it for the left PIC?
BTFSS SPI_RXDATA, 1
RETURN
; Process the command
BTFSC SPI_RXDATA, 0
GOTO ServoDir
; Motor speed command
; upper nibble holds 4 bits of motor speed information
BTFSS SPI_RXDATA, 7
GOTO BackwardsMot
; Set means run "forwards"
ForwardsMot: BCF PORTC, 4
MOVLW 0x80
SUBWF SPI_RXDATA, F
RLF SPI_RXDATA, F
ANDLW MotorSpeedMask
; Divide by two
RRF SPI_RXDATA, F
BCF SPI_RXDATA, 7
MOVF SPI_RXDATA, W
banksel CCPR1L
MOVWF CCPR1L ; Set new duty cycle
CALL PWM_ActiveHi
RETURN
BackwardsMot: BSF PORTC, 4
COMF SPI_RXDATA, F
MOVLW 0x80
SUBWF SPI_RXDATA, F
RLF SPI_RXDATA, F
ANDLW MotorSpeedMask
; Divide by two
RRF SPI_RXDATA, F
BCF SPI_RXDATA, 7
MOVF SPI_RXDATA, W
banksel CCPR1L
MOVWF CCPR1L
CALL PWM_ActiveLo
RETURN
; Command to set the rudder
; upper nibble should hold 4 bits of direction information
ServoDir:
RRF SPI_RXDATA, F
RRF SPI_RXDATA, F
RRF SPI_RXDATA, F
RRF SPI_RXDATA, F
MOVLW 0x0F
ANDWF SPI_RXDATA, W
CALL ServoTable
MOVWF ServoPulse
RETURN
Timer0_Int:
BCF INTCON, T0IF
banksel PORTA
; Check on the servo pulse width
DECFSZ Tmr0ServCount
GOTO Check
; If the counter finished, set servo pin high
BSF ServoPin
MOVLW Tmr0ServMax
MOVWF Tmr0ServCount
GOTO Counter2
; Check if the counter is equal to our pulsewidth
; if so, set the pin low
Check:
MOVF ServoPulse, W
SUBWF Tmr0ServCount, W
BTFSS STATUS, Z
GOTO Counter2
BCF ServoPin
; Check on our other counter
Counter2:
DECFSZ Timer0Count
RETURN
; If counter finished, set flag and reset counter
BSF Timer0Flag, 0
MOVLW Timer0Max
MOVWF Timer0Count
RETURN
END
SSlvR.asm
; Final Project - Terman Pond Flotilla
; ME218B
; By Allen Cheung
; -----------------------------------------------------------------
;
;
; Pins used:
; RB<7, 5> as transmit/receive lines for EUSART
;
list P=PIC16F690
#include "p16F690.inc"
#include pwm.h
__config (_CP_OFF & _WDT_OFF & _PWRTE_ON & _INTOSCIO)
;
; Variable Definitions
; ---------------------------------------------------------------
; Utility Variables
BIT0HI equ 0x01
BIT1HI equ 0x02
BIT2HI equ 0x04
Tmr0ServMax equ 0x3F
Timer0Max equ 0xFF
#define ServoPin PORTA,1
MotorSpeedMask equ 0xE0
; Locations in memory
SPI_RXDATA equ 0x20
SPI_TXDATA equ 0x21
Timer1 equ 0x22
Timer2 equ 0x23
W_TEMP equ 0x24
STATUS_TEMP equ 0x25
Timer0Count equ 0x26
Timer0Flag equ 0x27
Tmr0ServCount equ 0x28
ServoPulse equ 0x29
PORTAghost equ 0x2A
; Beginning of Program
; --------------------------------------------------------------------
org 0
goto Main
org 5
goto Interrupt
;
; Tables
; --------------------------------------------------------------------
; Lookup table for bit pattern to write to Port C output
END_TBL:
; make sure address is less than 0xff
ServoTable:
ADDWF PCL, F
RETLW 0x2C
RETLW 0x2D
RETLW 0x2E
RETLW 0x2F
RETLW 0x30
RETLW 0x31
RETLW 0x32
RETLW 0x34
RETLW 0x34
RETLW 0x36
RETLW 0x37
RETLW 0x38
RETLW 0x39
RETLW 0x3A
RETLW 0x3B
RETLW 0x3C
;
; Clock_Init
;
;
Clock_Init:
banksel OSCCON
BSF OSCCON, IRCF0
BSF OSCCON, IRCF1
BSF OSCCON, IRCF2
RETURN
;
; SPI_Init
; --------------------------------------------------------------------
; Routine to initialize SPI on the PIC.
SPI_Init:
; Handle all the ANSEL and TRIS pins for SPI
banksel ANSELH
BCF ANSELH, ANS8; Turn off AD on SS
BCF ANSELH, ANS9; Turn off AD on SDO
BCF ANSELH, ANS10; Turn off AD on SDI/SDA
banksel TRISA
BSF TRISB, TRISB4; Set SDI/SDA line as input
BCF TRISC, TRISC7; Set SDO line as output
BSF TRISC, TRISC6; Set SS line as input
; Are we master or slave
BSF TRISB, TRISB6; Set SCK line as input for Slave
banksel SSPSTAT
CLRF SSPSTAT; SMP = 0, CKE = 0, clear status bits
BSF SSPSTAT, CKE; CKE = 1
banksel SSPCON
MOVLW 0x35 ; Set up SPI port, Slave mode (SS), enable
MOVWF SSPCON ; Mode 3 (CKE = 1, CKP = 1)
; (SMP cleared for slave mode)
banksel PIE1
BSF PIE1, SSPIE ; Enable SSP interrupt
banksel PIR1
BCF PIR1, SSPIF ; Clear interrupt flag
; Should be ready to transmit
RETURN
;
; PWM_Init routine
; --------------------------------------------------------------------
; Routine to initialize PWM on the PIC
PWM_Init:
; Ensure Bank 1
BSF STATUS, RP0
BCF STATUS, RP1
; Disable PWM pin
BSF TRISC, TRISC5 ; Set C5 to input
; Set PWM Period
MOVLW 0xE0
MOVWF PR2
; Configure CCP for PWM
BCF STATUS, RP0 ; Select bank 0
MOVLW 0x0C ; Active High
MOVWF CCP1CON
; Set PWM duty cycle
MOVLW 0x00
MOVWF CCPR1L
; Configure and start Timer2
BCF PIR1, TMR2IF ; Clear Timer2 interrupt flag
BSF T2CON, T2CKPS0 ; Set Timer2 prescale value to 4
BSF T2CON, TMR2ON ; Turn Timer2 on
; Enable PWM output after new PWM cycle started
PWM_Pt_1: BTFSS PIR1, TMR2IF
GOTO PWM_Pt_1
BSF STATUS, RP0 ; Select bank 1
BCF TRISC, TRISC5 ; Set C5 to output
RETURN
PWM_ActiveHi:
banksel CCP1CON
MOVLW 0x0C
MOVWF CCP1CON
RETURN
PWM_ActiveLo:
banksel CCP1CON
MOVLW 0x0E
MOVWF CCP1CON
RETURN
;
; Timer0_Init routine
; --------------------------------------------------------------------
; Routine to initialize Timer0 on the PIC
Timer0_Init:
banksel OPTION_REG
; Set as timer
BCF OPTION_REG, T0CS
; Set prescaler to WDT
BSF OPTION_REG, PSA
; Clear the flag
banksel INTCON
BCF INTCON, T0IF
; Enable the interrupt
BSF INTCON, T0IE
; Reset the counter and flag
MOVLW Timer0Max
MOVWF Timer0Count
MOVLW Tmr0ServMax
MOVWF Tmr0ServCount
CLRF Timer0Flag
RETURN
LED_Init:
banksel PORTA
CLRF PORTAghost
BSF PORTA, 0
BSF PORTAghost, 0
banksel TRISA
BCF TRISA, 0
RETURN
HbridgeCtrlInit:
CALL PWM_Init
banksel PORTC
BCF PORTC, 4
banksel TRISC
BCF TRISC, TRISC4
RETURN
Servo_Init:
banksel PORTA
BCF ServoPin
banksel TRISA
BCF TRISA, 1
RETURN
;
; Initialize routine.
; --------------------------------------------------------------------
Initialize:
; Setup Clock
CALL Clock_Init
; Setup Timer0
CALL Timer0_Init
; Setup Hbridge control lines
CALL HbridgeCtrlInit
; Setup SPI
CALL SPI_Init
; Setup LEDs
CALL LED_Init
; Setup Servo
CALL Servo_Init
; Enable Interrupts
banksel INTCON
BSF INTCON, GIE
BSF INTCON, PEIE
RETURN
;********************************************************************************
;********************************************************************************
; Main Loop
; --------------------------------------------------------------------
; Continuously loops and handles the program
; Looks for a button press, looks for a received message on EUSART
; If slave select raised transmits message or ack
;********************************************************************************
;********************************************************************************
Main:
CALL Initialize
banksel PORTA
; Initialize starting values to neutral motor/rudder
MOVLW 0x34
MOVWF ServoPulse
SetPWMDuty 0x00
banksel PORTC
BCF PORTC, 4
; This is the main loop, here we just do nothing, checking the timer0 flag
; to control the LED. All responses are handled in SPI interrupt
PNT_2:
NOP
CALL CheckTimer0Flag
GOTO PNT_2
CheckTimer0Flag:
banksel PORTA
BTFSS Timer0Flag, 0
RETURN
BCF Timer0Flag, 0
; Toggle LED
BTFSS PORTAghost, 0
GOTO $+4
BCF PORTAghost, 0
BCF PORTA, 0
RETURN
BSF PORTAghost, 0
BSF PORTA, 0
RETURN
;
; Interrupt Service Routine
; ***********************************************************************
; ***** The PIC's one and only ISR... =( ******************************
; ***********************************************************************
Interrupt:
; PUSH
MOVWF W_TEMP ; Copy W to TEMP register
SWAPF STATUS, W ; Swap status to be saved into W
banksel PORTA
MOVWF STATUS_TEMP ; Save status to STATUS_TEMP register
; ISR
banksel PIR1
BTFSC PIR1, SSPIF
CALL SPI_Int
BTFSC INTCON, T0IF
CALL Timer0_Int
; POP
banksel PORTA
SWAPF STATUS_TEMP, W ; Swap nibbles in STATUS_TEMP register
; and place result into W
MOVWF STATUS ; Move W into STATUS register
; (sets bank to original state)
SWAPF W_TEMP, F ; Swap nibbles in W_TEMP and place result in W_TEMP
SWAPF W_TEMP, W ; Swap nibbles in W_TEMP and place result into W
RETFIE
; SPI_Int
; --------------------------------------------------------------------
; ISR that receives/transmits from SPI, but primary purpose is to receive
SPI_Int:
BCF PIR1, SSPIF
banksel PORTA
MOVF SSPBUF, W ; WREG reg = contents of SSPBUF
MOVWF SPI_RXDATA ; Save in user RAM, if data is meaningful
MOVF SPI_TXDATA, W ; W reg = contents of TXDATA
MOVWF SSPBUF ; New data to xmit
BTFSC SPI_RXDATA, 1
RETURN
; Process the command
BTFSC SPI_RXDATA, 0
GOTO ServoDir
; Motor speed command
; upper nibble holds 4 bits of motor speed information
BTFSS SPI_RXDATA, 7
GOTO BackwardsMot
; Set means run "forwards"
ForwardsMot: BCF PORTC, 4
MOVLW 0x80
SUBWF SPI_RXDATA, F
RLF SPI_RXDATA, F
ANDLW MotorSpeedMask
; Divide by two
RRF SPI_RXDATA, F
BCF SPI_RXDATA, 7
MOVF SPI_RXDATA, W
banksel CCPR1L
MOVWF CCPR1L ; Set new duty cycle
CALL PWM_ActiveHi
RETURN
BackwardsMot: BSF PORTC, 4
COMF SPI_RXDATA, F
MOVLW 0x80
SUBWF SPI_RXDATA, F
RLF SPI_RXDATA, F
ANDLW MotorSpeedMask
; Divide by two
RRF SPI_RXDATA, F
BCF SPI_RXDATA, 7
MOVF SPI_RXDATA, W
banksel CCPR1L
MOVWF CCPR1L
CALL PWM_ActiveLo
RETURN
; Command to set the rudder
; upper nibble should hold 4 bits of direction information
ServoDir:
RRF SPI_RXDATA, F
RRF SPI_RXDATA, F
RRF SPI_RXDATA, F
RRF SPI_RXDATA, F
MOVLW 0x0F
ANDWF SPI_RXDATA, W
CALL ServoTable
MOVWF ServoPulse
RETURN
Timer0_Int:
BCF INTCON, T0IF
banksel PORTA
; Check on the servo pulse width
DECFSZ Tmr0ServCount
GOTO Check
; If the counter finished, set servo pin high
BSF ServoPin
MOVLW Tmr0ServMax
MOVWF Tmr0ServCount
GOTO Counter2
; Check if the counter is equal to our pulsewidth
; if so, set the pin low
Check:
MOVF ServoPulse, W
SUBWF Tmr0ServCount, W
BTFSS STATUS, Z
GOTO Counter2
BCF ServoPin
; Check on our other counter
Counter2:
DECFSZ Timer0Count
RETURN
; If counter finished, set flag and reset counter
BSF Timer0Flag, 0
MOVLW Timer0Max
MOVWF Timer0Count
RETURN
END
pwm.h
SetPWMDuty macro duty
banksel CCPR1L
MOVLW duty
MOVWF CCPR1L
endm