ERRORLEVEL -302 TITLE "Boston Bomb (c) 2007 Doug Jackson." ; ;************************************************************************************* ; ; Boston Bomb - A simulation of a Boston Bomb ; ; Copyright (c) 2007 ; Doug Jackson ; doug@stillhq.com ; ; ; Create Date: 26 Aug, 2007 ; Notes: None ; ;************************************************************************************* ; Revision History ;************************************************************************************* ; Date By What ;************************************************************************************* ; 20070826 DRJ Initial Creation ; 20070906 DRJ Code Tidyup - saved 76 bytes (0xea - 0x9e)!! ; 20070912 DRJ Added animation capability - waves arms - Not as good as I expected! ;************************************************************************************* ; ; CPU configuration ; (It's a 16F84, XT oscillator, ; watchdog timer on, power-up timer on) processor 16f84a include __config _XT_OSC & _WDT_ON & _PWRTE_ON PAGE ; ;************************************************************************************* ; Hardware Constants ;************************************************************************************* ; #define CHARACTER PORTA ; the output for turniong on the character #define PSU PORTA,0 ; 1 = PSU on #define ARMLFTUP PORTB,4 ; definitions for the arm leds #define ARMLFTDN PORTB,5 #define ARMRGTUP PORTB,6 #define ARMRGTDN PORTB,7 #define LDR PORTB,1 ; the LDR for detecting darkness #define BUTTON PORTB,0 ; the interrupt push button ; ;************************************************************************************* ; Ram Variable assignments ;************************************************************************************* ; CBLOCK 0x010 TEMP ; temporary register J ; delay loop counter K ; delay loop counter L ; delay loop counter ADCVALH ADCVALL ML ; delay counter for temminute delay DAYFLAG ; flag to indicate that it has already been night, so wait for ; day before another trigger ENDC PAGE ; ;************************************************************************************* ; Code Starts Here ;************************************************************************************* ; org 0x0000 reset goto start ; Reset vector location ; ;************************************************************************************* ; Interrupt Vectors ;************************************************************************************* ; ; The only interrupt we care about is PB0 - the push button. ; If it is hit, start from scratch. org 0x0004 int clrf INTCON goto start ; Reset vector location PAGE ; ;************************************************************************************* ; Start: ; Set up all inputs and outputs as designed. ; and do a self test. ;************************************************************************************* ; org 0x0010 start ; bsf STATUS, RP0 ; Bank 1 movlw b'00000011' ; bottom 2 bits of port b are inputs movwf TRISB movlw b'00000000' ; and all bits of port A are outputs movwf TRISA bcf STATUS, RP0 ; select bank 0 again.. clrf INTCON ; Dissable interrupts bsf STATUS, RP0 ; select bank 1 movlw B'10001111' ; port B pullups are disabled ; prescaler set to WDT - 1:128 divider movwf OPTION_REG ; bcf STATUS, RP0 ; bank 0 bsf DAYFLAG,0 ; it is daytime so set the flag ; and turn our creature off. call turnoff PAGE ; ;************************************************************************************* ; Main Loop. This is where most of the work is done. ;************************************************************************************* ; MAINLOOP ; test our outputs ; by flashing a few times ; then turning on for 10 seconds call quickflash call turnoff movlw b'10010000' movwf INTCON ; GIE enabled - INTE enabled ; ; now we wait till the watchdog triggers us. ; it keeps us in a very low power mode to conserve battery power wait call turnoff sleep ; wait for a WDT timeout to happen ; yay, we are here because a wdt interrupt occurred ; check if the button is down... Button_Test call one_s_delay ; do a delay btfss BUTTON ; is the button still down? goto turnon ; no, jump out, and wait till the button has actually ; been held down ; yes - do it all again.. ; movlw b'10010000' ; ; movwf INTCON ; GIE enabled - INTE enabled ; ; now create a simple ADC using an LDR and a series cap to see if it is dark. ; if its dark, do a little dance ; dark_test bsf STATUS, RP0 ; Bank 1 movlw b'00000001' ; turn Port B.1 into an output, set all others as inputs movwf TRISB bcf STATUS, RP0 ; Bank 0 bsf LDR ; drive the ADC input high charge the capacitor call delay200ms ; do a delay (wait about 200ms) call delay200ms ; do a delay (wait about 200ms) bcf LDR ; drive the ADC input low to start the discharge cycle clrf ADCVALH ; clear the ADC High Value clrf ADCVALL ; clear the ADC Low Value adc_lp bsf STATUS, RP0 ; return to Bank 1 movlw b'00001111' ; turn Port B.1 into an input movwf TRISB bcf STATUS, RP0 ; return to Bank 0 incf ADCVALL,f movf ADCVALL,w ; test to detect rollover of the ADCVALL btfss STATUS,Z ; is the adcvall = zero (it rolled over)? goto adcl1 incf ADCVALH,f ; increment the high bit counter adcl1 clrwdt btfss LDR ; has the cap discharged enough to read low? goto adc_exit ; yep - bail out ; continue the discharge bsf STATUS, RP0 ; return to Bank 1 movlw b'00000001' ; turn Port B.1 back into an output movwf TRISB bcf STATUS, RP0 ; return to Bank 0 bcf LDR ; continue the discharge some more. movlw d'10' ; setup a loop counter movwf TEMP adcl2 clrwdt ; just waste some time decfsz TEMP,F ; decrement the loop counter goto adcl2 ; if non zero, waste some more time goto adc_lp ; ; ; ; adc_exit ; we have finally discharged the cap to a value that constitutes a Low. ; ADCVAL has a number that depends on the resistance ; low = low resistance (dark = les than 100) ; high = high resistance (light = greater than about 200) ; remember that adcval is made from2 parts ADCVALH and ADCVALL ; bsf STATUS, RP0 ; return to Bank 1 movlw b'00000001' ; turn Port B.1 back into an output movwf TRISB bcf STATUS, RP0 ; return to Bank 0 movf ADCVALH,w ; test the high byte of the ADCVAL btfsc STATUS,Z ; if it is non zero, it is far to light to be ; night time. goto night_test bsf DAYFLAG,0 ; it is daytime so set the daytime flag goto wait night_test movlw d'90' ; now, test the low byte subwf ADCVALL,w btfss STATUS,0 ; if carry is clear - we didn't overflow ; if set, then we overflowed - ; ADCVAL greater than test value - skip the jump goto night_time bsf DAYFLAG,0 ; it is daytime so set the daytime flag clrf CHARACTER ; make sure that the character is off goto wait night_time btfss DAYFLAG,0 ; has it been day - yep - do the dance ; otherwise it is still night goto wait bcf DAYFLAG,0 ; it is nighttime so clear the flag ; do our little dance ; then flash away for a while. call quickflash call slowflash call quickflash ; finished the dance - wait again goto wait ;************************************************************************************* ; turnon In response to the push button being pressed, do some slow flashes ; then leave the character on for 30 seconds for photos... ; Input: None ; Output: Time wasted. ; Comments: none ;************************************************************************************* ; turnon clrf INTCON movlw 0xff movwf CHARACTER bsf ARMLFTUP bsf ARMRGTDN call one_s_delay call turnoff call one_s_delay movlw b'10010000' movwf INTCON ; GIE enabled - INTE enabled call quickflash call quickflash call quickflash call turnoff bsf PSU ; leds on bsf ARMLFTDN bsf ARMRGTUP call one_s_delay call turnoff bsf PSU ; leds on bsf ARMLFTUP bsf ARMRGTDN call one_s_delay call one_s_delay call one_s_delay call one_s_delay call one_s_delay call turnoff ; leds off goto wait ;************************************************************************************* ; turnoff turn off the character... ; Input: None ; Output: darkness ; Comments: none ;************************************************************************************* ; turnoff bcf PSU ; leds off bcf ARMLFTUP bcf ARMLFTDN bcf ARMRGTUP bcf ARMRGTDN return ;************************************************************************************* ; quickflash flash the character quickly for a 5 cycles ; Input: None ; Output: flashing character. ; Comments: none ;************************************************************************************* ; quickflash movlw d'5' ; movwf TEMP ; load up a loop counter testlp bsf PSU ; leds on bsf ARMLFTUP bsf ARMRGTDN call delay200ms call turnoff ; leds off bsf PSU ; leds on bsf ARMLFTDN bsf ARMRGTUP call delay200ms call turnoff ; leds off call delay200ms decfsz TEMP,F goto testlp testlend bsf PSU ; leds on bsf ARMLFTUP bsf ARMRGTUP call delay200ms call delay200ms call delay200ms call delay200ms call delay200ms bcf PSU bcf ARMLFTUP bcf ARMLFTDN bcf ARMRGTUP bcf ARMRGTDN return ;************************************************************************************* ; slowflash flash the character 5 times with a one second delay ; flashes. ; Input: None ; Output: Flashing character. ; Comments: none ;************************************************************************************* ; slowflash movlw d'5' movwf TEMP ; setup the loop counter slowflp call turnoff bsf PSU ; leds on bsf ARMLFTDN bsf ARMRGTUP call delay200ms bcf ARMRGTUP BSF ARMRGTDN call delay200ms bsf ARMRGTUP bcf ARMRGTDN call delay200ms bcf ARMRGTUP BSF ARMRGTDN call delay200ms bsf ARMRGTUP bcf ARMRGTDN call delay200ms bcf ARMRGTUP BSF ARMRGTDN call delay200ms call one_s_delay ; wait call turnoff ; character off call one_s_delay ; wait decfsz TEMP,F ; have we looped enough times? goto slowflp ; no, try again return PAGE ; ;************************************************************************************* ; ten_min_delay Fixed delay time wait. Waste some time executing a nested loop ; Input: None ; Output: Time wasted. ; Comments: none ;************************************************************************************* ; ten_min_delay movlw d'60' movwf ML mlloop call ten_s_delay decfsz ML,f goto mlloop return ; ;************************************************************************************* ; ten_s_delay Fixed delay time wait. Waste some time executing a nested loop ; Input: None ; Output: Time wasted. ; Comments: none ;************************************************************************************* ; ten_s_delay movlw d'50' ; 5 creates about a 10 second delay. movwf L tensloop call delay200ms clrwdt decfsz L,f goto tensloop return ; ;************************************************************************************* ; long_delay Fixed delay time wait. Waste some time executing a nested loop ; Input: None ; Output: Time wasted. ; Comments: none ;************************************************************************************* ; one_s_delay movlw d'5' ; 5 creates about a 1 second delay. movwf L jloop1 call delay200ms clrwdt decfsz L,f goto jloop1 return PAGE ; ;************************************************************************************* ; delay200ms Waste some time executing a nested loop ; Input: None ; Output: Time wasted. ; Comments: none ;************************************************************************************* ; delay200ms movlw 0xe0 ; A fairly long delay. movwf J jloop movwf K kloop clrwdt decfsz K,f goto kloop decfsz J,f goto jloop return end