For any of you that want to see what the final code looks like here it is. Feel free to criticize at will.
volatile unsigned long period = 0; //time between pulses
volatile unsigned long prevTime = 0; //the last micros() we measured
volatile bool newMeasurementAvailable = 0;
unsigned long stablePeriod = 0; //
byte pointer = 0; //pointer to keep track of next position in array to store value
byte numPrevReadings = 0; //the number of readings to smooth, can be from 1 to 10, always starts at 1, dynamically changed based on period/RPM
unsigned long matrix[4][10] = { //initialize the array with zeros
{0,0,0,0,0,0,0,0,0,0}, //stores the pulse period
{0,0,0,0,0,0,0,0,0,0}, //stores raw rpm
{0,0,0,0,0,0,0,0,0,0}, //stores smoothed rpm of current reading and numPrevReadingss
{0,0,0,0,0,0,0,0,0,0} //not used just haven't decided if I'm going to or not
};
unsigned long total = 0;
void setup(){
pinMode(21, INPUT);
Serial.begin(9600);
attachInterrupt(digitalPinToInterrupt(2), isr, FALLING); //Interrupts are called on Rise of Input
Serial.println("Begin");
}
void loop(){
if (newMeasurementAvailable) {
noInterrupts();
stablePeriod = period;
interrupts();
storeAndProcess();
newMeasurementAvailable = 0;
int rpmd = getRPM(0) - getRPM(1); // rpm delta from the previous reading
Serial.print(" period0=");
Serial.print(getPeriod(0));
Serial.print("\t rpm=");
Serial.print(getRPM(0));
Serial.print("\t rpmd=");
Serial.print(abs(rpmd));
Serial.print("\t srpm=");
Serial.println(getSmoothedRPM(0));
}
}
void storeAndProcess() {
matrix[0][pointer] = stablePeriod; //store the period
matrix[1][pointer] = (60 * 1000000) / matrix[0][pointer]; //store the raw RPM
//The next line determines the number of previous periods to use to calculate the average. As speed increases, number of previous readings will increase to a maximum of 9.
//Using 125000 as a value below is a period of 1/8 of a second (1,000,000/125,000). This equates to 480 RPM. So up to 480 RPM it uses one reading. At every multiple
//of 480 RPM the number of values used for smoothing will increase by 1 up to 4800 RPM. With an array of 10 elements as defined in this sketch that only gives us a max
//of the current value plus the 9 previous values. The array could be defined with more than 10 elements if you wanted to change this. Additionally instead of using
//simple division as I've done you could use the map function to define the range of potential RPM's at which you want smoothing done.
numPrevReadings = 125000 / stablePeriod;
numPrevReadings = constrain(numPrevReadings, 0, 9);
total = stablePeriod; //start with the period we just measured
if (numPrevReadings != 0) {
for (int i = 0; i < numPrevReadings; i++) { //add numPrevReadings previous periods
total += getPeriod(i);
}
}
matrix[2][pointer] = ((numPrevReadings + 1) * (60 * 1000000)) / total; //store the smoothed RPM
if (pointer++ >= 9) pointer = 0; //increment the pointer to the position to store the next reading
}
unsigned long getPeriod(byte position) {
//position = 0 returns the last recorded value
//position = 1 returns next oldest and so on
int positionToGet = (pointer - 1 - position);
if (positionToGet < 0) positionToGet += 10;
unsigned long value = matrix[0][positionToGet];
return value;
}
unsigned long getRPM(byte position) {
int positionToGet = (pointer - 1 - position);
if (positionToGet < 0) positionToGet += 10;
unsigned long value = matrix[1][positionToGet];
return value;
}
unsigned long getSmoothedRPM(byte position) {
int positionToGet = (pointer - 1 - position);
if (positionToGet < 0) positionToGet += 10;
unsigned long value = matrix[2][positionToGet];
return value;
}
void isr(){
newMeasurementAvailable = 1;
period = micros() - prevTime;
prevTime = micros();
}