Boat Right Helper .asm ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Helper PIC 1 (this pic drives the RIGHT motor)
; Outputs right motor PWM, and configures Red Base LED, Blue Base LED, and iButton Sync LED
; 218C Spring 2008
; Redneck Yacht Club
; Kuan Li, Stephanie Lue, Christine Tower
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
list P=PIC16F690
#include "p16f690.inc"
__config (_CP_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC)

; Note: Timing is based on using the external resonator (10MHz)
;
;               variable definitions
W_TEMP          equ             0x20
STATUS_TEMP     equ             0x21
PWM_Bit         equ             0x05            ; control of PWM is on C5
byte_count      equ             0x22
PWM_byte        equ             0x23
Special_byte    equ             0x24
temp_received   equ             0x25
;
;               #Defines
#define         RIGHT_HEADER_BYTE     0xAA           
;
                org             0
                                     goto            Main
                org             4
                goto            InterruptServiceRoutine
                org             5
;
;       Tables can go here
;
END_TBL:
;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Main
;Main program
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Main:
                call            PWM_Init
                call            General_Init
                call            SSP_Init
                call            Receive_Init
ForeverLoop:
                banksel         byte_count
                movlw           0x03
                xorwf           byte_count,W
                btfsc           STATUS,Z                        ; if Z = 1, then 3 bytes have been received (new data)
                goto            ProcessPacket
                goto            ForeverLoop
ProcessPacket:
                call            DriveRightForward               ; update the PWM value
                call            LightLEDs                       ; light iButton sync, Red and Blue base active LEDs accordingly
                banksel         byte_count                     
                clrf            byte_count                      ; clear byte count for next packet
                goto            ForeverLoop
;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Initialize Timer2
; This subroutine intializes timer 0: sets the prescale value,  and clears the overflow flag
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
TMR2_Init:
                BANKSEL         T2CON                           ; go to timer 2 bank
                CLRF            T2CON                           ; stop timer 2, prescaler = 1:1, post scaler
                CLRF            TMR2                            ; Clear Timer 2 register                
                CLRF            INTCON                          ; Disable interrupts
                BANKSEL         PIE1                            ; Bank 1
                BCF             PIE1, TMR2IE                    ; clear TMR2IE bit in PIE1 register
                BCF             STATUS, RP0                     ; Bank 0
                CLRF            PIR1                            ; Clear peripheral interrupts Flags
                MOVLW           0x7B                            ; Pre scalar = 1:16, Post scalar = 1:16
                MOVWF           T2CON                           ; move pre scale and post scale to T2CON register; Timer2 is not yet enabled
                RETURN
;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Initialize PWM
; This subroutine intializes timer 0: sets the prescale value,  and clears the overflow flag
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
PWM_Init:
                PAGESEL         TMR2_Init                       ; go to page with TMR2_Init
                CALL            TMR2_Init                       ; initialize Timer 2 pre and post scalar, This doesn't turn on timer 2 or set PR2 (PWM frequency)
                CLRF            CCP1CON                         ; CCP Module is off for PWM 1
                CLRF            TMR2                            ; Clear Timer 2
                BANKSEL         PR2                             ; go to bank with PR2 register
                MOVLW           0xFF                            ; move 0xFF (256) to W register
                MOVWF           PR2                             ; set PR2 to compare only after 256 ticks Assuming Fosc = 8Mhz, Prescale 1:16, PWM frequency is 488 Hz
                BANKSEL         CCPR1L                          ; go to bank with CCPR1L register
                MOVLW           0x00                            ; 
                MOVWF           CCPR1L                          ; initially set Duty Cycle = 0% for PWM 1
                BANKSEL         INTCON                          ; go to bank with INTCON
                BSF             INTCON, GIE                     ; enable global interrupt
                BSF             INTCON, PEIE                    ; enable peripheral interrupt
                BANKSEL         PIE1                             ; go to bank with PIE
                BSF             PIE1, TMR2IE                     ; enable Timer 2 to PR2 Match interrupt                 
                BSF             PIE1, CCP1IE                     ; enable CCP1 interrupt for PWM 1 ** CCP1IE CHeck that it is not used for PWM mode
                BANKSEL         PIR1
                CLRF            PIR1                            ; clear peripheral interrupts flags
                BANKSEL         CCP1CON                         ; go to bank with CCP1CON
                MOVLW           0x0C            
                MOVWF           CCP1CON                         ; PWM mode, 2 LSBs of Duty cycle = 00 (using only the 8 Msbs)
                BANKSEL         TRISC                           ; go to bank with TRISC
                BCF             TRISC, PWM_Bit                  ; make pin output for PWM 1 ** CHECK TO SEE IF THESE ARE IN THE SAME BANK
                BANKSEL         T2CON                           
                BSF             T2CON, TMR2ON                   ; turn Timer 2 on; starts to increment


                ;This is for the TLE 5206 (direction pin)
                banksel         TRISC
                bcf             TRISC,4
                banksel         PORTC
                bcf             PORTC,4                         ; Set Port C4 low
                RETURN          

