Arduino Micro: RPM counter goes to 0 after 30 seconds and won't move

I built a small centrifuge and I’m trying to count the RPMs using an E18-D80NK IR sensor. It’s connected to pin 2 of an Arduino Micro which is interrupt 1. I got the RPM code from the arduino.cc site (http://playground.arduino.cc/Main/ReadingRPM). It should count the interrupts and then calculate the RPM.

My issue is that after about 30 seconds or so, my RPM value goes to 0 and stays there and I have no idea why. It should keep showing the RPM value indefinitely.
If I don’t spin it, and let the RPM remain at 0, then try to run it after 30 seconds or so, it stays at 0

Once it goes to 0, it will always stay at 0 until I do a reset of the arduino micro.

Also, if I stop spinning it before it does the perma-0 thing, it stays at the last value instead of going to 0 like it should.

How can I fix this please?

//code for the OLED display
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define OLED_DC 11
#define OLED_CS 12
#define OLED_CLK 10
#define OLED_MOSI 9
#define OLED_RESET 13
Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);

#define NUMFLAKES 10
#define XPOS 0
#define YPOS 1
#define DELTAY 2

#define LOGO16_GLCD_HEIGHT 16 
#define LOGO16_GLCD_WIDTH  16 
static unsigned char PROGMEM logo16_glcd_bmp[] =
{ B00000000, B11000000,
  B00000001, B11000000,
  B00000001, B11000000,
  B00000011, B11100000,
  B11110011, B11100000,
  B11111110, B11111000,
  B01111110, B11111111,
  B00110011, B10011111,
  B00011111, B11111100,
  B00001101, B01110000,
  B00011011, B10100000,
  B00111111, B11100000,
  B00111111, B11110000,
  B01111100, B11110000,
  B01110000, B01110000,
  B00000000, B00110000 };

//variables for rpm counting
int rpmcount = 0;  
int timeold =0;
int rpm;

unsigned int potPin = 8;    // select the input pin for the potentiometer
int val = 0;                // variable to store the value coming from the sensor
unsigned int btnpin = 3;    // pin for the set button
int setval = 0;             // set value variable
int spd= 0;                 // spd var for motor control function
unsigned int button_push = 5; // Set button value high
unsigned int delta = 0;     // var for difference between actual and desired rpm

// OLED code
#if (SSD1306_LCDHEIGHT != 64)
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif

//diabled speed control until rpm error is figured out
/*
int motor_cont(int spd)
{
  int delta2 = spd - rpm;
  delta = abs(delta2);
  
  if (rpm < spd){
    val = val ++;
  }
  
  if (rpm > spd){
    val = val --;
  }
  
  if (setval < 10){
    val = 0;
  }
  
  if (val < 0){
    val = 0;
  }
  delay(100);
  return val;
}
*/

// function for rpm calculation
void rpm_fun()
 {
   rpmcount++;
   //Each rotation, this interrupt function is run twice
 }
 
void setup()   { 
  
 attachInterrupt(1, rpm_fun, FALLING); // IR signal wire connected to pin 2 which is interrupt 1, int caused on going from +5 to 0v
   rpmcount = 0; // initializing rpm variables
   rpm = 0;
   timeold = 0;
   
  //button stuff disabled until rpm problem resolved 
  //pinMode(btnpin, INPUT);      //Set pin 3 as input for the button 
  //digitalWrite(btnpin, HIGH);  //Enable pull up resistor for button input
  
  digitalWrite(2, HIGH);       //Enable pull up resistors for IR sensor input
  
  //output for L298N motor control
  pinMode(5, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(6, OUTPUT);
  
 
  // OLED code  
  // by default, we'll generate the high voltage from the 3.3v line internally! (neat!)
  display.begin(SSD1306_SWITCHCAPVCC);
  // init done
  display.display(); // show splashscreen
  delay(1000);
  display.clearDisplay();   // clears the screen and buffer
}

void loop() {

// RPM calculator
if (rpmcount >= 20) { 
     //Update RPM every 20 counts, increase this for better RPM resolution,
     //decrease for faster update
     rpm = 30*1000/(millis() - timeold)*rpmcount;
     timeold = millis();
     rpmcount = 0;
}

 // g force calculation disabled until rpm issue resolved
 //unsigned int Gs = 1.12 * 125 * rpm/1000 * rpm/1000;

 // code to display data to OLED
 display.setTextSize(1);
 display.setTextColor(WHITE);
 display.setCursor(0,0);
 display.println("Centrifuge 2.0 by"); 
 display.println("David Dominguez");
 display.println();
 display.print("Desired RPM: ");
 display.setTextSize(1);
 display.println(setval);
 display.setTextSize(1);
 display.print("Set RPM:     ");
 display.setTextSize(1);
 display.println(spd);
 display.setTextSize(1);
 display.print("PWM Value:   ");
 display.println(val);
 display.print("Actual RPM:  ");
 display.println(rpm);
 display.print("G-Force:     ");
 //display.print(Gs);
 display.display();
 display.clearDisplay();   // clears the screen and buffer 
 
 setval = analogRead(potPin);    // read the value from the sensor
 
 /*button_push = digitalRead(btnpin);
 if (button_push < 1){
   spd = setval;
 }
 
 val = motor_cont(spd); 
 */
  
 //Motor control
 analogWrite(6, setval/4);
 digitalWrite(5, LOW);
 digitalWrite(4, HIGH);
}

timeold is an int.
Make it unsigned long.
(32.767 seconds)

That did it!

Thanks :slight_smile:

int rpmcount = 0;  

void rpm_fun()
 {
   rpmcount++;
   //Each rotation, this interrupt function is run twice
 }

void loop() {

// RPM calculator
if (rpmcount >= 20) {

Variables used in interrupt service routines AND other functions, as rpmcount is, need to be volatile.