;**********************************************************************
;                                                                     *
;    Filename:      Pulser.asm                                        *
;    Date:          30.04.11                                          *
;    File Version:                                                    *
;                                                                     *
;    Author:        Káró György                                       *
;                                                                     *
;**********************************************************************
;                                                                     *
;    Files required:                                                  *
;                   12F675i.lkr                                       *
;                   P12F675.inc                                       *
;                                                                     *
;**********************************************************************
;                                                                     *
;    Notes:                                                           *
;           A quick and dirty program.  Reads pot connected to AN0.   *
;           A TMR1 interrupt occurs every 0.5 seconds.                *
;           When the number of TMR1 rollovers >= the A/D result, a    *
;           relay will be turned on for a 0.5 second pulse.           *
;                                                                     *
;**********************************************************************

	list      p=12f675          ; list directive to define processor
	#include <p12f675.inc>      ; processor specific variable definitions
    
    radix   dec
    
	errorlevel  -302            ; suppress message 302 from list file

	__CONFIG   _CP_OFF & _CPD_OFF & _BODEN_OFF & _MCLRE_ON & _WDT_OFF & _PWRTE_ON & _INTRC_OSC_CLKOUT  

; pin definitions
;       GP0 - Analog input from wiper of 5k pot.  Sets delay time between 0.5 second relay pulses.
;       GP1 - Not used.
;       GP2 - Drives 4N32 optoisolator thru 200 ohm resistor.  4N32 then drives relay output.  Delays between 0.5 second relay pulses are set by pot.
;       GP3 - Reset button between ground and MCLR.  MCLR tied high via 10k resister.
;       GP4 - Fosc/4 clockout for debug purposes.
;       GP5 - Drives an LED on a clock tick.  Visual indication that program is working.


; #defines
    #define pot         GPIO, GP0
    #define relay       GPIO, GP2
    #define aliveLED    GPIO, GP5

; Shared Uninitialized Data Section
INT_VAR     UDATA_SHR   0x20   
w_temp      RES     1       ; variable used for context saving 
status_temp	RES     1       ; variable used for context saving

rollcntL    RES     1       ; low byte of TMR1 rollovers
rollcntH    RES     1       ; high byte of TMR1 rollovers

rollflag    RES     1       ; bit 0 = TMR1 rollover flag for main loop to poll 


;**********************************************************************
RESET_VECTOR    CODE    0x000   ; processor reset vector
		goto    main            ; go to beginning of program

INT_VECTOR      CODE    0x004   ; interrupt vector location
		movwf   w_temp          ; save off current W register contents
		movf    STATUS,w        ; move status register into W register
		movwf   status_temp     ; save off contents of STATUS register
        
 ; check for TMR1 rollover
        banksel PIR1
        btfss   PIR1, TMR1IF    ; TMR1 rollover?
        goto    nextIRQ
        movlw   0xBD            ; reload TMR1
        banksel TMR1L
        movwf   TMR1L
        movlw   0xB
        banksel TMR1H
        movwf   TMR1H
        
        banksel GPIO
        bcf     relay           ; turn off relay
        
        banksel GPIO
        movlw   b'00100000'     ; toggle aliveLED for visual indication     
        xorwf   GPIO, f
                
        banksel rollflag
        bsf     rollflag, 0     ; set roll-over flag for main loop to poll
        
        banksel PIR1
        bcf     PIR1, TMR1IF    ; clear interrupt flag
    
nextIRQ
		movf    status_temp,w   ; retrieve copy of STATUS register
		movwf	STATUS          ; restore pre-isr STATUS register contents
		swapf   w_temp,f
		swapf   w_temp,w        ; restore pre-isr W register contents
		retfie                  ; return from interrupt


; Main Code
main
		call    0x3FF           ; retrieve factory calibration value
		banksel OSCCAL
		movwf   OSCCAL          ; update register with factory cal value 

; initialize variables
        banksel rollcntL
        clrf    rollcntL
        banksel rollcntH
        clrf    rollcntH
        banksel rollflag
        clrf    rollflag

; set up direction of I/O pins
        banksel TRISIO
        movlw   b'00000001'
        ;         xx------  not implemented
        ;         --0-----  0=output, GP5, Drives an LED on a clock tick.  Visual indication that program is working.
        ;         ---0----  0=output, GP4, Fosc/4 clockout for debug purposes
        ;         ----x---  not used, GP3, Dedicated to MCLR
        ;         -----0--  0=output, GP2, Optoisolator, relay driver
        ;         ------0-  0=output, GP1, not used (output defective)
        ;         -------1  1=input, GP0, analog input
        movwf   TRISIO

; set up comparator
        banksel CMCON
        movlw   b'00000111'
        ;         x-------  not implemented
        ;         -0------  output bit
        ;         --x-----  not implemented
        ;         ---0----  0=non-inverted output
        ;         ----0---  0=Vin- to Cin-
        ;         -----111  111=comparator off
        movwf   CMCON