;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; General Init
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
General_Init:
                BANKSEL         OSCCON
                MOVLW           0x70                            ; 0111 0000 set internal resonator to be 8MHz
                IORWF           OSCCON, 1                       ; inclusive OR, place result back into OSCCON register
                BANKSEL         TRISC
;               LED port initialization
                BCF             TRISC, 4                        ; make C4 an output
                bcf             TRISC, 0                        ; make C0 an output
                bcf             TRISC, 1                        ; make C1 an output
                bcf             TRISC, 2                        ; make C2 an output
                banksel         PORTC
                bcf             PORTC, 4
                bcf             PORTC, 0
                bcf             PORTC, 1
                bcf             PORTC, 2                        ; initially clear Ports C0-2,4
                banksel         ANSEL
                bcf             ANSEL,ANS4                      ; make C0 digital I/O
                bcf             ANSEL,ANS5                      ; make C1 digital I/O
                bcf             ANSEL,ANS6                      ; make C2 digital I/O
;               Clear receive variables
                banksel         byte_count
                clrf            byte_count                      ; initially clear byte_count
                banksel         PWM_byte
                clrf            PWM_byte                        ; initially clear PWM_byte
                banksel         temp_received
                clrf            temp_received                   ; initially clear temp_received
                banksel         Special_byte
                clrf            Special_byte                    ; initially clear Special_byte        
                RETURN
;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Receive Init
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Receive_Init:
                banksel         PIE1
                bsf             PIE1,SSPIE                      ; enable Synchronous Serial Port interrupts
                banksel         PIR1
                bcf             PIR1,SSPIF                      ; initially clear the SSPIF flag
                return
;
;               
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Setup for all the SSP:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SSP_Init:
                banksel	SSPSTAT		;The Sync Serial Port Status Register (pg 180 of manual)
                bsf	SSPSTAT,SMP		;Input data sampled at end of data output line. (clear for Slave mode)
                nop
                bsf	SSPSTAT,CKE		;Data transmitted on falling edge of SCK
                nop		
                
                banksel         SSPCON		;The Sync Serial Port Control Register (pg 181 of manual)
                bsf	SSPCON,SSPEN	                ;SSP enable bit.
                nop			
                bsf	SSPCON,CKP		;Clock polarity Select Bit; transmit happens on rising edge, receive on falling edge
                nop
                ;The SSP mode select. 
                ;This is for the Slave mode: with clock = SCK pin, and SS pin control disabled
                ;----------------------	
                bcf	SSPCON,SSPM3	
                nop
                bsf	SSPCON,SSPM2	
                nop
                bcf	SSPCON,SSPM1	
                nop
                bcf	SSPCON,SSPM0	
                nop

                banksel	ANSELH
	bcf	ANSELH,1		; Sets the ANSEL9 (RC7) to digital input/output
	nop
	bcf	ANSELH,2		; Sets the ANSEL10 (RB4) to digital input/output.
		
	banksel	TRISC
                bcf	TRISC,7		; Set the Data direction to output for the SDO for the SSP
	nop
                bsf	TRISB,4		; Set the Data direction to input for the SDI for the SSP		
	nop                

                banksel	TRISB
;                bcf	TRISB,6		; Clear the SCK to output for MASTER MODE on TRISB 6								
;                nop
                bsf	TRISB,6		; SET the SCK to input for SLAVE MODE on TRISB 6								
                nop
                	
	;This is setting up the slave select line.
	banksel	ANSELH
	bcf	ANSELH,ANS8		; This is to set control of the Slave select line.
		
	banksel	TRISC				
;	bcf	TRISC,6		; Clears the bit so that the SS is output (This is for MASTER)
;	nop
	bsf	TRISC,6		; Sets the bit so that the SS is input (this is for SLAVE)
	nop
                return
