;/*******************************************************************
;/ Steven Kosmerchock
;/ Phoenix, Az  USA
;/ www.geocities.com/researchtriangle/lab/6584
;/-------------------------------------------------------------------
;/ ***** Project Description: *****
;/ Uses a MICROCHIP PIC16F84 running at 4MHz to control the ignition of a model
;/ rocket "igniter" used for engines and parachute packs. Has a user 
;/ selectable delay of 1 second to 15 seconds. Designed to run off of a
;/ single 9V battery. Uses a MICROCHIP TC4422 to control the voltage and
;/ current to the "igniter". There are two "fail safe" ports. RB0 and RB1
;/ must both be active before timer begins.
;/-------------------------------------------------------------------
;/ ***** PORT DEFINITIONS *****
;/ RA0:	HIGH=1 SECOND
;/ RA1:	HIGH=2 SECONDS
;/ RA2:	HIGH=4 SECONDS
;/ RA3:	HIGH=8 SECONDS
;/-------------------------------------------------------------------
;/ Assembly file:	r_timer.asm
;/ Project file:	r_timer.pjt
;/ HEX file:		r_timer.hex
;--------------------------------------------------------------------
;
	errorlevel	-302	;IGNORE BANK SWITCHING "WARNING".
	errorlevel	-216	;RADIX "WARNING".
	errorlevel	-313	;Ignore "CBLOCK" WARNING.
;
	list p=16f84
;
	include "p16f84.inc"
;
	radix	hex
;
;--------------------------------------------------------------------
rp0	equ	5		;"RP0" bit in STATUS register.
z_flag	equ	2		;"Z" FLAG in STATUS register. Used to see if last 
;				 operation's result was 0.
w	equ	0		;"W" register is declared as 0.
f	equ	1		;"F" register is declared as 1.
;						
;--------------------------------------------------------------------
status	equ	0x03		;STATUS equate.
porta	equ	0x05		;PORTA equate.
portb	equ	0x06		;PORTB equate.
trisa	equ	0x85		;PORTA "DATA DIRECTION REGISTER".
trisb	equ	0x86		;PORTB "DATA DIRECTION REGISTER".
sec_count	equ	0x0C		;SRAM, holds number of seconds to delay.
temp_a	equ	0x0D		;PORTA shadow register.
d1	equ	0x0E
d2	equ	0x0F
d3	equ	0x10
;--------------------------------------------------------------------
;
	__CONFIG	_XT_OSC & _CP_ON & _WDT_OFF & _PWRTE_ON
;
; Start at the reset vector
	org	0x000
	goto	main
;-------------------------------------------------------------------- 
;/Routine that initializes PIC's I/O pins.
;
init_pic:
	nop
	bsf	status,rp0	;Set "RP0" for BANK1.
	nop
	movlw	0xff
	movwf	trisa		;PORTA all INPUTS.
	movlw	b'01111111'		
	movwf	trisb		;RB7 is OUTPUT, rest are INPUTS.
	nop
	bcf	status,rp0	;Clear "RP0" for BANK0.
	bsf	portb,7		;Set IGNITER ENABLE HIGH (DISABLED).
	nop
	clrf	sec_count	;Initial state of seconds counter is 0.
	return
;
;--------------------------------------------------------------------
;/ Routine that tests PORTA to decide what dip switches are set. Default 
;/ time with all dipwitches OFF is 1 SECOND!
time_set:
	nop
	bcf	status,z_flag	;Clear "ZERO" flag.
;
;/ ALL dip switches OFF test.
;
	movf	porta,w
	xorlw	0x00		;XOR "W" (0x00) with "TEMP_A", if "Z" = 1, they match.
	btfsc	status,z_flag	;Test "Z" flag, if 1 "TEMP_A" was 0x00.
	goto	one_sec		;"Z" flag 1, delay 1 second.
	nop
;
;/ Dip switches set for 1 second?
;
	movf	porta,w
	xorlw	0x01		;XOR "W" (0x01) with "TEMP_A", if "Z" = 1, they match.
	btfsc	status,z_flag	;Test "Z" flag, if 1 "TEMP_A" was 0x01.
	goto	one_sec		;"Z" flag 1, delay 1 second.
	nop
;
;/ Dip switches set for 2 seconds?
;
	movf	porta,w
	xorlw	0x02		;XOR "W" (0x02) with "TEMP_A", if "Z" = 1, they match.
	btfsc	status,z_flag	;Test "Z" flag, if 1 "TEMP_A" was 0x02.
	goto	two_secs	;"Z" flag 1, delay 2 seconds.
	nop
;
;/ Dip switches set for 3 seconds?
;
	movf	porta,w
	xorlw	0x03		;XOR "W" (0x03) with "TEMP_A", if "Z" = 1, they match.
	btfsc	status,z_flag	;Test "Z" flag, if 1 "TEMP_A" was 0x03.
	goto	three_secs	;"Z" flag 1, delay 3 seconds.
	nop	
;
;/ Dip switches set for 4 seconds?
;
	movf	porta,w
	xorlw	0x04		;XOR "W" (0x04) with "TEMP_A", if "Z" = 1, they match.
	btfsc	status,z_flag	;Test "Z" flag, if 1 "TEMP_A" was 0x04.
	goto	four_secs	;"Z" flag 1, delay 4 seconds.
	nop
;
;/ Dip switches set for 5 seconds?
;
	movf	porta,w
	xorlw	0x05		;XOR "W" (0x05) with "TEMP_A", if "Z" = 1, they match.
	btfsc	status,z_flag	;Test "Z" flag, if 1 "TEMP_A" was 0x05.
	goto	five_secs	;"Z" flag 1, delay 5 seconds.
	nop
;
;/ Dip switches set for 6 seconds?
;
	movf	porta,w
	xorlw	0x06		;XOR "W" (0x06) with "TEMP_A", if "Z" = 1, they match.
	btfsc	status,z_flag	;Test "Z" flag, if 1 "TEMP_A" was 0x06.
	goto	six_secs	;"Z" flag 1, delay 6 seconds.
	nop
;
;/ Dip switches set for 7 seconds?
;
	movf	porta,w
	xorlw	0x07		;XOR "W" (0x07) with "TEMP_A", if "Z" = 1, they match.
	btfsc	status,z_flag	;Test "Z" flag, if 1 "TEMP_A" was 0x07.
	goto	seven_secs	;"Z" flag 1, delay 7 seconds.
	nop
;
;/ Dip switches set for 8 seconds?
;
	movf	porta,w
	xorlw	0x08		;XOR "W" (0x08) with "TEMP_A", if "Z" = 1, they match.
	btfsc	status,z_flag	;Test "Z" flag, if 1 "TEMP_A" was 0x08.
	goto	eight_secs	;"Z" flag 1, delay 8 seconds.
	nop
;
;/ Dip switches set for 9 seconds?
;
	movf	porta,w
	xorlw	0x09		;XOR "W" (0x09) with "TEMP_A", if "Z" = 1, they match.
	btfsc	status,z_flag	;Test "Z" flag, if 1 "TEMP_A" was 0x09.
	goto	nine_secs	;"Z" flag 1, delay 9 seconds.
	nop
;
;/ Dip switches set for 10 seconds?
;
	movf	porta,w
	xorlw	0x0A		;XOR "W" (0x0A) with "TEMP_A", if "Z" = 1, they match.
	btfsc	status,z_flag	;Test "Z" flag, if 1 "TEMP_A" was 0x0A.
	goto	ten_secs	;"Z" flag 1, delay 10 seconds.
	nop
;
;/ Dip switches set for 11 seconds?
;
	movf	porta,w
	xorlw	0x0B		;XOR "W" (0x0B) with "TEMP_A", if "Z" = 1, they match.
	btfsc	status,z_flag	;Test "Z" flag, if 1 "TEMP_A" was 0x0B.
	goto	eleven_secs	;"Z" flag 1, delay 11 seconds.
	nop
;
;/ Dip switches set for 12 seconds?
;
	movf	porta,w
	xorlw	0x0C		;XOR "W" (0x0C) with "TEMP_A", if "Z" = 1, they match.
	btfsc	status,z_flag	;Test "Z" flag, if 1 "TEMP_A" was 0x0C.
	goto	twelve_secs	;"Z" flag 1, delay 12 seconds.
	nop
;
;/ Dip switches set for 13 seconds?
;
	movf	porta,w
	xorlw	0x0D		;XOR "W" (0x0D) with "TEMP_A", if "Z" = 1, they match.
	btfsc	status,z_flag	;Test "Z" flag, if 1 "TEMP_A" was 0x0D.
	goto	thirteen_secs	;"Z" flag 1, delay 13 seconds.
	nop
;
;/ Dip switches set for 14 seconds?
;
	movf	porta,w
	xorlw	0x0E		;XOR "W" (0x0E) with "TEMP_A", if "Z" = 1, they match.
	btfsc	status,z_flag	;Test "Z" flag, if 1 "TEMP_A" was 0x0E.
	goto	fourteen_secs	;"Z" flag 1, delay 14 seconds.
	nop
	goto	fifteen_secs	;ALL switches set. Delay will be 15 seconds long (MAX).
;
;--------------------------------------------------------------------
;/ Sets up "sec_count" register with 0x01. "sec_delay" will be called once.
; 
one_sec:
	nop
	movlw	0x01		;Load "sec_count" with 0x01, delay equals 1s.
	movwf	sec_count
	nop
	return
;--------------------------------------------------------------------
;/ Sets up "sec_count" register with 0x02. "sec_delay" will be called twice.
; 
two_secs:
	nop
	movlw	0x02		;Load "sec_count" with 0x02, delay equals 2s.
	movwf	sec_count
	nop
	return
;--------------------------------------------------------------------
;/ Sets up "sec_count" register with 0x03. "sec_delay" will be called three times.
; 
three_secs:
	nop
	movlw	0x03		;Load "sec_count" with 0x03, delay equals 3s.
	movwf	sec_count
	nop
	return
;--------------------------------------------------------------------
;/ Sets up "sec_count" register with 0x04. "sec_delay" will be called four times.
; 
four_secs:
	nop
	movlw	0x04		;Load "sec_count" with 0x04, delay equals 4s.
	movwf	sec_count
	nop
	return
;--------------------------------------------------------------------
;/ Sets up "sec_count" register with 0x05. "sec_delay" will be called five times.
; 
five_secs:
	nop
	movlw	0x05		;Load "sec_count" with 0x05, delay equals 5s.
	movwf	sec_count
	nop
	return
;--------------------------------------------------------------------
;/ Sets up "sec_count" register with 0x06. "sec_delay" will be called six times.
; 
six_secs:
	nop
	movlw	0x06		;Load "sec_count" with 0x06, delay equals 6s.
	movwf	sec_count
	nop
	return
;--------------------------------------------------------------------
;/ Sets up "sec_count" register with 0x07. "sec_delay" will be called seven times.
; 
seven_secs:
	nop
	movlw	0x07		;Load "sec_count" with 0x07, delay equals 7s.
	movwf	sec_count
	nop
	return
;--------------------------------------------------------------------
;/ Sets up "sec_count" register with 0x08. "sec_delay" will be called eight times.
; 
eight_secs:
	nop
	movlw	0x08		;Load "sec_count" with 0x08, delay equals 8s.
	movwf	sec_count
	nop
	return
;--------------------------------------------------------------------
;/ Sets up "sec_count" register with 0x09. "sec_delay" will be called nine times.
; 
nine_secs:
	nop
	movlw	0x09		;Load "sec_count" with 0x09, delay equals 9s.
	movwf	sec_count
	nop
	return
;--------------------------------------------------------------------
;/ Sets up "sec_count" register with 0x0A. "sec_delay" will be called ten times.
; 
ten_secs:
	nop
	movlw	0x0A		;Load "sec_count" with 0x0A, delay equals 10s.
	movwf	sec_count
	nop
	return
;--------------------------------------------------------------------
;/ Sets up "sec_count" register with 0x0B. "sec_delay" will be called eleven times.
; 
eleven_secs:
	nop
	movlw	0x0B		;Load "sec_count" with 0x0B, delay equals 11s.
	movwf	sec_count
	nop
	return
;--------------------------------------------------------------------
;/ Sets up "sec_count" register with 0x0C. "sec_delay" will be called twelve times.
; 
twelve_secs:
	nop
	movlw	0x0C		;Load "sec_count" with 0x0C, delay equals 12s.
	movwf	sec_count
	nop
	return
;--------------------------------------------------------------------
;/ Sets up "sec_count" register with 0x0D. "sec_delay" will be called thirteen times.
; 
thirteen_secs:
	nop
	movlw	0x0D		;Load "sec_count" with 0x0D, delay equals 13s.
	movwf	sec_count
	nop
	return
;--------------------------------------------------------------------
;/ Sets up "sec_count" register with 0x0E. "sec_delay" will be called fourteen times.
; 
fourteen_secs:
	nop
	movlw	0x0E		;Load "sec_count" with 0x0E, delay equals 14s.
	movwf	sec_count
	nop
	return
;--------------------------------------------------------------------
;/ Sets up "sec_count" register with 0x0F. "sec_delay" will be called fifteen times.
; 
fifteen_secs:
	nop
	movlw	0x0F		;Load "sec_count" with 0x0F, delay equals 15s.
	movwf	sec_count
	nop
	return
;--------------------------------------------------------------------
;/ Routine that gets variable from "sec_count" and uses it to control
;/ the amount of times "sec_delay" is called.
;
start_delay:
	call	sec_delay	;Do a 1 second delay.
	decfsz	sec_count,f	;Decrement "sec_count", result in "sec_count".
	goto	start_delay	;"sec_count" != 0, delay 1 second longer.
	nop
	return
;
;--------------------------------------------------------------------
;/ Routine that delays for 1 second.
;/ Created by delay generator: www.piclist.com
;
sec_delay:	
	movlw	0x07
	movwf	d1
	movlw	0x2F
	movwf	d2
	movlw	0x03
	movwf	d3
delay_loop:
	decfsz	d1,f
	goto	$+2
	decfsz	d2,f
	goto	$+2
	decfsz	d3,f
	goto	delay_loop
;
	goto	$+1
	goto	$+1
	goto	$+1
;
	return
;--------------------------------------------------------------------
;/ "RB0" FAILSAFE Check routine.
;/ "PRIMARY" FAILSAFE: Used for transport and setting up of rocket.
;/ Keeps testing "RB0" until it has been disabled (OPEN). After it has been
;/ open, tests secondary failsafe before delay begins.
;
primary_failsafe:
	nop
	btfss	portb,0		;Test to see if RB0 is LOW (ENABLED).
	goto	primary_failsafe	;Still ENABLED, keep testing.
	nop
	return
;--------------------------------------------------------------------
;/"RB1" FAILSAFE Check routine.
;/ "SECONDARY" FAILSAFE: Used after rocket has taken off, if disabled, delay starts.
;/ At end of delay, igniter is activated to discharge parachute or second stage of rocket.
;
secondary_failsafe:
	nop
	btfsc	portb,1		;Test to see if RB1 is HIGH (ENABLED).
	goto	secondary_failsafe	;Still ENABLED, keep testing.
	nop
	return
;--------------------------------------------------------------------
;/ Routine to charge "IGNITER".
;
ignite:
	nop
	bcf	portb,7		;ENABLE IGNITER>
	nop
	return
;
;--------------------------------------------------------------------
;/Beginning of program. All functions are called from here.
;
main:
	call	init_pic	;Routine to initialize PIC I/O.
	call	time_set	;Test state of switches (delay selected).
	call	primary_failsafe	;Check to see if user has removed "FAILSAFE".
	call	secondary_failsafe	;Check to see rocket has been launched.
	call	start_delay		;Begin user defined delay.
	call	ignite			;Ignite charge.
loop	nop
	goto	loop			;Continous loop.
;
;--------------------------------------------------------------------
	end


