;;;;;;; P3 for QwikFlash board ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
; Name: Shane Connelly
; Name: Grant Lohsen
; Handle: WSCL
;
; PIC18F452's internal clock period is 0.4 microseconds.
; Use Timer2 for a loop time of approximately ten milliseconds (see Figure 16-3)
; with A=16, B=223, C=7 for 24976 internal clock cycles = 9990.4 microseconds.
; Toggle B0 output every ten milliseconds for measuring looptime with scope.
; Step stepper motor at a rate of 100 steps per second.
; Blink "Alive" LED every two seconds.
; Also, the code reads the value of the potentiometer every 1 second and sends it
; to the computer as an integer value from 0 to 8.
; After it reads the potentiometer, it sets the stepper motor to step n times per
; second where n = 12 * (the potentiometer value from 0-8).
;
;;;;;;; Program hierarchy ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Mainline
;   Initial
;   PotDisplay
;     ReadPot
;     TXbyte
;     RateDisplay
;       FXD0808U
;       TXbyte
;   ControlStepping
;   BlinkAlive
;   LoopTime
;
;;;;;;; Assembler directives ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

        list  P=PIC18F452, F=INHX32, C=160, N=0, ST=OFF, MM=OFF, R=DEC, X=ON
        #include P18F452.inc
        __CONFIG  _CONFIG1H, _HS_OSC_1H  ;HS oscillator
        __CONFIG  _CONFIG2L, _PWRT_ON_2L & _BOR_ON_2L & _BORV_42_2L  ;Reset
        __CONFIG  _CONFIG2H, _WDT_OFF_2H  ;Watchdog timer disabled
        __CONFIG  _CONFIG3H, _CCP2MX_ON_3H  ;CCP2 to RC1 (rather than to RB3)
        __CONFIG  _CONFIG4L, _LVP_OFF_4L  ;RB5 enabled for I/O

;;;;;;; Variables ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

        cblock  0x000           ;Beginning of Access RAM
        ALIVECNT                ;Counter for blinking "Alive" LED
        HUNDRED                 ;Counter for reading the potentiometer value
        POTVALUE                ;Holds the raw potentiometer value
        SMALLPOT                ;Holds the scaled value of the potentiometer
        STEPRATE                ;The rate in steps/second of the stepper motor
        ACCUM                   ;The accumulator for the motor
        endc
        
        #include <C:\MATH18\MATHVARS.inc>

;;;;;;; Macro definitions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

MOVLF   macro  literal,dest
        movlw  literal
        movwf  dest
        endm

;;;;;;; Vectors ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

        org  0x0000             ;Reset vector
        goto  Mainline

        org  0x0008             ;High priority interrupt vector
        goto  $                 ;Trap

        org  0x0018             ;Low priority interrupt vector
        goto  $                 ;Trap

;;;;;;; Mainline program ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Mainline
        call  Initial           ;Initialize everything
        LOOP_
          btg  PORTB,RB0        ;Toggle pin, to support measuring loop time
          bsf PORTC, RC2        ;Toggle pin to support measuring useful function time
          call  PotDisplay      ;run the potentiometer read and display functions
          call  ControlStepping  ;control the motor step rate
          call  BlinkAlive      ;Blink "Alive" LED
          bcf PORTC, RC2        ;set the pin low to end timing
          call  LoopTime        ;Wait for ten milliseconds to be up
        ENDLOOP_

;;;;;;; Initial subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; This subroutine performs all initializations of variables and registers.

Initial
        MOVLF  B'01001110',ADCON1  ;Enable PORTA & PORTE digital I/O pins
        MOVLF  B'01100001',ADCON0  ;Select pot input to ADC
        MOVLF  B'11100001',TRISA  ;Set I/O for PORTA
        MOVLF  B'11001100',TRISB  ;Set I/O for PORTB
        MOVLF  B'11010000',TRISC  ;Set I/O for PORTC
        MOVLF  B'00001111',TRISD  ;Set I/O for PORTD
        MOVLF  B'00000100',TRISE  ;Set I/O for PORTE
        MOVLF  B'00010000',PORTA  ;Turn off all four LEDs driven from PORTA
        bsf  PORTB,RB5          ;Step direction is CW
        MOVLF  B'10110111',T2CON  ;Set up Timer2 (10 millisecond looptime)
        MOVLF  222, PR2
        MOVLF 200,ALIVECNT      ;set the time/loop
        MOVLF 100,HUNDRED       ;set the time/loop
        return


;;;;;;; PotDisplay subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; This subroutine briefly displays a range between 0 and 8 of the Potentiometer.

