NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Support Forum » Calculating RPM

January 04, 2011
by Ralphxyz
Ralphxyz's Avatar

Would someone please put me out of my misery.

I think I am suffering from the Age virus.

I have been working on this for the past two weeks but I just can not comprehend how to get pulses per minute from a pulse stream. I have a good handle on doing a interrupt and getting a pulse count but how do I put that together with a timer?

I have a pulse program that uses the tempsensor program using a pot in place of the LM34 temp sensor to give variable pulse count. The temp_sensor reading is used to time a pulse on a output pin which then goes to a counter pin.

/*
 PIN DEFINITIONS:
 PC0 -- Pot 0 - 5 volts input that varies a voltage on PIN23 PC0
 PB4 -- 50ms Pulsed output Pin18
 PB0 -- ICP1 Counter/Timer1 Input Capture Unit Pin14  
//*/

I am using ICP1 (PB0) for pulse counter (Input Capture Unit).

I have also done this using a Pin Change Interrupt but I am still lost.

Using the ICP1 Input Capture, I "should" not need to use any debounce code as it is handled by the mcu.

I have to use a ATmel Dragon to do the programing as the bootloader does not allow me use PB0 as a input. I compile the program using the Nerdkit and then load the .hex with the Dragon.

If you would like to see the code which is interesting as it has the tempsensor making variable pulse timing, the RTC and the input capture functions working. So it makes a good simulator for a pulsing project (I think).

So I have the variable pulse representing a revolution now how would I get the number of revolutions (pulses) in a minute?

This is for my anemometer project.

Thanks,

Ralph

January 04, 2011
by mongo
mongo's Avatar

It might be easier to time the pulse to pulse duration instead. The shorter the duration, the faster the speed. Read it every two cycles and it updates every other revolution. Let me think on the formula but it's all mathematics.

Kind of like figuring your pulse rate from just a few beets.

January 05, 2011
by Ralphxyz
Ralphxyz's Avatar

Thanks Mongo, "It might be easier to time the pulse to pulse duration instead."

Instead of what?

It's the time period I am having problems with, at least that is what I think I am having problems with.

I know how to start a timer and I know how to initiate a interrupt on overflow or reaching a clock tick count (MAX).

But how do I see the number of pulses during that period?

I know this is going to be obvious but I just do not see it.

Ralph

January 05, 2011
by bretm
bretm's Avatar

Just count either the rising or falling edges. Keep sampling the pin, and if the previous sample was "low" and the new sample is "high", that's a rising edge. The number of rising edges equals the number of pulses. The sampling period should be at least double the sample rate divided by the duty cycle to be sure you don't miss any pulses.

If you're sampling F times per second, the number of samples is N, the number of edges (pulses) is P, and the number of pulses per rotation is K, the RPM is (60 * P * F) / (K * N).

      rotations   rotations   pulses   samples   seconds
RPM = --------- = --------- * ------ * ------- * -------
       minute       pulse     sample   second    minute

                      1         P
                =    ---    *  ---   *   F     *   60
                      K         N
January 05, 2011
by Ralphxyz
Ralphxyz's Avatar

Thanks for the response bretm, but how would I sample F times per second?

How do I capture the number of pulses per second?

I have the Real Time Clock program running in my code.

Ralph

January 05, 2011
by bretm
bretm's Avatar

Your code is running the interrupt at 100 times per second, so F is 100.

You don't need pulses per second, you just need the count of the pulses, and the count of the seconds (it's the number of times your interrupt runs, divided by 100). It goes something like this:

volatile uint32_t N = 0;  // count of samples
volatile uint32_t P = 0;  // count of pulses (samples with rising edges)
volatile char oldSample;

ISR(TIMER0_COMPA_vect)
{
    N++;
    char newSample = PINB & (1<<PB0);  // or whatever pin you're using
    if (oldSample == 0 && newSample != 0)
        P++;
    oldSample = newSample;
}

That gives you N and P. F and K are constants. (If you get one pulse per rotation, K is 1).

N will overflow after 497 days in case that's an issue.

January 05, 2011
by mongo
mongo's Avatar

Here is how I would envision it...

