optimizing tachometer reading

Go To Last Post
13 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hi, i'm making a tachometer for a motor that i have, i know that the max rpm for my motor is 3000, so i tried to count the rpm with the input capture pin, but the precision is not good, im testing it with a square wave generator and i tune it to 5 hz, and my code gives me 4hz, i dont need god precision but i sure would like to know if i can tweak a little my code :P , here is my code

my uC is atmega32 i know is overkill for this but im going to use an atmega 8 in my final circuit

my oscillator is the internal RC 1mhz and i used the stk500 to tune it at 1% precision

#include
#include
#include
#define rising_config 0b11000011
#define falling_config 0b10000011

//Variables
uint16_t rising_edge_time=0,falling_edge_time=0;
uint16_t duty_cycle=0;
uint16_t rpm =0;
float temp=0;
char new_read=0;
//Interrupt Code
ISR (TIMER0_OVF_vect){
if(new_read ==1){
temp = duty_cycle*2*.000064;
rpm = (1/temp)*60;

if((rpm<=10000)&&(rpm>=10)){
lcd_clear();
lcd_string("RPM = ");
lcd_custom_num2(rpm,10);
}
else{
lcd_clear();
lcd_string("OUT OF RANGE");
}
}
TIFR = 0;
}

ISR(TIMER1_CAPT_vect){
if(TCCR1B==rising_config){
falling_edge_time = ICR1;
TCCR1B = falling_config;
}
else{
rising_edge_time = ICR1;
TCCR1B = rising_config;
TCNT1 = 0;
duty_cycle = (unsigned long)rising_edge_time - (unsigned long)falling_edge_time;
new_read =1;
}
TIFR = 0;
}
//Main Code
int main(void){
config_lcd();
TCCR0 = 0x05;
TCCR1A=0;
TCCR1B = rising_config;
TCNT0 = 0;
TCNT1=0;
TIMSK|=(1<<TICIE1)|(1<<TOIE0);
sei();
while(1)
{
}
return 0;
}

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I believe you should be measuring edge to edge here. From rising to rising or falling to falling.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What are you going to use as your signal from the motor? The motor is going to have an unbelievably noisy signal for almost any signal source. Before you get to the precise technique of how you are going to count the signal, you had better know what the signal is going to look like.

-Tony

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Spamiam,
If you are making your readings with a 1 second time base, you may see a +/- 1 error at the lower end of your RPM range. Extend your measurement period out to 10s and this will reduce this error. The other option is to make a revolution produce multiple pulses and divide by the number of pulses per revolution. The last option would be to measure the duration of a pulse created by some sort of cam on the motor.

All of these solutions will be complicated by any noise generated by the motor.

Good luck,

A

AVR Studio 4 Ver. 4.18 684
avr-gcc Ver. 4.3.0
ISIS 7
ELECTRA

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If this is a vehicle engin, then "max RPM" might be 3000 and certainly your system must be set up to handle that. But typical might be 1200 RPM or 600 RPM, and you want good readings at the typical.

As 1200 RPM is 20 RPS, and 600 RPM is 10 RPS, you can see that even if you are "perfect" the readings will be quite coarse if your counting mechanism has one edge per revolution. (Is it)?

Also, as mentioned, whether a vehicle engine or an electric motor the signal is likely to be quite noisy without filtering. Is it squeaky-clean on your 'scope?

So, are you satisfied with +/- 10% at 600 RPM? It sounds like the answer is "no".

You can gain a bit of resolution at the expense of update rate by gathering n samples into a circular buffer and using the average. But it will still be small numbers and quite coarse.

I agree with the alternative: Use ICP and time each cycle. Some averaging may be useful--e.g., add together all the times for a fraction of a second, count the number, and use the average for display update.

I have a couple production apps where I route the signal to both the Tn and ICPn pins, and decide which range to use based on the observed signal.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Rounding may help some:

rpm = (1/temp)*60 + 0.5f; 

C: i = "told you so";

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I would hope that there will be a simple way to get multiple edges per revolution. The OP has not said what type of engine this is, nor what he plans on using as the rotation sensor.

Regular modern car engines will have something like the crank angle sensor which will have multiple edges, often with a skip at TDC of #1 cylinder. That might be a good signal source.

On older engines, you might use an inductive pickup on a spark plug wire. This would give 1 edge for every 2 rotations. If you have access to the coil, then you can measure measure off the negative side of the coil. You would get N/2 edges per revolution where N is the number of cylinders.

Most likely signal conditioning is going to be a necessity to prevent damage to the AVR.

If you use the coil, then you could use a comparator comparing the negative side of the coil to 6 volts (assuming a 12 volt electrical system). The output of the comparator can be pulled up to VCC of the AVR. The comparator can have a little feedback to give a schmitt trigger effect and improve noise immunity. The inputs to the comparator can be low-pass filtered to reduce sensitivity to transients and ringing.

This sort of signal conditioning can be applied to a variety of signal sources.

-Tony

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

The OP has not said what type of engine this is, nor what he plans on using as the rotation sensor.

Do we know whether it is an "engine" or a "motor"?

While multiple edges per revolution may be nice, at moderate speeds--say, anything over 4rps/240rpm-- and a 1/4 second update rate can give you exact speed with one edge per revolution, and no loss of accuracy or display rate. This is using the input-capture facility of the AVR. It is a fairly simple app.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Considering the op specified "motor" and the max rpm is 3000 I would think it is unlikely to be an engine.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

CirMicro wrote:
Considering the op specified "motor" and the max rpm is 3000 I would think it is unlikely to be an engine.

Good point. I was a little mystified by that, but assuming that the OP is referring to an electric motor makes lots of sense. Of course it opens up a variety of tach techniques specific to electric motors.

-Tony

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
If this is a vehicle engin, then "max RPM" might be 3000
For a Ferrari??

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Considering the op specified "motor" and the max rpm is 3000 I would think it is unlikely to be an engine.


Not for us old farm boys. 1700RPM at full-throttle back when I was your age.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Use the inverse of your reading.

If you have a timer running at 1MHz and a motor running at 600 rpm (10Hz) Then each time you detect an full revolution of the motor you have a number in the range of 100000 to play with.
That's an deviation of 10ppm ( 0.001%)

Is that good enough?

Gr, P.

Paul van der Hoeven.
Bunch of old projects with AVR's:
http://www.hoevendesign.com