rpm sensing with proximity sensor

Alimoestar_S_K:
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
pinMode(interruptPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(interruptPin), blink, HIGH);
/* CHANGE to trigger the interrupt whenever the pin changes value

  • LOW to trigger the interrupt whenever the pin is low,
  • RISING to trigger when the pin goes from low to high,
  • FALLING for when the pin goes from high to low.The Due, Zero and MKR1000 boards allows also:
  • HIGH to trigger the interrupt whenever the pin is high.
    */
    Serial.begin(9600);

}

Hello there!

The first thing that strikes me as odd is that you have the interrupt pin set as INPUT_PULLUP, which leads me to believe that your sensor pulls the pin low when it sees the metal bolt. Your interrupt is set to run the ISR when the pin is high. Since the pin is set at INPUT_PULLUP, the ISR is going to continuously run when the sensor does not see the bolt, seeing as how the pin is always high (except for the metal bolt). Try changing the interrupt event so that it triggers the ISR during a FALLING edge, instead of HIGH.

  attachInterrupt(digitalPinToInterrupt(interruptPin), blink, HIGH);

The valid modes are RISING, FALLING, CHANGE, and LOW. HIGH is nowhere in that list.

PaulS:
The valid modes are RISING, FALLING, CHANGE, and LOW. HIGH is nowhere in that list.

Here is a snippet from the Arduino Reference page for attachInterrupt(). It clearly says that HIGH is on the list. Additionally, if HIGH wasn't allowed, wouldn't the compiler throw an error?

Additionally, if HIGH wasn't allowed, wouldn't the compiler throw an error?

The compiler would throw an error if you tried to use "SamIsAnIdiot" as the argument. You are free to use values of the correct type, but not that the function expects, and the compiler will let you.

I see. You say that HIGH is not a valid argument input, but yet is it on the reference snippet I posted. Any explanations?

bos1714:
I see. You say that HIGH is not a valid argument input, but yet is it on the reference snippet I posted. Any explanations?

Other than that it doesn't make sense? Why would you want to trigger an interrupt continually when a pin was HIGH or LOW?

Interrupts are to handle changes from outside the microcontroller.

(LOW has a valid use in waking from sleep mode)

Here is a snippet from the Arduino Reference page for attachInterrupt(). It clearly says that HIGH is on the list.

You are correct about this, but there is more to consider. Did you see this line about the Due, Zero, and MKR1000 boards right before the listing of HIGH

The Due, Zero and MKR1000 boards allows also:
HIGH: to trigger the interrupt whenever the pin is HIGH

What Arduino do you have?

In the AT328 Arduinos the external interrupt mode HIGH is actually treated the same as CHANGE.

Arduino.h defines HIGH as 1 and LOW as 0. It also defines CHANGE as 1, FALLING as 2 and RISING as 3.

The attachInterrupt() function (defined in WInterrupts.c) just does an entry of that value into the External Interrupt Control Register A (EICRA) for interrupt sense control. The only values which fit into the two control bits of that register are 0 through 3.

Table 12-1. Interrupt 1 Sense Control
ISC11 ISC10 Description
0 0 The low level of INT1 generates an interrupt request.
0 1 Any logical change on INT1 generates an interrupt request.
1 0 The falling edge of INT1 generates an interrupt request.
1 1 The rising edge of INT1 generates an interrupt request.

Please elaborate on what your program is doing. "no luck" is not a very good problem statement.

dear all,

i have changed the code a little. the idea is now to measure the time between 2 pulses (1 bolt passes the sensr twice, thus 1 full rotation of the axis) and calculate the rpm. measurements happens in microseconds.

const byte interruptPin = 2;
volatile byte state = LOW;
float n=0;
float RPM = 0;
unsigned long previoustime = 0;


void setup() {
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), blink, FALLING);
  /* CHANGE to trigger the interrupt whenever the pin changes value
      LOW to trigger the interrupt whenever the pin is low,
      RISING to trigger when the pin goes from low to high,
      FALLING for when the pin goes from high to low.The Due, Zero and MKR1000 boards allows also:
      HIGH to trigger the interrupt whenever the pin is high.
  */


}
void loop() {

  digitalWrite(LED_BUILTIN, state);
}


void blink() {
  state = !state;
  if (digitalRead(LED_BUILTIN  == FALLING))
  {n++;
  }
  Serial.print("number of detections : ");
  Serial.print(n);
  
  if (n == 2){
     unsigned long currenttime = micros();
     RPM = (((float) 1.00 / (float)(currenttime - previoustime)) * (float) 60000000.00);
     currenttime = previoustime;
     n=0;
  }
      
    Serial.print("         RPM :   ");
    Serial.println(RPM);

  }

