You can use a timer interrupt. You can use TMR0 or just "piggyback" on Darrel's TMR1 interrupt in the SSPWM routine.
The only caveat is that the period of that interrupt must be shorter than the narrowest pulse (either high or low) that your speedometer sensor puts out.
I have written (and posted) a routine that would do what you want. Mine is written in asm, but could be written in PBP as well.
Below is a section. It measures the speed of 9 fans by watching the tachometers.
A couple of things to note -
It must be written as an ISR.
The interrupt time is determined by PRELOADH and PRELOADL.
The routine runs for an exact number of interrupts before stopping (FanClock is the counter) 1000 is the number here.
So if you interrupt at 1mSec intervals, this routine will run for 1 second before being restarted in the main loop.
To use:
Set your interrupt rate.
Determine how many counts you need to get the accuracy you want (which determines
how long you need to count and therefore, the maximum update rate of your speedometer).
If you get 1 cycle (1 high period and one low period) per foot, and you have a 50% duty cycle, then you will get 88 cycles per second with a high period of 5.6 mSec and a low period of 5.6 mSec. To account for jitter, your interrupt period would have to be 5 mSec or less. You would have 166 transitions (low->high + high -> low) in one second. If you set FanCounter to time out in .3614 seconds (say 100 counts with a 3.614 mSec update rate), the count would be in exact mph with a .3614 second update rate. Longer counting intervals and faster interrupts gives more accuracy and less jitter.
You need clear TPE before you start.
Check TPE in your main loop. If it is set, the routine has completed. Transfer the contents of the FanxCounters to another set of variables (call them FanYcounters, clear all the FanXcounters, Clear FanClock and Clear TPE. Now your main loop can read FanYcounters and display the mph, or RPM, or whatever.
You don't have to stop TMR0 on most chips to reload it. You do have to stop most of the other timers before reloading. Check your datasheet.
The routine runs for an exact number of interrupts before stopping. You need clear TPE before you start.
Code:
Asm
ReadTachs
movff PreloadH,TMR0H ; Preload depends on clk speed
movff PreloadL,TMR0L
infsnz MasterClock
incf MasterClock + 1
btfsc TPE,0
bra DoneForNow
;CheckFans
infsnz FanClock
incf FanClock + 1
movlw 0x03 - 1 ; Real value is 1000 = 0x3E8, but must have one less
cpfsgt FanClock + 1 ; to compare with greater than
bra FanRoutine
movlw 0xE8 - 1 ; Likewise, subtract one here, too.
cpfsgt FanClock
bra FanRoutine
bsf TPE,0
clrf FanClock
clrf FanClock + 1
bra DoneForNow
FanRoutine
movf PORTB,0,0
movwf Temp,0 ; Save VAR so can't change between compare and save
xorwf OldPortB,0,0
movwf changedB,0
movff Temp,OldPortB
movf PORTC,0,0
movwf Temp,0
xorwf OldPortC,0,0
movwf changedC,0
movff Temp,OldPortC
movf PORTD,0,0
movwf Temp,0
xorwf OldPortD,0,0
movwf changedD,0
movff Temp,OldPortD
Fan1
btfss changedB,0
bra Fan2
infsnz Fan1Counter
incf Fan1Counter+1
Fan2
btfss changedB,1
bra Fan3
infsnz Fan2Counter
incf Fan2Counter+1
Fan3
btfss changedB,2
bra Fan4
infsnz Fan3Counter
incf Fan3Counter+1
Fan4
btfss changedB,3
bra Fan5
infsnz Fan4Counter
incf Fan4Counter+1
Fan5
btfss changedB,4
bra Fan6
infsnz Fan5Counter
incf Fan5Counter+1
Fan6
btfss changedB,5
bra Fan7
infsnz Fan6Counter
incf Fan6Counter+1
Fan7
btfss changedC,0
bra Fan8
infsnz Fan7Counter
incf Fan7Counter+1
Fan8
btfss changedD,5
bra Fan9
infsnz Fan8Counter
incf Fan8Counter+1
Fan9
btfss changedD,4
bra DoneForNow
infsnz Fan9Counter
incf Fan9Counter+1
DoneForNow
bcf INTCON,2 ; Clear the TIMER0 interrupt flag
INT_RETURN ; WAS RETFIE FAST Return from the interrupt
ENDASM
Bookmarks