First positive rise of the pulse, start the counter. Count clock cycles until the next positive rise in the pulse. This gives you a number of clock cycles per the pulse cycle. Say the pulse is 1 second from start of 1 to start of 2. At 14 million clock cycles, your count would divide by 14 million times 60. (I think), which would be 60 RPM. Just as if it only took 7 million counts to do one rev, it would work out to 120 RPM. So, the math would look like this:

 T=14000000 (clock freq)
 C=counts per input cycle. One input cycle per rev.

 RPM=T/C*60

The third positive swing would just reset the counter and wait until the next positive pulse and start over. The display would update every 2 revs or so.

January 06, 2011
by Ralphxyz
Ralphxyz's Avatar

Thanks to the input I think I now can really get dangerous and try some Pseudocode to illustrate my problems/questions.

Pseudocode RPM simulator
variables are denoted in <...>

Step1   Start Pulse Counter <pulse>
            <pulse++>

In Main()
    Step2   -----Start Timer
            |
          10sec     Accumulate <pulse> as <count> 
            |  
    Step3   -----Stop Timer
    Step4 Send <count> to LCD
    Step5 Reset <count> to 0

    Loop to Step2 Start Timer

Here are my problems/questions:

1. <pulse> will continuly incremate until it overflows.

   What does that mean? Will it just reset to 0?
   What Type should pulse be?

2. How would I accumulate <pulse> as <count> starting from 0 each time?

   <pulse> is always incremating but I want the <count> number of the increments 
   not the accumulated value of <pulse> just the number of pulses.

2. How do I Stop a timer after 10 seconds?

   What triggers Stop Timer (Step3)

Thanks again,

Ralph

January 06, 2011
by bretm
bretm's Avatar

A signed value like a int32_t will overflow to a large negative number. An unsigned value like a uint32_t will overflow to 0. But uint32_t can go up to about 4 billion. That's a really huge number. Even if you get 1000 pulses per second it won't overflow for over 46 days.

Do you really want to wait 10 seconds for your answer?

Here's my psuedo-code, assuming one pulse equals one rotation which seems like it might be the case here. This is mongo's approach but with one result for each rotation so you may want to average a few of them together.

volatile uint32_t overflows;
volatile uint32_t ticks;
volatile char waiting;

ISR(timer1 input capture vect)
{
    ticks = ISR1 | (overflows << 16);
    waiting = 0;
}

ISR(timer1 overflow vect)
{
    overflows++;
}

main()
{
    overflows = 0;
    TCNT1 = 0;
    set up input capture to watch rising edges
    set up timer with clk/k prescale
    uint32_t ticksPerMinute = (60 * F_CPU) / k;
    sei();

    // wait for first event
    waiting = 1;
    while(waiting) 
        ;

    // capture first value
    cli();
    uint32_t previousTicks = ticks;
    sei();

    while (1)
    {
        // wait for next event (one full rotation)
        waiting = 1;
        while(waiting)
            ;

        // grab next value
        cli();
        uint32_t nextTicks = ticks;

        // handle overflow (about 38 minutes when k=8)
        if (overflows > 0xFF00)
        {
            overflows -= 0xFF00;
            previousTicks -= 0xFF000000;
            nextTicks -= 0xFF000000;
        }
        sei();

        // calculate results
        uint32_t ticksPerRotation = nextTicks - previousTicks;
        previousTicks = nextTicks;
        uint32_t rpm = ticksPerMinute / ticksPerRotation;
        display rpm
    }
}
January 06, 2011
by Ralphxyz
Ralphxyz's Avatar

Thanks bretm, that is just what I was looking for. For some reason the logic of what I am trying to do kept escaping me, that darn Age virus I am sure.

Which of course means everything was getting harder to fathom. Thanks to you and mongo I was starting to think clearer and now with your psuedo-code I"should" be able to move on.

Of course I reserve the right to return with more questions.

The timing is arbitrary I probable will go for a 1 second period I will have to see what a 5 mph wind produces in RPMs.

Actually knowing the circumference of my anemometer I should be able to predict the number of revolutions at 1/3 efficiency.

Thanks again, I really appreciate and need the help.

Ralph

Post a Reply

Please log in to post a reply.

Did you know that the microcontroller's crystal oscillator can be used to keep accurate time? Learn more...