but what happens in serial monitor is that the rpm value keeps dropping till reaches zero.But motor speed is constant.

help please.

dear all,

im working with a inductive proximity sensor and want to measure the time between 2 interupts of this sensor.

this is my code, which for some reason keeps dropping till reaches zero

//15 augustus 2018
// Alimoestar S.K.

const byte interruptPin = 2;
volatile byte state = LOW;
float n=0;
float Time = 0;


void setup() {
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), blink, FALLING);
  /* CHANGE to trigger the interrupt whenever the pin changes value
      LOW to trigger the interrupt whenever the pin is low,
      RISING to trigger when the pin goes from low to high,
      FALLING for when the pin goes from high to low.The Due, Zero and MKR1000 boards allows also:
      HIGH to trigger the interrupt whenever the pin is high.
  */


}
void loop() {

  digitalWrite(LED_BUILTIN, state);
}


void blink() {
  state = !state;
  if (digitalRead(LED_BUILTIN  == FALLING))
  {unsigned long previoustime= micros();
    n++;
  
  Serial.print("number of detections : ");
  Serial.print(n);
  
   
  if (n == 2){
     unsigned long currenttime = micros();
     Time=(float)(currenttime - previoustime);
        currenttime = previoustime;
     n=1;
  }
  }
 
 
       
    Serial.print("         RPM :   ");
    Serial.println(RPM);

  }

any idea's???
thank you in advance

Don't do serial I/O in interrupt context.

keeps dropping till reaches zero

I don't know what that means.

digitalRead(LED_BUILTIN  == FALLING)Oops

dear awol,

when i say keep dropping till reaches zero, i meant that the value printed on the serial monitor was decreasing till it reached zero.

i've recently found out that i made an error in

 currenttime = previoustime;
// it should be the other way around
previoustime = currenttime;

since fixing this, no more decreasing till zero

AWOL:
Don't do serial I/O in interrupt context.

should i put this in the loop, like this? or do you suggest a different way?

//15 augustus 2018
// Alimoestar S.K.

const byte interruptPin = 2;
volatile byte state = LOW;
float n=0;
float Time = 0;


void setup() {
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), blink, FALLING);
  /* CHANGE to trigger the interrupt whenever the pin changes value
      LOW to trigger the interrupt whenever the pin is low,
      RISING to trigger when the pin goes from low to high,
      FALLING for when the pin goes from high to low.The Due, Zero and MKR1000 boards allows also:
      HIGH to trigger the interrupt whenever the pin is high.
  */


}


void blink() {
  state = !state;
  if (digitalRead(LED_BUILTIN  == FALLING))
  {unsigned long previoustime= micros();
    n++;
  
  Serial.print("number of detections : ");
  Serial.print(n);
  
   
  if (n == 2){
     unsigned long currenttime = micros();
     Time=(float)(currenttime - previoustime);
        previoustime = currenttime;
     n=1;
  }
  }
  }
 
 void loop() {

  digitalWrite(LED_BUILTIN, state);

       
    Serial.print("         RPM :   ");
    Serial.println(RPM);

  }

if (digitalRead(LED_BUILTIN  == FALLING))Still oops.

  attachInterrupt(digitalPinToInterrupt(interruptPin), blink, FALLING);

That is a stupid name for the function to call. Nothing is blinking...

  if (digitalRead(LED_BUILTIN  == FALLING))

Work out, on paper, EXACTLY which pin you are reading from. It is NOT the pin you want to read from.

There is NO need to read the state of an output pin. Keep track of the state you set it to.

Regardless, the state of the LED pin has NOTHING to do with the time that the sensor (assuming that it is indeed connected to pin 2) triggered the interrupt.

Your code is, as currently written, complete nonsense.

dear all,

i've taken all coments and advise into consideration. did some extra reading and came up with the following.

/* Alimoestar S.K.
 *  original code may 2018
 *  16 aug 2018 revised 
 *  coments and advise from arduino forum toopic :rpm sensing with proximity sensor
 * 
  */

const byte interruptPin = 2;
volatile long n=0;
volatile long RPM=0;
volatile boolean flag=0;
long RPMperiod;
unsigned long previoustime=0;


void setup()
{
  Serial.begin(9600);
  attachInterrupt(digitalPinToInterrupt(interruptPin), sensor, FALLING);

}

