LUNAR’clips 2002                        Volume 9, Number 2

Livermore Unit of the National Association of Rocketry              March/April 2002

Copyright © 2002 by LUNAR, All rights reserved.

CODING FOR TIMER (assemble it using MPLAB)

;========================================================================
; Tmr_a7HC.asm
;       Parachute deployment timer, High Current Ignitor version
;       $Revision:    $ 
;       $author:        $
;	Copyright (C) Sutsoft, 1999
;************************************************************************
; Notes:
; version 7:
; Added code to detect inital application of a battery and immediately
;   fall asleep to prevent accidental battery drain if plugged in then
;   not used.  Also safer when wiring in flash bulbs.
; version 6:
; Added wait for no_cont or 5 seconds before sleeping uP after fire for
;   high current style ignitors instead of flash bulbs.
; Added s/w "stack" manager for 5 call deep stack implemented as a macro
;   Return routine done as a goto function to save code space.
; Optimized loop timing for 1 second (16 trips through the loop)
;   Sim shows 1 sec = 999.25ms
;========================================================================
;*** program equates ***
;port def's
tmr0		equ	0x01	; timer0 register
PC      	equ     0x02	; PCL reg
FSR     	equ     0x04	; indirection pointer
INDF            equ     0x00	; indirection data reg
PORTB		equ	0x06	;
PORTC		equ	0x07	;
STATUS		equ	0x03	;
;bit def's
Z		equ	0x02	; Z flag in STATUS reg
C		equ	0x00	; C flag in STATUS
DC		equ	0x01	; DC flag in STATUS
CONT    	equ     0x04    ; PORTB bit 2 (RB2)
FIRE		equ	0x02	; PORTB bit 1 (RB1)
GSWITCH		equ	0x00	; PORTB bit 0 (RB0)
;other def's
W       	equ     0x00    ; constants for results storage direction
F       	equ     0x01    ;       "       "       "       "
GREEN		equ	0x20	; port (bit) config for a GREEN LED
RED		equ	0x10	; port (bit) config for a RED LED
OFF		equ	0x00	; port (bit) config for no LED
DEAD_COUNT	equ	0x0A	; number of tries to wait for no_cont after firing
SECRET_SPOT	equ	0x17	; used to force a sleep when the battery is first
				; applied. Lives above the stack area
SECRET_NUMBER	equ	0xB2	; number to look for (10110010)
;========================================================================
;================= Important values...DO NOT CHANGE =====================
;========================================================================
TIMER_OFFSET	equ	0x0C	; 62.5 ms loop compensation

STACK_SIZE	equ	0x05	; s/w "stack" is 5 bytes deep
;========================================================================
;*** program variables ***
count		equ	0x08	; counter variable
swtch_count 	equ     0x09    ; holds switch count
g_status        equ     0x0A    ; holds the g-switch status
temp		equ	0x0B	; G/P temporary variable
fire_count	equ	0x0C	; dead-man loop counter
cont_stat	equ	0x0D	; holds status of continuity check
;==========================================================================
;       Operation Configuration Bits
;==========================================================================
_MCLRE_ON                    EQU     H'0FFF'
_MCLRE_OFF                   EQU     H'0FDF'
_CP_ON                       EQU     H'002F'
_CP_OFF                      EQU     H'0FFF'
_WDT_ON                      EQU     H'0FFF'
_WDT_OFF                     EQU     H'0FF7'
_LP_OSC                      EQU     H'0FF8'
_XT_OSC                      EQU     H'0FF9'
_HS_OSC                      EQU     H'0FFA'
; assign device type and configuration bits:
; It'a 16C505 w/ reset=on, code prot=OFF, xtern Osc, no WDT
	LIST P=16C505
	__config  _MCLRE_ON & _CP_OFF & _XT_OSC & _WDT_OFF
;==========================================================================
;  NCALL MACRO
; define NCALL as a MACRO used instead of the 
; mnemonic call.
;==========================================================================
NCALL   MACRO   LABEL   
        MOVF    PC,W    	; save PC on "stack"
        MOVWF   INDF       	;
        INCF    FSR, F  	; inc. "stack"  pointer.
        GOTO    LABEL   	; jump to routine
        ENDM
;========================================================================
;====================== start of executable code ========================
;========================================================================
        ORG     10		; put the stack out past the other 
				; program variables
STACK   RES     STACK_SIZE     	; define stack size = 5.

	org	0		; start execution at address zero

INIT_STACK:
	movlw   STACK   	; load "stack" as indirect pointer
        movwf   FSR     	; 
start:
	clrw			; clear W
	movlw	0xC7		; load W with option bytes (11000111)
	clrwdt			; clear WDT
	option			; load OPTION reg
; set up the ports
	movlw	0x0D		; load W with port B config
	tris	PORTB		; RB0=I, RB1=O, RB2=I, RB3=I
	movwf	PORTB		; all ports set to zero
	movlw	0x0F		; load W with port C configuration
        tris    PORTC           ; RC0 - RC3 are inputs (hex switch)
                                ; RC4 and RC5 are output (LED)
        clrw                    ; set RC4 & RC5 both to low
        movwf   PORTC           ; so that the LED is turned OFF
