Tachometer with 1 rpm resolution.

Purpc

New Member
Hi
After going around and around with the limitations of Picaxe word variable, I found this code on other forum:
Code:
'

**********************************************************************************
' **********************************************************************************
' *****
' ****** * * * *MOTORCYCLE TACHOMETER by Warren Schroeder July 5, 2008
' ****** * * * ACCURATE OUTPUT FROM 0 TO 65500 RPM WITH 1RPM RESOLUTION
' ****** * * * * * * * * * * * * * MikroBASIC 7.2
' ****** * * * Tested On EasyPIC5 with PIC18F4431 @ 32MHz (8MHz x 4PLL)
' *****
' ***********************************************************************************
' ***********************************************************************************
' *****
' ****** *RPM Display on 16x2 LCD
' *****
' ****** *This TACHOMETER Code is developed for 60 input pulses per engine revolution
' ****** *Output Range is 0 to 62535 RPM in 1RPM Resolution with updates every second
' *****
' ****** *Timer0 is set up as a 16-bit counter with T0CK1 RC3 catching rising edges
' ****** *CCP1 is set up for 62500us interrupts using the special event feature
' ****** *which resets Timer1 on Compare-Match
' ****** *16 CCP1 Interrupts @ 62500us each = 1 Second
' *****
' ***********************************************************************************
' ***********************************************************************************


* Dim CCPR* *as Word Absolute $FBE* * *' CCPR1L:CCPR1H Pair as Word
* Dim Tally* as Byte
* Dim RPM* * as Word
* Dim TRPML* as Byte Absolute $30
* Dim TRPMH* as Byte Absolute $31
* Dim TRPM* *as Word Absolute $30
* Dim RPMStr as String[5]


* sub procedure interrupt()
* * * * *TRPML = TMR0L* * * * * * * *' capture Count; store in temp register
* * * * *TRPMH = TMR0H
* * * * *Tally = inc(Tally) And 15* *' Mod16 counter
* * * If Tally = 0 Then* * * * * * * ' if 1 second
* * * * *TMR0H = 0* * * * * * * * * *' clear Timer0 Counter
* * * * *TMR0L = 0
* * * * *RPM = TRPM* * * * * * * * * ' save RPM value for display
* * * End If
* * * PIR1.CCP1IF = 0* * * * * * * * ' clear interrupt flag
* end sub

* sub procedure Timer0_As_Counter()
* * * T0CON* *= 40* * * ' Off; 16Bit; Counter; rising edge; no prescaler
* * * TMR0H* *= 0* * * *' Clear Timer0 Count
* * * TMR0L* *= 0
* * * TRISC.3 = 1* * * *' RC3 is T0CK1 Counter Input
* end sub

* sub procedure CCP1_As_Timer()
* * * CCP1CON* = 11* * *' CCP1 Compare Match Special Event
* * * T1CON* * = 48* * *' Timer1 Off; Prescaler=8 = 1us ticks (125ns x 8)
* * * TMR1H* * = 0* * * ' Clear Timer1
* * * TMR1L* * = 0
* * * CCPR* * *= 62500* ' interrupt every 62500us
* * * PIE1.CCP1IE = 1* *' enable CCP1 interrupt
* * * PIR1.CCP1IF = 0* *' clear CCP1 interrupt flag
* * * INTCON* * * = 192 ' enable GIE and PEIE
* end sub


main:
* * * ANSEL0 = 0* * * * ' disable adc's
* * * ANSEL1 = 0
* * * TRISA* = 0
* * * TRISB* = 0
* * * TRISC* = 0
* * * TRISD* = 0
* * * LATA* *= 0
* * * LATB* *= 0
* * * LATC* *= 0
* * * LATD* *= 0

* * * Timer0_As_Counter()
* * * CCP1_As_Timer()
* * * LCD_CONFIG(PORTB,3,2,1,0,PORTB,4,0,5)
* * * LCD_CMD(LCD_CURSOR_OFF)

* * * Tally = 0* * * * * ' reset timing tally
* * * T0CON.TMR0ON = 1* *' start Timer0 counter
* * * T1CON.TMR1ON = 1* *' start Timer1

* * * While 1=1
* * * * * delay_ms(50)
* * * * * WordToStr(RPM, RPMStr)
* * * * * LCD_OUT(1,1,RPMStr)
* * * * * LCD_OUT_CP(" RPM")
* * * Wend

end.
After reads and understand the code, because the limitations of Picaxe and making my calculations, a can only get 16-65500 range of resolution, using 28x2 at 40 MHz with a 1us count increment on pulsin, but for rpm lower than 16 the pulsin gets a timeout.
I'm a newbie in picaxe and can't figure how to work around this. Someone with more knowledge can figure who?
 

AllyCat

Senior Member
Hi,

Welcome to the forum.

What accuracy do you actually need and what are you trying to do?

If your hardware delivers only one pulse per revolution and you need 1 rev per minute accuracy, then the measurement will take at least one minute (which normally is not very useful).

If your rotor is actually turning so slowly (i.e. just a few rpm), then you must generate a larger number of (accurately-spaced) pulses per revolution, or use a much lower frequency counter (and be patient for each result).

Cheers, Alan.
 

oracacle

Senior Member
what are you measuring the RPM of? is it actually going to get below 16rpm. The example code you have posted is for a motorcycle which will only rarely get below 1000rpm. you will also have to consider the max rpm you need to be able to read.

In theory there is no reason why you cant use 2 frequencies. one make use of the internal oscillator and the other external
ir
Code:
if rpm < 20 then
     setfreq m4
else
    setfreq em40
end if
if you do this you have to ensure that there is an overlap in the rpm so that detection happens with the ranges of each frequency. you may also be able to do it directly off the raw pulse count before any post processing is done to it.
 

Purpc

New Member
Hi
Thanks for the reply. To get 1 rpm the pulse have to take 1 second, with the freq M4 it overflow before that.
The other issue is the math. If I use ms I will lose also acuracy, ex
60000/2=30000 <=> 30 rpm: 60000/3=10000 <=> 10 rpm .
I will try count the overflows .
 

oracacle

Senior Member
seeing as you are using an X2 you could user timer.
Not used the timer much myself, however you could use it for timing a 1 or 2 second period while using if..then loop for the tacho input, latency wont be an issue at low rpm.
the timer is background and can trigger interrupts to stop the counting.

another way that I can't confirm will work is to use the external timer input on the 28x2 to count the pulses. the time measurement duration can be obtained using a simple pause before reading the timer variable. timer variable can be reset with timer = 0
 
Top