How can I get a zero speed (zero rpm) reading from an interrupt

Hello Arduinoers,

I am attempting to create a bicycle light from a neopixel strip where the lightpattern is controlled by the bike speed. When the bike is not moving, a new light pattern should take over.
The sensor I'm using is a hall effect.
Speed reading works just fine, but when the bike stops, there are no more triggers and the speed stays as the last recorded.
I am struggling to get a "reading" of 0 k/ph, but of course the interrupt only triggers when there is movement.

Here is a bare bones version of the code. I had to clean up a lot of mess, so without the attemps of a 0-reading:

/*
NeoPixel strip PIN6.
Hall effect sensor attached to PIN2
*/
//#include <LiquidCrystal.h>
#include <Adafruit_NeoPixel.h>


#define CHANGE 1
#define FALLING 2
#define RISING 3
#define PIN 6 //Attach NeoPixel strip
#define NUM_PIXELS  24
//const int hallpin = 2;
//int hallState = 0;

Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_PIXELS, PIN, NEO_GRB + NEO_KHZ800);


unsigned long start, finished;
unsigned long elapsed, time;
float circ = 2.00; // wheel circumference (meters)
float speedkph;
float mps;
float LEDspeed;
float gap;
const int debounce = 100;  // debounce milliseconds


void setup() {
  attachInterrupt(0, speedCalc, RISING); // interrupt called when rising edge is detected on digital pin 3
  start = millis();
  Serial.begin(9600);
  strip.begin();
  strip.show();// Initialize all pixels to 'off'
  delay(2000);
}

void speedCalc() {
  unsigned long now = millis();
  if (digitalRead(0) == HIGH) // check if the pin is really high
  {
    if (now - start > debounce)
    {
      elapsed = now - start;
      start = now;
      speedkph = (3600 * circ) / elapsed; // kph
      mps = (speedkph * 0.28); //calculates meters per second from kph
      LEDspeed = (33.33 / mps); //calculates milliseconds between LEDs
      gap = (1000 / mps); //spacing between LED chases
    }
  }
  Serial.print("speedkph: ");
  Serial.println(speedkph);
}


void loop() {

  if (speedkph > 0) {
    for (int led = 24; led >= 0; led--) {
      strip.setPixelColor(led, 0, 0, 180);
      strip.show();
      delay(LEDspeed);
    }

    delay(gap);

    for (int led = 24; led >= 0; led--) {
      strip.setPixelColor(led, 0, 0, 0);
      strip.show();
      delay(LEDspeed);
    }
  }
  if (speedkph == 0) {
    //new light pattern
  }
}

Is there any way for the interrupt to generate 0 k/ph? I have tried with:

if (elapsed > 2000) {
speedkph = 0;

...both within the interrupt and in the loop, but to no avail.

I assume, it is best to keep this outside of the main loop, for it to run smoothly.

So to keep this short, I humbly ask for ideas or suggestions (or the need to clarify).

Thanks for reading and for any help!

Change

 if (speedkph == 0) {

to:

if (millis() - start > 2000) {

This will mean that no interrupt in longer than 2000 ms is considered stopped.

Also, I think you need to spend some time studying http://www.arduino.cc/en/Reference/AttachInterrupt, especially:

You should declare as volatile any variables that you modify within the attached function.

Generally, an ISR should be as short and fast as possible.

I think you answered your own question, really.

The interrupt really does just that: it interrupts whatever is happening in the main loop() method.

So if your main loop method constantly asks the question: has an interrupt event occurred within the last X milliseconds (using the example pert gave you) then do nothing, as the light pattern has been changed.

If the answer was no, nothing has happened for X milliseconds, then you know that you need to change the light pattern as the bike is stopped.

That all said, the interrupt routine should do not more than flag whether the bike is moving or not - let the main loop() method work out what needs to be done as a result of that. As pert has already mentioned you want to do as little as possible in your ISR - and no delays or serial.prints or anything like that.

Hello pert and Ralph_S_Bacon!

Thank you for your fast replies. Yes, I needed to do some reading up on the AttachInterrupt!
I had been looking through various examples on the web, but I hadn't latched onto the volatile declaration. You nudged me on to my merry way to illumination!

And of course this solved the 0 kph issue:

if (millis() - start > 2000) {

With the volatiles added, and serial.prints moved to the main loop, it works like a charm:

#include <Adafruit_NeoPixel.h>


#define CHANGE 1
#define FALLING 2
#define RISING 3
#define PIN 6 //Attach NeoPixel strip
#define NUM_PIXELS  24


Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_PIXELS, PIN, NEO_GRB + NEO_KHZ800);


unsigned long start, finished;
unsigned long elapsed, time;
float circ = 2.00; // wheel circumference (meters)
volatile float speedkph;
float mps;
volatile float LEDspeed;
volatile float gap;
const int debounce = 100;  // debounce milliseconds


void setup() {
  attachInterrupt(0, speedCalc, RISING); // interrupt called when rising edge is detected on digital pin 3
  start = millis();
  Serial.begin(9600);
  strip.begin();
  strip.show();// Initialize all pixels to 'off'
  delay(2000);
}

void speedCalc() {
  unsigned long now = millis();
  if (digitalRead(0) == HIGH) // check if the pin is really high
  {
    if (now - start > debounce)
    {
      elapsed = now - start;
      start = now;
      speedkph = (3600 * circ) / elapsed; // kph
      mps = (speedkph * 0.28); //calculates meters per second from kph
      LEDspeed = (33.33 / mps); //calculates milliseconds between LEDs
      gap = (1000 / mps); //spacing between LED chases
    }
  }
}



void loop() {

  if (speedkph > 0) {
    for (int led = 24; led >= 0; led--) {
      strip.setPixelColor(led, 0, 0, 180);
      strip.show();
      delay(LEDspeed);
    }

    delay(gap);

    for (int led = 24; led >= 0; led--) {
      strip.setPixelColor(led, 0, 0, 0);
      strip.show();
      delay(LEDspeed);
    }
  }
  if (millis() - start > 2000) {
    //new light pattern
    }
  }
Serial.print("speedkph: ");
Serial.println(speedkph);
}

Thanks for your help!