PotDisplay
        decf  HUNDRED,F         ;Decrement hundred loop counter and return if not zero
        IF_ .Z.
          MOVLF  100,HUNDRED    ;Reinitialize BLNKCNT
          call ReadPot          ;sends the potentiometers value to the ADC
          movff ADRESH, POTVALUE  ;sends the ADC value to POTVALUE
          movf POTVALUE,W       ;copies potvalue to the wreg
          mullw 9               ;multiplies potvalue(in wreg) by 9
          movff PRODH, SMALLPOT  ;get the upper byte and store it in smallpot
          
          movf SMALLPOT, W      ; multiply the potentiometer value by 12 to generate the 
          mullw 12              ; motor stepping rate between 0 and 96 (in steps/second)
          movff PRODL, STEPRATE  ;save the stepping rate in variable STEPRATE
          
          movlw 0x0d            ;sends 0x0d to the wreg for ascii conversion
          call TXbyte           ;transmits wreg to the Computer
          movlw 0x30            ;sends 0x30 to the wreg for ascii conversion
          addwf SMALLPOT,W      ;converts the value to ascii
          call TXbyte           ;transmits wreg to the computer
          
          call RateDisplay      ;Show the motor rate on the computer
        ENDIF_
        return
        
;;;;;;; ReadPot subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; This subroutine reads the potentiometer and puts the upper byte into ADRESH

ReadPot
        bsf ADCON0,GO_DONE      ;initiate Conversation
        REPEAT_
        UNTIL_  ADCON0,GO_DONE == 0  ;wait for completion of conversion
        return                  ;return with result in ADRESH
        
;;;;;;; RateDisplay subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; This subroutine sends the value of the variable STEPRATE to the computer as ASCII digits

RateDisplay
        movlw 10                ;We need to divide 10 from the STEPRATE to produce
                                ;an ASCII value to transmit
        movwf BARGB0            ;Store 10 in the B argument of divide (A/B)
        movff STEPRATE, AARGB0  ;Store the step rate in the value of A for the divide
        call FXD0808U           ;Perform the division function
        movlw 0x0d              ;This sends the loads the carriage return value
        call TXbyte             ;And send it to the computer
        movlw 0x30              ;Load an ASCII adjuster
        addwf AARGB0, W         ;To add to the integer result of the division
        call TXbyte             ;Send this ASCII value to the computer
        movlw 0x30              ;Load an ASCII adjuster
        addwf REMB0, W          ;To add to the remainder of the division
        call TXbyte             ;Send this ASCII value to the computer
        return
        
;;;;;;; TXbyte subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; This subroutine first waits on the UART if a byte is in the process of being
; sent.  Then it sends the content of WREG to the PC.

TXbyte
        REPEAT_                 ;If an earlier transmission is still
        UNTIL_ PIR1,TXIF == 1   ;in progress then wait
        movwf TXREG             ;send new byte from wreg
        return	

;;;;;;; ControlStepping subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; This subroutine steps the stepper motor in accordance to the STEPRATE variable

ControlStepping
        movf STEPRATE, W        ;Add STEPRATE into the step motor accumulator
        addwf ACCUM, F
        IF_ .C.                 ;If there is an overflow from the accumulator then...
          btg PORTB,RB1         ;Toggle RB1 for motor time measurement
          bsf  PORTB,RB4        ;Set the stepper motor movement
          bcf  PORTB,RB4        ;Clear the stepper motor movement
          movlw 100             ;Move 100 into WREG for subtraction
          subwf ACCUM,F           ;Subtract 100 to drop the counter down from the overflow
        ENDIF_
        return
        
;;;;;;; BlinkAlive subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; This subroutine briefly blinks the LED next to the PIC every two seconds.

BlinkAlive
        bsf  PORTA,RA4          ;Turn off LED
        decf  ALIVECNT,F        ;Decrement loop counter and return if not zero
        IF_ .Z.
          MOVLF  200,ALIVECNT   ;Reinitialize BLNKCNT
          bcf  PORTA,RA4        ;Turn on LED for ten milliseconds every 2 sec
        ENDIF_
        return
        

;;;;;;; LoopTime subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; When Timer2 rolls over and sets the TMR2IF flag, approximately ten
; milliseconds have passed since the last time the flag was set.  The flag
; is cleared and execution returns from the subroutine to the mainline loop.

LoopTime
        REPEAT_
        UNTIL_  PIR1,TMR2IF == 1  ;Wait for completion of ten milliseconds
        bcf  PIR1,TMR2IF        ;Clear flag
        return  

        #include <C:\MATH18\FXD0808U.inc>
        end
        




