Have you thought of doing it a slightly different way? Most sensors have some jitter, so averaging out several samples gives a better result. Also, the duty cycle often isn't constant. To be really accurate, you have to take width of a positive half-cycle and add it to the width of a negative-half cyle.
I had enormous problems measuring the speeds of small fans using PULSIN. In order to get a stable, accurate result I had to average so many samples together the routine was taking too long.
Below is an ISR written in assembly that does the job perfectly.
It is run on a timer interrupt, so you can use any pin. The interrupt period is adjusted to be less than the period of the smallest half-cycle you need to measure.
In the example below, it is 1mSec. TPE is a flag that gets set after a certain number of interrrupts (1000 in this case), so it will measure over 1 second.
To use it, you clear Fanclock and Fan1Counter and TPE
Your main loop checks for TPE being set. If it is, it transfers the contents of Fan1Counter to another variable (call it SPEED), clears FanClock, Fan1Counter and TPE.
Now the variable SPEED always has the number of transitions (twice the pulse rate). It runs totally in the background. The rest of your program really doesn't need to know your timer exists. All it has to do is read SPEED and clear the variables.
Since you are getting ~4K pulses / mile, you will get a little less than 1 pulse per foot of travel. 60MPH = 88 ft/sec. So you could count for a little less than 1/2 second (change 3E8 to something a little smaller than 1F4) and you will get an answer in MPH. No fancy math required.
Code:
ReadTach
movlw 0xEC ; Reload TMR0 with 65535 - 10000
movwf TMR0H
movlw 0x7E
movwf TMR0L
bcf INTCON,2 ; Clear the TIMER0 interrupt flag
btfss TPE,0
bra CheckFans
bra DoneForNow
CheckFans
infsnz FanClock
incf FanClock + 1
movlw 0x03 - 1 ; 1000 = 0x3E8, but must have one less
cpfsgt FanClock + 1 ; to compare with greater than
bra FanRoutine
movlw 0xE8 - 1 ; Again, subtract one
cpfsgt FanClock
bra FanRoutine
bsf TPE,0
clrf FanClock
clrf FanClock + 1
bra DoneForNow
FanRoutine
movf PORTB,0,0
movwf Temp,0
xorwf OldPortB,0,0 ' XOR current with old to detect change
movwf changedB,0
movff Temp,OldPortB
Fan1
btfss changedB,0 ' Fan is connected to PortB.0
bra DoneForNow
infsnz Fan1Counter
incf Fan1Counter+1 ; increment the counter
DoneForNow
INT_RETURN
Bookmarks