I posted this at least once before, but here it is again;


Code:
        INCLUDE "DT_INTS-18.bas"         ; Base Interrupt System

  
ASM
INT_LIST  macro    
              INT_Handler    TMR0_INT,   ReadTachs,   ASM,  yes 

          endm
    INT_CREATE              
ENDASM
                         
Goto OverInt

;-----------------------------------------------------------------
   
Asm                            
ReadTachs
         movff    PreloadH,TMR0H  ; Preload depends on clk speed
         movff    PreloadL,TMR0L
      
        
      
         infsnz  MasterClock                     ; 16 bit timer used for housekeeping
         incf    MasterClock + 1
        
         btfsc   TPE,0                             ; Tells tach routine to stop
         bra     DoneForNow
        
;CheckTach        
         infsnz  TachClock          ; Tells tach counters how long to count
         incf    TachClock + 1
     
         movlw   0x03 - 1          ; Real value is 1000 = 0x3E8, but must have one less
         cpfsgt  TachClock + 1      ; to compare with greater than
         bra     TachRoutine
         movlw   0xE8 - 1          ; Likewise, subtract one here, too.
         cpfsgt  TachClock
         bra     TachRoutine
         bsf     TPE,0
         
         clrf    TachClock
         clrf    TachClock + 1
         bra     DoneForNow
                
TachRoutine
              
         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
         
         
Tach1       
         btfss   changedB,0
         bra     Tach2
         infsnz  Tach1Counter
         incf    Tach1Counter+1
       
Tach2        
         btfss   changedB,1
         bra     Tach3
         infsnz  Tach2Counter
         incf    TachCounter+1
                
Tach3        
         btfss   changedB,2
         bra     Tach4
         infsnz  TachCounter
         incf    TachCounter+1
Tach4        
         btfss   changedB,3
         bra     Tach5
         infsnz  Tach4Counter
         incf    Tach4Counter+1
       
Tach5       
         btfss   changedB,4
         bra     Tach6
         infsnz  Tach5Counter
         incf    Tach5Counter+1        
       
Tach6       
         btfss   changedB,5
         bra     Tach7
         infsnz  Tach6Counter
         incf    Tach6Counter+1 
                 
Tach7        
         btfss   changedC,0
         bra     Tach8
         infsnz  TachCounter
         incf    TachCounter+1  
           
Tach8        
         btfss   changedD,5
         bra     Tach9
         infsnz  Tach8Counter
         incf    Tach8Counter+1               
              
Tach9        
         btfss   changedD,4
         bra     DoneForNow
         infsnz  Tach9Counter
         incf    Tach9Counter+1  
                     
DoneForNow
        
         bcf     INTCON,2   ; Clear the TIMER0 interrupt flag
       
        INT_RETURN	 	
ENDASM

Set the PRELOAD value for the interrupt period (must be shorter than the shortest tach half-cycle). Set the TachCounter for how many interrupts you want to count over (currently 1000). Clear all the TachCounters and set TPE to 0. Periodically check to see if TPE is set. If so, copy the TachCounters to other variables, zero the variables and start over. All done in the background and does a nice job of averaging - something you will need if there is any kind of noise present.