void loop()
{
    if(flag)
  {
    RPM=(60000000UL/RPMperiod);   //One (1) signal per rotation.
    interrupts();
    Serial.print("RPM = ");
    Serial.println(RPM );
    flag=0;
  }
}

void sensor()
{unsigned long currenttime=micros();
  RPMperiod=float ( currenttime- previoustime);
  flag=1;
  previoustime = currenttime;

}

in the serial monitor i'm seeing my rpm value and a lot of other things.

PaulS:
Work out, on paper, EXACTLY which pin you are reading from. It is NOT the pin you want to read from.

the pin i am reading from is pin 2 on the arduino uno R3, which has interrupts for pin 2 and 3.

PaulS:
There is NO need to read the state of an output pin. Keep track of the state you set it to.

so in other words leave out the write state to build in led and try something else?
will a flag function work?

the pin i am reading from is pin 2 on the arduino uno R3, which has interrupts for pin 2 and 3.

With this code,

  if (digitalRead(LED_BUILTIN  == FALLING))

You are comparing LED_BUILTIN to FALLING, which returns true or false. Which of those values do you think is 2? Neither one is. That code is reading from pin true or pin false. Hardly a reasonable thing to do.

Even if you fix that to

  if (digitalRead(LED_BUILTIN)  == FALLING)

so that you are reading from the LED_BUILTIN pin, you are comparing HIGH or LOW to FALLING. Never will match...

dear all,

after consideration of all your comments and some extra reading and testing, i came up with the following code:

/* RPM sensing using a arduino uno
    and inductive proximity sensor
    Alimoestar S.K.
    original code may 2018
    revised 20 aug 2018
    revised 27 aug 2018
    revised 1 sep 2018

*/

//---------------------------- declaration -------------------------------
const byte interruptPin = 2;
int n = 0;
volatile long RPM = 0;
volatile long RPMsum = 0;             // sum of 20 RPM measurements
volatile long RPMav = 0;              // average of 20 RPM measurements
float F = 0.000;                      // frequency
volatile boolean flag = 0;
unsigned long DeltaT;                 // time between two interupts
unsigned long previoustime = 0;



//---------------------------- setup --------------------------------------
void setup()
{
  Serial.begin(9600);
  attachInterrupt(digitalPinToInterrupt(interruptPin), sensor, FALLING);
}

//---------------------------- ISR sensor --------------------------------
void sensor()
{ flag = 1;
}

//----------------------------- loop --------------------------------------
void loop()
{ //-----------------------------------------------------------------------rpm measurement
  if (flag)
  { noInterrupts();                                            // disables interrupt, because the folloing is time sensitive
    n++;
    unsigned long currenttime = micros();                      // measure the current time
    DeltaT = (currenttime - previoustime);                     // calculate the time difference
    previoustime = currenttime;                                // set previoustime = currenttime


    if (DeltaT >= 32000) {                                     // deltaT 32000 => rpm= +-1800 (debouncing)
      RPM = float(60000000UL / DeltaT);                        // calculate the rpm (One (1) signal per rotation)
      
      Serial.print("delta T =\t");
      Serial.print(DeltaT);
      Serial.print("\t rpm =\t");
      Serial.println(RPM );
     
      //}

      //---------------------------------------------- frequency calculation
      F = (RPMav / 2) * 60.00;
      flag = 0;
      interrupts();

    }



    // Average RPM value of 200 measurements
    RPMsum = RPMsum + RPM; // sum of 200 measurements

    if (n == 20) {
      RPMav = (RPMsum / 20); // averge of 200 measurement
      //---------------------------------------------- print to serial screen
      Serial.print("    RPM = ");
      Serial.print(RPM );
      Serial.print("    RPMav = ");
      Serial.print(RPMav );
      Serial.print("     Freq = ");
      Serial.println(F );
      RPMsum = 0;
      n = 0;

    }
  }

}//-------------------------------- end loop -----------------------------------------


//--------------------------------- end code -----------------------------------------

this seemed to work at first, but after some time gave some nonsense reading.
any thoughts or coments???

but after some time gave some nonsense reading.
any thoughts or coments

Yes. You ABSOLUTELY MUST understand what you can, and can not do, with interrupts disabled.

The ONLY thing you should be doing, while interrupts are disabled, is copying and resetting the values of the variables that the interrupt service routine(s) use.

NOT A SINGLE THING ELSE.

This is similar to my project. These comments make little sense. Watch this little video; If you can understand this simple sketch, the solution will become obvious. (use a Hall detector, not the photo module in the video. I have since learned that RPM is usually done with a Hall effect detector)