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