As stated previously, Wicked Air Sportz conducts testing using a Oehler Model 43 chrono. We have tested v2.0 through v2.7 of the Intimidator Equalizer code, shooting over this chrono and in every instance, the counter has matched chrono's results.
The Equalizer's max rate of fire counter displays the maximum number of shots that occurred during exactly one second of shooting. If you pulled the trigger for 10 seconds, the fastest string of shots during any 1 second period is recorded as the highest (max) rate of fire.
Below is code associated with the rate of fire handling, which will perhaps give a better explanation of how this works. We are providing this code for public inspection, but we are not entering this code into the public domain. All copyrights are retained. This is being done to prove the point that the counter is 100% accurate, as verified by the Oehler Model 43 chrono and other small chronos. We welcome anyone with experience in PIC micro assembly to make their comments about the operation of the MROF code.
© 2002-2003 by Jim Drew
Timer Interrupt code, occurs after 1000ms:
; This code handles events that happen every one second
SysClockExit incfsz SecondClockLow,f ; inc low byte of 1 second clock
goto NoSecond ; no wrap
incfsz SecondClockHigh,f ; inc high byte of 1 second clock
goto NoSecond
; 1 second has elapsed, so reset the clock and handle whatever events need
; to be handled.
clrf ROF ; clear rate of fire
bsf SystemFlags,sf_Update ; set update flag
CheckTimers btfss AuxFlags,af_Timer ; is timer running?
goto NoGameClock
decf GTimerSecs,f
comf GTimerSecs,w ; did the seconds wrap?
btfss STATUS,Z
goto NoGameClock
movlw 59
movwf GTimerSecs ; store new value in timer
decf GTimerMins,f
comf GTimerMins,w ; did the minutes wrap?
btfss STATUS,Z
goto NoGameClock
; alarm code goes here!!
bcf AuxFlags,af_Timer ; turn off timer!
clrf GTimerSecs
clrf GTimerMins
NoGameClock movf BLClock,f ; see if clock is 0
btfsc STATUS,Z ; skip if not equal
goto NoBLChange
decfsz BLClock,f ; decrement backlight clock
goto NoBLChange ; no wrap yet
BACKLIGHT_OFF ; clock now at 0 so turn off backlight!
btfss SystemFlags,sf_Menu ; in menu mode?
goto NoBLChange ; nope continue
NoBLChange
NoSecond return
----------------------------------------------------------
Interrupt code that handles firing, particularly the clean up code after shot has completed:
DoBoltDelay btfss EyeIN ; get eye state, skip if bolt IS blocking the eye beam!
goto StillNoBolt
bcf SystemEvent,se_BoltDelay ; we picked up something again, so go back to checking the bolt constantly!
bsf SystemEvent,se_BoltCheck
goto TMR2Exit
StillNoBolt decfsz TMR2Count,f ; decrement countdown, if <>0 then clear int flag and exit
goto TMR2Exit
movlw 3 ; eye worked this time, so lets reset
movwf EyeFailures ; # of failures before disabling the eye
ShotCleanUp movf CycleClock,w ; save total cycle time
movwf CycleTime
incfsz ShotCountLow,f
goto NoShotCountWrap
incf ShotCountHigh,f
NoShotCountWrap LED_OFF
btfss TimerControl,tc_Start ; is timer start based on first trigger?
bsf AuxFlags,af_Timer ; yes, so start timer
incf ROF,f ; increment rate of fire counter
bsf SystemFlags,sf_Shot ; set flag to update display
IFDEF FULLAUTO
btfss Flags,ef_FireMode ; firing mode full auto?
goto NoBallExit ; no, exit
btfss Trigger ; is the trigger still down?
goto DoFASetup ; yes, goto do full auto setup
ENDIF
NoBallExit EYEIR_OFF ; turn off IR transmitter
clrf SystemEvent
bcf INTCON,RBIF ; clear any pending interrupts
bsf INTCON,RBIE ; re-enable change state int (allow button events)
FiringExit bcf T2CON,TMR2ON ; disable timer 2
TMR2Exit bcf PIR1,TMR2IF ; clear interrupt pending flag
goto IntHandlerExit ; go to exit routine
----------------------------------------------------------
This is the routine that shows the shot count, called as a task via the multitasking when the system flag (thread queue) is set (shot occurred):
;**********************************************************************
; This routine displays the current shot counter. The system flag
; sf_Shot determines if the gun has been fired since the last time
; this routine was called. If it has been fired, the count is
; displayed and the system flag is cleared.
ShowShotCount movlw (lcd_DDRAM|Line1)+11 ; move cursor to proper position
call SendINS
movf ShotCountHigh,w ; get current high byte
movwf NumH ; save for ASCII conversion
movf ShotCountLow,w ; get current low byte
movwf NumL ; save for ASCII conversion
call Dec2ASCII ; convert to ASCII value
; call PrintTenKs
call PrintThousands
call PrintHundreds
call PrintTens
call PrintOnes
bcf SystemFlags,sf_Shot ; clear update counter flag
; max rate of fire display
movf ROF,w
iorwf MROF,w ; if ROF and MROF are 0, then display it!
btfsc STATUS,Z
goto ForceROFDisplay
movf ROF,w ; get current ROF
subwf MROF,w ; subtract from current MROF
btfsc STATUS,C ; new MROF?
goto OldMROF
ForceROFDisplay movlw (lcd_DDRAM|Line1)+6 ; move cursor to proper position
call SendINS
movlw ROFChar
call SendCHAR ; ROF symbol
movf ROF,w ; current ROF is
movwf MROF ; now the new MROF
movwf Scratch1
clrf Scratch2
movlw 10
SubLoop subwf Scratch1,f
btfss STATUS,C ; did we get a carry?
goto NoCarry
incf Scratch2,f
goto SubLoop
NoCarry addwf Scratch1,f
movf Scratch2,f ; did we get to 10 or more?
btfsc STATUS,Z
goto SingleDigit ; nope, so don't show leading '0'
movf Scratch2,w
call PrintCommon
SingleDigit movf Scratch1,w
call PrintCommon
movlw ' '
call SendCHAR
; cycle time display
OldMROF
IFDEF SHOWCYCLETIME
movlw (lcd_DDRAM|Line2)+5 ; move cursor to proper position
call SendINS
movf CycleTime,w
movwf Scratch1
clrf Scratch2
movlw 10
SubLoop2 subwf Scratch1,f
btfss STATUS,C ; did we get a carry?
goto NoCarry2
incf Scratch2,f
goto SubLoop2
NoCarry2 addwf Scratch1,f
movf Scratch2,w
call PrintCommon
movf Scratch1,w
call PrintCommon
movlw 'm'
call SendCHAR ; send to display
movlw 's'
call SendCHAR ; send to display
ENDIF
return