I am building a cycle computer and have run into an odd problem.
There is a reed switch on the bike that makes contact when a magnet on the spokes passes it. The reed switch fires an interrupt that notes down the time and increments a counter. Outside the interrupt the RPM is counted by dividing the number of revolutions (ticks) that have occurred by the time (millis) taken. This means the main program can go off and do some time consuming task and get an average of the RPM when it gets back.
The problem is the first time the sketch runs after power up or reset the value in the counter is often (but not always) 1 when it was declared as 0. It would appear the interrupt is firing when it is attached or a few ms after. I don't understand why? I enable the internal pullup resistor and set the interrupt for falling before attaching it.
If I pull the code out into it's own sketch it works perfectly, first time through the rpms are zero as they should be. If it is included in the rest of my cycle computer sketch the RPMs are not zero first time through.
Is it normal for interrupts to fire when first attached? Do interrupts not play nicely with pullup resistors? Have I done something else stupid in my code?
These compile and can be used for testing. Connect pin 3 to ground to simulate a wheel spining
This one works.
#include <Wire.h>
//Various I/O pins. Listed here to keep track of them. Uncomment as requred.
#define pinTacho 2 //2 interrupt 0, tacho RPM sensor
#define pinWheel 3 //3 interrupt 1, wheel RPM sensor
//Variables and stuff
int speedNow = 0; //the bike's speed
int tachoRPM = 0; //the tacho (engine RPM)
unsigned long wheelRPM = 0; //the tacho (engine RPM)
int wheelMinRPM = 1; //constant to add to the RPM so we never show the ratio as 1:0 //read this from the SD card
int wheelCirc = 2000; //circumference of the wheel where the speed is measured, in millimeters.
volatile unsigned long wheelMillisCurrent = 1; //time of this wheel tick. May need to use micros() if millis isn't fast enough
unsigned long wheelMillisPrevious = 0; //time of last wheel tick. May need to use micros() if millis isn't fast enough
volatile unsigned long wheelTickCurrent = 0; //this wheel tick number
unsigned long wheelTickPrevious = 0; //last wheel tick number
unsigned long wheelTickCount = 0; //increments each time the wheel rotates
unsigned long wheelRPMTemp = 0;
unsigned long wheelRPMTemp1 = 0;
unsigned long wheelRPMTemp2 = 0;
unsigned long wheelRPMTemp3 = 0;
unsigned long wheelRPMTemp4 = 0;
unsigned long speedTemp1 = 0;
unsigned long speedTemp2 = 0;
unsigned long speedTemp3 = 0;
unsigned long wheelTickDifference = 0;
unsigned long wheelMillisDifference = 0;
/***** Setup ************************************************************
Setup the Arduino
************************************************************************/
void setup() {
// Debug
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
//Debug end
//setup various I/O pins
pinMode(pinWheel, INPUT_PULLUP); // Wheel RPM, int0. Enable internal pullup resistor
//setup interrupts
delay(1000);
attachInterrupt(1, wheelUpdate, FALLING); //interrupt 1 uses pin 3. Wheel RPM sensor must be on this input for speed measurement
}
/***** loop() ************************************************************
Main pogram loop
************************************************************************/
void loop() {
//Calculate the wheel RPM - Method 1, split it into bits so we don't accidentally overflow .
//Wheel RPM. Revs = ticks/millisec * 1000 = ticks /sec * 60 sec = ticks/min = rev/min
wheelTickDifference = wheelTickCurrent - wheelTickPrevious;
Serial.print(" wheelTickDifference ");
Serial.print(wheelTickDifference);
/**** HELP, Lines above: First time through this gives wheelTickDifference == 0 as it should ***/
wheelMillisDifference = wheelMillisCurrent - wheelMillisPrevious;
Serial.print(" wheelMillisDifference ");
Serial.print(wheelMillisDifference);
wheelRPMTemp = ((wheelTickDifference) * 1000 * 60) / (wheelMillisDifference+1); //add 1 so we don't divide by zero
Serial.print(" wheelRPMTemp ");
Serial.print(wheelRPMTemp);
//Calculate the wheel RPM - Method 2, All in one line, we could accidentally overflow .
wheelRPMTemp1 = ((wheelTickCurrent - wheelTickPrevious) *1000 *60) / (wheelMillisCurrent - wheelMillisPrevious+1);
Serial.print(" wheelRPMTemp1 ");
Serial.println(wheelRPMTemp1);
/**** HELP, Lines above: First time through this gives wheelTickDifference == 0 as it should ***/
//Turn the current variables into previous
wheelTickPrevious = wheelTickCurrent;
wheelMillisPrevious = wheelMillisCurrent;
//may need to add a delay in here so we don't try to update the screen too fast.
delay(1000);
}
/**** Interrupts ********************************************************
* We may be busy doing something else when the tick occurs and miss several ticks.
* Use TickCount to tell how many ticks have occured since we last took the difference in millis
************************************************************************/
/***** Wheel ***********************************************************
update the wheel RPM reading
The wheel sensor fired, grab the time and increment the wheel ticks.
***********************************************************************/
void wheelUpdate(){
wheelMillisCurrent = millis(); //wheel rotated, note the time
wheelTickCurrent++; //increments each time the wheel rotates
}
The attached one gives funny rpm readings on first run. (It's too big to post the code, I think).
ScooterPuterMini.ino (39.2 KB)