; check for initial power-up when battery is first connected.
; check SECRET_SPOT for a value of SECRET_NUMBER.  If not present, write the 
; value and go to sleep, otherwise fall through to main().
; This is here to prevent accidental battery drain if plugged in then not used.
; Also this is a safer mode in which to attach flash bulbs prior to arming.
	movlw	SECRET_NUMBER 	; load secret number to W
	subwf	SECRET_SPOT, W	; subtract value at secret spot
	btfss	STATUS, Z	; if Z bit is set, not the first power up
	goto	init_pwr	; if not set, write value and go to sleep
main:                      	;
	;read hex switch setting
        NCALL 	read_switch	; read HEX switch setting
	movf	swtch_count, F	; test for zero (this will set Z bit if 
				; swtch_count = 0)
	btfsc	STATUS, Z	; if zero, end program		
	goto	finish		
	;check flashbulb continuity
        NCALL 	check_cont	; check flash bulb continuity
	movf	cont_stat, F	; test for zero. zero = no_cont
        btfsc   STATUS, Z       ; if Z is set, there was no continuity
        goto    blink_bad       ; blink the LED, then go to sleep
	;count out switch setting
	NCALL	blink		; 
	;indicate armed status
        NCALL 	armed_light	; 
	;wait for launch signal
        NCALL 	g_switch	; 
timer_loop:
	NCALL 	one_sec		; loop for one second
	decf	swtch_count, F	; decrement main loop counter
	btfss	STATUS, Z	; check for zero flag
	goto	timer_loop	; loop until it is
				; else NCALL fire which
        goto	fire		; sets RB1 and waits until it's fired
finish:
	movlw	0x0		; reset FIRE (RB1)
	movwf	PORTB		; clear fire bit
        movlw   0xFF            ; set all ports to input
        tris    PORTB           ; to save power
        tris    PORTC           ; then 
        sleep                   ; goto sleep w/ no wake up's (we're done)
;========================================================================
;===== end of main loop code  ===========================================
;************************************************************************
;  one_sec()
; Counts for one second.
;************************************************************************
one_sec:			; sub routine
	movlw	0x04		; load count with 4 (count for 1 second)
	movwf	count		;	
	goto	o_loop		; start counting
;************************************************************************
;  quarter_sec()
; Counts for 1/4 second.
;************************************************************************
quarter_sec:
	movlw	0x01		; count for 1/4 sec
	movwf	count		;
	goto	o_loop		; start counting
;************************************************************************
;  half_sec()
; Counts for 1/2 second.
;************************************************************************
half_sec:
	movlw	0x02		; 1/2 second
	movwf	count		;
				; fall through to o_loop
o_loop:
	; loop timer. 4 NCALLs  == 1/4 second
	NCALL load_timer		;   62.5 ms
	NCALL load_timer		; + 62.5 ms
	NCALL load_timer		; + 62.5 ms
 	NCALL load_timer		; + 62.5 ms
				;===========
				;  250.0 ms 
	decf	count, 1	; decrement count
	btfsc	STATUS,	Z	; check zero flag
	goto	RTN		; if set, return
        goto    o_loop          ; else loop again
;************************************************************************
;  load_timer()
; Function loads tmr0 (timer0 reg) with an offset to calibrate to 62.5 ms
; count time, then pends on the Z flag waiting for the timer to roll over
; to zero. Returns nothing.
;************************************************************************
load_timer:			; sub routine
	movlw	TIMER_OFFSET	; timer offset
	movwf	tmr0		;
read_bit:			;
	movlw	0xFF		; set W
	andwf	tmr0, 0		; AND with timer0
	btfss	STATUS, Z	; test Z bit. If clear,
	goto	read_bit	; test again until it's set
	goto	RTN		; return
;************************************************************************
;  fire()
; Sets the RB1 bit to fire charge, then waits until there is no 
; continuity or 5 seconds has elapsed, which ever comes first.
;************************************************************************
fire:				; sub routine
	movlw	FIRE		; set bit 1 
	movwf	PORTB		; of PORTB (RB1)
	movlw	DEAD_COUNT	; set up a dead-man timer of 5 seconds
	movwf	fire_count	; store it
f_loop:
	NCALL	check_cont	; check the Flashbulb continuity
	movf	cont_stat, F	; this sets Z if cont_stat = 0 
	btfsc   STATUS, Z       ; if Z is  set,  
	goto	finish		; it did fire. we're done
				; else it may have, we don't know.
	decf	fire_count, F	; subtract 1 from dead-man counter
	btfsc	STATUS, Z	; if count = zero, stop trying
	goto	finish		; we're done
	NCALL	half_sec	; else wait 500 ms
	goto	f_loop		; then try again
;************************************************************************
;  check_cont()
; Read RB2.  If it's set, we have continuity, else
; there is a problem (no continuity). Stores status in cont_stat.
;************************************************************************
check_cont:
        movfw   PORTB           ; read all of PORTB
        andlw   CONT		; mask off all but RB2 (bit 2, CONT)
	movwf	cont_stat	; save the status
				; RB2 HIGH = Continuity
				; RB2 LOW = NO Continuity
	goto	RTN		; return
