Tach input on any pin
Uses Darrel Taylor's Instant Interrupts
Fast, since is in ASM
This routine uses TMR0, but will work with any other unused timer.
To use -
Set interrupt period so that there will ALWAYS be an interrupt in the shortest
"high" or "low" period you want to measure. For example, if highest tach freq
is 100Hz and is a square wave, the period will be 10msec and the "high" part
of the square wave will be 5msec and the "low" period will be 5msec. In this case
the interrupt period should be 5msec minimum - choose 4 msec or less (must be a
little less than 5msec to cover interrupt latency). If the tach frequency is higher
or the input is not a square wave, you will have to increase the interrupt rate
accordingly.
In your main PBP routine - Clear TachCounter,ShaftCounter1,ShaftCounter2,Shaftcount erX.
Then clear PeriodDone. The routine will count for 1000 interrupts. When you want to
read the tachs, check if PeriodDone bit 0 is set - if it is, then the count is finished.
Move the ShaftCounters into PBP variables, Clear the shaftcounters and clear PeriodDone.
The cycle repeats and runs totally in the background.
You will have to mutliply the ShaftCounter variables by a value determined by
the tachometer and interrupt rate to get actual RPM.
The code can probably be improved, but it works for me.
Code:
Asm
ReadTachs
movlw 0xEC ; Reload TMR0 with your own value - sets INT rate - see explanation above
movwf TMR0H ; Load the high byte first
movlw 0x7E ; Load the low byte
movwf TMR0L
btfss PeriodDone,0 ; Check to see if counting period is over
bra CheckTach
bra DoneForNow
infsnz TachCounter ; 16 bit counter
incf TachCounter + 1
movlw 0x03 - 1 ; 1000 = 0x3E8, but must have one less
cpfsgt TachCounter + 1 ; to compare with greater than (choose a different number if you like)
bra FanRoutine
movlw 0xE8 - 1 ; Again, subtract one
cpfsgt FanCounter
bra MainRoutine
bsf PeriodDone,0 ; Set the PERIOD Done lsbit
clrf TachCounter ; Clear the counter
clrf TachCounter+ 1
bra DoneForNow
MainRoutine
movf PORTB,0,0 ; Load all of Port B
movwf Temp,0 ; Copy it into TEMP for safety
xorwf OldPortB,0,0 ; XOR it with previous read
movwf changedB,0 ; Move the XORed byte into variable
movff Temp,OldPortB ; Move Temp to OldPortB
movf PORTC,0,0 ; Do the same for PORTC (or any port with a tach input)
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
Shaft1
btfss changedB,0 ; Read in the bit - if it changed from last read it will be a "1"
bra Shaft2 ; It hasn't changed, so go to next
infsnz Shaft1Counter ; Increment the counter lowbyte
incf Shaft1Counter+1 ; If necessary, increment the high byte
Shaft2
btfss changedC,1 ; This shaft tach is fed into PORTC.1
bra Shaft3
infsnz Shaft2Counter
incf Shaft2Counter+1
; Put more shaftcounters here if you need them.
DoneForNow
bcf INTCON,2 ; Clear the TIMER0 interrupt flag
INT_RETURN
ENDASM
Bookmarks