Simple RPM counter printed on the serial monitor

Hello,
before you all start to direct me to old topics, I would like to mention that I checked them all and I steel have no clue, as I am new to the programming. I have tried many different ones and nothing seems to work.

I would like to do just a simple RPM counter, collecting data from one input pin that is connected to photo-interrupter circuit, do simple math and than to print the RPM on serial monitor. Non of that LCD rubbish, that thing is just confusing me.

Can anybody please help? Please?

To measure RPM you could count pulses for a period and calculate RPM or measure the time between pulses and calculate RPM. Do you understand the difference ?

As to programming the Arduino. do you know how to read the state of an input pin and print the state on the Serial monitor ?

Thank you UKHeliBob, Yes I know how to read from an input pin and print on Serial monitor, I went through basic tutorials, and here I got stuck. I understand what you are saying, I tried to measure the time between two pulses and calculate RPM (figured it would be more precise that way?), but did not know how to actually do it, what functions to use and how. ...On every tutorial there is a LCD involved, so that got me confused also, and some of the fellas on the forum, they are explaining it with terminology I don't quite understand. Could you please help me out?

When the input becomes LOW save the value of millis() to a variable. When it becomes LOW again save the value of millis() again. Subtract one value from another and you know how many milliseconds one pulse takes which allows you to calculate how many pulses there would be in one minute

The trick is to detect when an input becomes LOW rather than when it is LOW. Look at the StateChangeDetection example in the IDE to see how to do that

Use a pullup resistor on the input pin or INPUT_PULLUP in its pinMode() ro keep the pin in a known state at all times

Your request rang a bell and I searched for a sketch I wrote a few years ago. To my surprise, I actually found it.

It did more than just calculate the rpm, and I was also surprised that I had the discipline back then to put the rpm stuff in a function of its own, so was easy to cut it out as below.

It's based on this.

You'll need to go through it and declare all the variables, of course.

YMMV, E&OE, T's & C's apply, blah blah :wink:

void getRPM()
{

  sensPinValue = digitalRead(sensPin);
  digitalWrite(sensLedPin, sensPinValue );
  if (sensPinValue != prevSensPinValue)
  {
    // just broke or cleared beam, don't know which yet
    if (sensPinValue == HIGH)
    {
      // just broke ie new rev just started
      totalRevs = totalRevs + 1;
      prevRevStartedAt = thisRevStartedAt;
      thisRevStartedAt = millis();
      if (totalRevs > 0)
      {
        //so this rev took:
        prevRevTook = thisRevStartedAt - prevRevStartedAt;

        RPM = 60000. / prevRevTook;
        Serial.print("Act RPM= ");
        Serial.println(RPM);
      }
    }
    prevSensPinValue = sensPinValue;
  }

}  // getRPM

Usage:

void loop()
{
getRPM();
}

"The trick is to detect when an input becomes LOW rather than when it is LOW. Look at the StateChangeDetection example in the IDE to see how to do that"

Thank you UKHeliBob, that helped a lot to understand the problem! Saved me from a dead end.

Thank you arduin_ologist as well, If I understand that correctly now, your code is doing just what UKHeliBob described, only it is in a separate function and you call it to the void loop with getRPM(); when you need it in your code (not sure why and how jet but that's another topic). Would it work to just place it directly into void loop() ?

Thank you both!

Yep it does pretty much what UKHB suggested.

You could indeed just stick that code in loop(), but think about how cluttered loop() may get if you have many different things to do. A nice tidy loop() could look like this:

void loop()
{
  doThingOne();
  doThingTwo();
  doThingThree();
  doAnotherThing();
  doYetAnotherThing();
}

... and all those "things" could be tucked away at the end of the sketch out of the way.

If you want to now add yetAnotherOtherThing it's easy to do that, or to take one out. Or if one part isn't working properly, you know exactly where to go to fix it, not hunt through a huuuuge long loop() to find one bad line.

Nice one, thank you for explaining it, I'll keep that in my mind for future projects:-) What I'am doing now is an electronic circuit with an Op-amp that automatically stabilize the RPM of a DC motor. So I would like to measure RPM with Arduino to be able to see if my circuit is actually working. Would I get more accurate reading with using of micros() instead of millis() in your code?

herbie87:
Nice one, thank you for explaining it, I'll keep that in my mind for future projects

The loop() in my actual sketch was:

void loop()
{
  setRPM();
  getRPM();
  adjustRPM();
} //loop

herbie87:
Would I get more accurate reading with using of micros() instead of millis() in your code?

No idea....

Sounds like nice project, maybe I'll try to do that also, after I finish this one first. Thanx
Btw, I only need 1000 - 2500 RPM accuracy.

The code in this link is derived from a program I use to control the speed of a small DC motor. It works fine for a speed range from 1500 to 15000 RPM

...R

Thank you all for your help!
I used arduin_ologist's code, I put it in a void loop and added the code (below) in front of it to declare all the variables. It is working very well, as I tested it with the simple switch and pull-down resistor for the input signal and a stopwatch. Still don't know how accurate it is on high RPM, but the code works...finally :smiley:

int sensPin = 2;
int sensPinValue;
int prevSensPinValue;
int sensLedPin;
unsigned long totalRevs;
unsigned long prevRevStartedAt;
unsigned long thisRevStartedAt;
unsigned long prevRevTook;
int RPM;

void setup() {
pinMode(sensPin, INPUT);
Serial.begin(9600);

}

I am glad to hear that you got it working but you did not

put it in a void loop

I assume that you put it in the loop() function and that function was declared not to return a value, hence it was void

UKHeliBob:
but you did not

hahaha but it works! Help me understand;
In his original post arduin_ologist started the code with: void getRPM() and than he calls that in his void loop() isn't that returning the value? and it also starts with: void ...getRPM
What does returning the value means?

A function in C is like a mathematical function...

  y = f(x)[\pre]

The value assigned to y is the value that f() calculated from its inputs. This is the[i] return[/i] value.

Functions can return integers, pointers to data or maybe just a true/false to indicate success or failure.

But you cannot insist that every function must return a value. Something like digitalWrite() can't really give you any information back. It has a [i]side effect[/i] of changing a digital output pin. loop() is another example. There is no meaningful return value.

So there is a special type of return value which says to the compiler "this function doesn't return anything." This is [i]void[/i]

But you still say a void function [i]returns[/i] because it returns control to the caller. Both types of return use the keyword [tt]return[/tt] but you can let a void function run off the end and it automatically returns. The compiler will complain if a non-void function is missing a return statement.
void getRPM()

a function named getRPM that does not return a value and does not take any parameters. It certainly changes the value of some variables and they will be available to the rest of the program if they are declared global

As to returning a value, let's use this function as an example

int multiply(int a, int b)
{
  return a * b;
}

The function promises to return an int to the calling program and takes 2 ints as parameters. You could call it like this

multiply(2, 3);

and it would multiply 2 by 3 and return the result, but the way it was called the result is thrown away. But if you did

int answer = multiply(2, 3);

then the result would be in the answer variable. Of course, the function has no need to know what you are going to do with the result or which variable you are going to assign it to so you can do

int area1 = multiply(10, 20);
int area2 = multiply(12, 15);

If you wanted just to print the result and did not want to use its value in the program you could do

Serial.println(multiply(2, 3));

Thank you both for help, and others as well! Now I'm getting somewhere with the real understanding of the structure. That's exactly what I needed at this point of my progression. Cheers! Will pass the knowledge one day :slight_smile:
PS:sorry for my bad english, I'm self-taught.