;************************************************************************
;  read_switch()
; Reads the HEX rotary switch, decodes it, and stores the value in 
; swtch_count.
;************************************************************************
read_switch:
        movfw   PORTC           ; read port C
				; bits are inverted (0 = true) in H/W so
				; invert lower 4 bits
        andlw   0x0F            ; mask off upper 4 bits
                                ; (only need the lower 4)
        movwf   swtch_count     ; store it
	comf	swtch_count, F	; invert it
	movlw	0x0F		; load mask
	andwf	swtch_count, F	; clear upper 4 bits
        goto	RTN             ; return
;************************************************************************
;  armed_light()
; Sets the NO_CONTINUITY/ARMED LED to ARMED Status
;************************************************************************
armed_light:
        movlw   RED     ; set RC5 LOW, RC4 HIGH (RED)
	movwf	PORTC		; PORTC
	goto   RTN		; return good
;************************************************************************
;  g_switch()
; Check the status of the G switch and wait until it goes HIGH.
; Stores the status in g_status.
;************************************************************************
g_switch:
                                ; pend on the "G" switch (RB0) until a 
                                ; launch is detected (RB0 = HIGH)
        movfw   PORTB           ; read the port
	movwf	g_status	; save it
        btfss   g_status, 0     ; if bit 0 = 1, start debounce
        goto    g_switch        ; else keep looping until it is a 1
        NCALL	load_timer      ; wait ~70 ms (debounce period)
        movfw   PORTB           ; read the port again
        andwf   g_status, F     ; AND it with g_status, result in g_status
        btfss   g_status, 0     ; if it's still a 1, we're cool, launch detected!
        goto    g_switch        ; else go wait some more
	goto   RTN		; return, we've launched! 
;************************************************************************
;  blink()
; Flashes the LED on (GREEN) and off for .5 second each to count out the 
; switch setting stored in swtch_count. Flashes on/off for each count through 
; a loop. 
;************************************************************************
blink:
	movfw	swtch_count 	; load the switch count read from the port
	movwf	temp		; save in temp
bl1:
	movlw   GREEN     	; set RC5 HIGH, RC4 LOW (GREEN LED)
	movwf	PORTC		; PORTC
	NCALL	half_sec	; wait 500 ms
	movlw   OFF     	; set RC5 LOW, RC4 LOW (NO LED)
	movwf	PORTC		; PORTC
	NCALL	half_sec	; wait 500 ms

	decfsz	temp, F		; decrement temp
	goto	bl1		; if not zero, loop again
	goto   RTN		; if we're done, return
;************************************************************************
;  inti_pwr()
; Write SECRET_NUMBER TO SECRET_SPOT and go to sleep.
;************************************************************************
init_pwr:
	movlw	SECRET_NUMBER	; load secret number (0xB2)
	movwf	SECRET_SPOT	; store in SECRET_SPOT
	sleep			; wait for reset button press
;************************************************************************
;  blink_bad()
; Flashes the LED from GREEN to RED for 375 ms each for 6 cycles
; to indicate an error condition, then turns the LED OFF.
;************************************************************************
blink_bad:
	movlw	6	 	; load the loop count
	movwf	temp		; save in temp
blb1:
	movlw   GREEN     	; set RC5 HIGH, RC4 LOW (GREEN LED)
	movwf	PORTC		; PORTC
	NCALL	quarter_sec	; wait 250 ms
	NCALL	load_timer	; wait 62.5 ms
	NCALL	load_timer	; wait 62.5 ms
	movlw   RED     	; set RC5 LOW, RC4 HIGH (RED LED)
	movwf	PORTC		; PORTC
	NCALL	quarter_sec	; wait 250 ms
	NCALL	load_timer	; wait 62.5 ms
	NCALL	load_timer	; wait 62.5 ms
	decfsz	temp, F		; decrement temp
	goto	blb1		; if not zero, loop again
	movlw	OFF		; set LED to OFF
	movwf	PORTC		; (RC4 & RC5 LOW)
	goto	finish		; we're done
;************************************************************************
;  RTN()
; Return from subroutine NCALL. Could have been done as a MACRO, but
; saves code if done this way. 'POPs' the stack and reloads the PCL.
; Use only in conjunction with NCALL.
;************************************************************************
RTN     DECF    FSR, F  ; point to last "stack" location
        MOVLW   3       ; add 3 and output value from FSR
        ADDWF   INDF,W  ;       
        MOVWF   PC      ; load in PC as next executable 
			; instruction
;************************************************************************
	end			; end of program


Return to Index


| About LUNAR | Home | Calendar | Contacts | Gallery | Old Gallery | Member Pages | Events | Presentations & Docs | LUNAR'clips | Handbook | Space Place | Mailing Lists | Joining | Other Rocketry Pages | Site Map | Frames |

All content is the responsibility of LUNAR. If you have comments or suggestions regarding these web pages, please contact the

Copyright © 1992 - 2024 LUNAR