; set up A/D converter
        banksel ANSEL
        movlw   b'00010001'
        ;         x-------  not implemented
        ;         -001----  001=Focs/8 Conversion Clock
        ;         ----0---  0=digital I/O, GP4, Fosc/4 clockout for debug purposes.
        ;         -----0--  0=digital I/O, GP2, Optoisolator, relay driver
        ;         ------0-  0=digital I/O, GP1, not used
        ;         -------1  1=analog  I/O, GP0, analog input
        movwf   ANSEL
        
        banksel ADCON0
        movlw   b'10000001'
        ;         1-------  1=right justified result
        ;         -0------  0=Vdd is voltage reference
        ;         --xx----  not implemented
        ;         ----00--  00=select channel 0 (GP0)
        ;         ------0-  0=A/D conversion not started
        ;         -------1  1=A/D converter module is operating
        movwf   ADCON0

; initialize output pins
init
        banksel GPIO
        movlw   b'00000000'
        movwf   GPIO
                
; initialize interrupts
        banksel INTCON
        movlw   b'01000000'
        ;         0-------  0=interrupts disabled
        ;         -1------  1=enable peripheral interrupts
        ;         --0-----  0=disable TMR0 overflow interrupt
        ;         ---0----  0=disable GP2/INT external interrupt
        ;         ----0---  0=disable GPIO port change interrupt
        ;         -----0--  0=no on TMR0 overflow
        ;         ------0-  0=no GP2/INT external interrupt
        ;         -------0  0=no GPIO port change
        movwf   INTCON
    
        banksel PIE1    
        movlw   b'00000001'
        ;         0-------  0=disable EE write complete interrupt
        ;         -0------  0=disable A/D converter interrupt
        ;         --xx----  not implemented
        ;         ----0---  0=comparator interrupt disabled
        ;         -----xx-  not implemented
        ;         -------1  1=enable TMR1 overflow interrupt
        movwf   PIE1
        
        banksel PIR1
        movlw   b'00000000'
        ;         0------- 0=no EE write complete
        ;         -0------ 0=no A/D conversion complete
        ;         --xx---- not implemented
        ;         ----0--- 0=no comparator interrupt
        ;         -----xx- not implemented
        ;         -------0 0=no TMR1 overflow
        movwf   PIR1

; initialize TMR1
        banksel T1CON
        movlw  b'00110101'    
        ;       x-------  not implemented
        ;       -0------  0=gate disabled
        ;       --11----  01=1:8 prescaler
        ;       ----0---  0=LP oscillator is off
        ;       -----1--  1=external clock input not synchronized
        ;       ------0-  0=internal clock
        ;       -------1  1=enable timer
        movwf   T1CON

    ; preload for 500ms rollover @ 4 MHZ internal oscillator
    ; Fosc/4 = 1 MHZ = 1 uS per clock
    ; 500000 clocks per 500 ms
    ; with 1:8 prescaler: 65535 - (500000/8) = 3035 = 0xBDB initial value
        banksel TMR1L
        movlw   0xDB
        movwf   TMR1L
        banksel TMR1H
        movlw   0xB
        movwf   TMR1H
        
        banksel INTCON
        bsf     INTCON, GIE     ; enable interrupts
        
; Main Loop
forever        
        banksel ADCON0      
        bsf     ADCON0, GO      ; start A/D conversion
        btfsc   ADCON0, NOT_DONE
        goto    $-1
        
        banksel rollflag
        btfsc   rollflag, 0     ; TMR1 rollover?
        call    compare
        
        goto    forever

; Compare subroutine - Test rollover counter to see if it >= the A/D result.
; If it is we turn on the relay.
compare        
        banksel rollflag
        bcf     rollflag, 0     ; reset ISR rollover flag
          
    ; increment number of rollovers
        banksel rollcntL
        incf    rollcntL, f     ; number of rollovers
        btfsc   STATUS, Z       ; more than 255 rollovers?               
        incf    rollcntH, f     ; yes, increment high byte of rollover counter    
            
    ; compare to see if rollover counter is >= A/D result (16 bit unsigned comparision)
        banksel ADRESH
        movfw   ADRESH
        banksel rollcntH
        subwf   rollcntH, w     ; w = rollcntH - ADRESH
        btfss   STATUS, C       ; if rollcntH >= ADRESH, C=1
        return
        btfss   STATUS, Z       ; if rollcntH = ADRESH, C=1
        goto    relay_on
        banksel ADRESL
        movfw   ADRESL
        banksel rollcntL
        subwf   rollcntL, w     ; w = rollcntL - ADRESL
        btfss   STATUS, C       ; if rollcntL >= ADRESL, C=1
        return
        
    ; rollover counter >= A/D result
relay_on
        banksel rollcntL        ; reset roll-over counters
        clrf    rollcntL
        banksel rollcntH
        clrf    rollcntH
        
        banksel GPIO            ; turn on relay
        bsf     relay    
        return
                         

; initialize eeprom locations
EE		CODE	0x2100
		DE	0x00, 0x01, 0x02, 0x03


		END