;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; DriveRightForward Routine
; Puts the value of the second byte received (PWM_byte) into the CCPR1L register to create a PWM signal
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
DriveRightForward:
                BANKSEL         PORTC
                BCF             PORTC, 4                        ; make port C4 lo
                BANKSEL         CCPR1L
                movf            PWM_byte,W                      ; write PWM of DC 50%
                MOVWF           CCPR1L
                RETURN
;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; LightLEDs Routine
; Will light the iButton Sync LED, Red Base active LED, or Blue Base active LED depending on the values in the third
; byte received (Special_byte)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
LightLEDs:
                banksel         PORTC                 
                banksel         Special_byte                    ; else handle the LED lighting event
                btfsc           Special_byte,3
                call            iButtonSyncLight
                btfsc           Special_byte,4
                call            RedBaseLight
                btfsc           Special_byte,5
                call            BlueBaseLight
                return

DontLight:
                return

iButtonSyncLight:
                banksel         PORTC
                bsf             PORTC, 2                        ; raise C2 (iButton Sync light) to indicate that a sync has occured)
                return

RedBaseLight:
                banksel         PORTC
                bsf             PORTC,0                         ; raise C0 (Red LED) to indicate that the Red base is active
                bcf             PORTC,1                         ; lower C1 (Blue LED) because the Blue base is not active
                return

BlueBaseLight:
                banksel         PORTC
                bsf             PORTC,1                         ; raise C1 (Blue LED) to indicate that the Blue base is active
                bcf             PORTC,0                         ; lower C0 (Red LED) because the Red base is not active
                return
;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Interrupt Service Routine for PWM
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
InterruptServiceRoutine:
Push:
                MOVWF           W_TEMP                          ; Copy W to TEMP register
                SWAPF           STATUS, W                       ; Swap status to be saved into W
                MOVWF           STATUS_TEMP                     ; Save status to STATUS_TEMP register
;               First, test for the cause of the interrupt
InterrruptSourceTest:
                banksel         PIR1
                btfsc           PIR1,SSPIF                      ; test to see if a receive has occured
                goto            HandleReceive                   ; if SSPIF = 1, TX/RX is complete
                goto            HandlePWM                       ; else, a PWM interrupt occurred
HandleReceive:
;               Handle the receive interrupt
                banksel         PIR1
                bcf             PIR1,SSPIF                      ; clear the receive flag
                banksel         byte_count
                movlw           0x00            
                xorwf           byte_count,W
                btfsc           STATUS,Z                        ; if Z = 1, then byte_count = 0
                goto            FirstByte
                movlw           0x01
                xorwf           byte_count,W
                btfsc           STATUS,Z                        ; if Z = 1, then byte_count = 1
                goto            SecondByte
                goto            ThirdByte
FirstByte:
                banksel         SSPBUF
                movf            SSPBUF,W
                movwf           temp_received                   ; the contents of SSPBUF are now stored in W
                movlw           RIGHT_HEADER_BYTE
                xorwf           temp_received,W                 ; see if Byte 1 is actually the header
                banksel         byte_count
                btfss           STATUS,Z                        ; if Z = 1, then Byte 1 is the header
                goto            ClearByteCount                  ; if Z = 0 then Byte 1 is not the header and we need to reset
                banksel         byte_count                      ; else, increment byte_count and exit
                incf            byte_count                      ; increment byte_count to = 1
                goto            Pop
SecondByte:
                banksel         SSPBUF
                movf            SSPBUF,W
                movwf           PWM_byte                        ; move the contents of Byte 2 into PWM_BYTE
                banksel         byte_count                      ; else, increment byte_count and exit
                incf            byte_count                      ; increment byte_count to = 2
                goto            Pop
ThirdByte:
                banksel         SSPBUF
                movf            SSPBUF,W
                movwf           Special_byte                    ; move the contents of Byte 2 into PWM_BYTE
                banksel         byte_count
                incf            byte_count                      ; increment byte_count to = 3
                goto            Pop  

ClearByteCount:
                banksel         byte_count
                clrf            byte_count                      ; reset byte_count for next packet
                goto            Pop                               
HandlePWM:
;               Handle the PWM timer overflow interrupt                
PWM_Period:
                BCF             PIR1, TMR2IF                    ; update this PWM period and the following Duty Cycle

Pop:
                SWAPF           STATUS_TEMP, W                  ; swap nibbles in STATUS_TEMp register and place result in 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 into W_TEMP
                SWAPF           W_TEMP, W                       ; Swap nibbles in W_TEMP and place result into W
                RETFIE                                          ; return from interrupt, keep fingers crossed that this actually works!
;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;  
                END