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
All content is the responsibility of LUNAR.
If you have comments or suggestions regarding these web pages,
please contact the
Copyright © 1992 - 2025 LUNAR