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