aviatorken:
I'm still trying to wrap my head around figuring out how to determine the right duration of time to record. Using a hall effect sensor to help me figure out the magnet on the flywheel, I determined that the pattern is: FALLING (1st magnet leading edge), RISING (1st magnet trailing edge), FALLING (3rd magnet leading edge), RISING (3rd magnet trailing edge).
The middle/2nd magnet does nothing, I believe it's only there to strengthen/couple the field to the ignition coil.
So really I need to figure out how to find the time window between the RISING of the 3rd magnet to the FALLING of the 1st magnet, but I do not know how due to to the same pattern is created between the 1st and 3rd magnets which is what I need to avoid for false readings.
The only thing I can think of quickly is to record 3 High to Low periods and pick the one with the greatest duration, but this might be flawed? Just an idea that came to my head that caused me to edit this post. Or record 2 Low to Low periods and pick the one with the longest duration?
Edit 2: added current code, basically waiting for 3 pulses to occur and do subtraction to find the longest duration between the two groups: pulse 1 and 2, and pulse 2 and 3. This may be flawed logic though? Do I need to wait for 4 pulses to occur and add a 3rd group, pulses 3 and 4?
The below code still gives me false readings, I cannot seem to grasp a solution.
Help is appreciated 
Code:
#include <PinChangeInt.h>
#define ENGINE_KILL_FLAG 1
#define RPM_INPUT_PIN 4
unsigned long rpmTimeoutInterval = 1000000;
volatile unsigned long rpmPulse1Micros = 0;
volatile unsigned long rpmPulse2Micros = 0;
volatile unsigned long rpmPulse3Micros = 0;
volatile uint16_t volatileEngineRPM = 0;
volatile uint8_t bUpdateFlagsShared;
volatile uint8_t rpmPulseCounter = 0;
volatile uint16_t unEngineKillInShared;
uint16_t unEngineKillStartPeriod;
void setup()
{
Serial.begin(115200);
PCintPort::attachInterrupt(RPM_INPUT_PIN, calcRPMInput, FALLING);
}
void loop()
{
static uint16_t unEngineKillIn;
static uint8_t bUpdateFlags;
if (bUpdateFlagsShared)
{
noInterrupts();
bUpdateFlags = bUpdateFlagsShared;
if (bUpdateFlags & ENGINE_KILL_FLAG)
{
unEngineKillIn = unEngineKillInShared;
}
bUpdateFlagsShared = 0;
interrupts();
}
uint16_t engineRPM = volatileEngineRPM;
unsigned long rpmPulse3MicrosCopy = rpmPulse3Micros;
if (micros() - rpmPulse3MicrosCopy > rpmTimeoutInterval)
{
engineRPM = 0;
}
Serial.println(engineRPM);
bUpdateFlags = 0;
}
void calcRPMInput()
{
rpmPulseCounter++;
if (rpmPulseCounter == 1)
{
rpmPulse1Micros = micros();
}
else if (rpmPulseCounter == 2)
{
rpmPulse2Micros = micros();
}
if (rpmPulseCounter == 3)
{
rpmPulseCounter = 0;
rpmPulse3Micros = micros();
unsigned long pulse1and2Duration = rpmPulse2Micros - rpmPulse1Micros;
unsigned long pulse2and3Duration = rpmPulse3Micros - rpmPulse2Micros;
unsigned long pulseDuration = pulse2and3Duration;
if (pulse1and2Duration > pulse2and3Duration)
{
pulseDuration = pulse1and2Duration;
}
if (pulseDuration >= 16000 && pulseDuration <= rpmTimeoutInterval)
{
// 60,000,000 microseconds in one minute
uint16_t rpm = 60000000 / pulseDuration;
volatileEngineRPM = rpm;
}
}
}
Why not count the number of pulses in a full revolution before storing time?
Example Code:
#include <PinChangeInt.h>
// My Encoder has 1 Clock pulses per revolution
// note that 60000000.0 = (60 seonds * 1000000 microseconds)microseconds in a minute / 1 pulses in 1 revolution)
#define Multiplier 60000000.0 // don't forget a decimal place to make this number a floating point number
#define #define RPM_INPUT_PIN 4
//#define RPM_INPUT_PIN 2 // My Uno only has pins 2 and 3 as interrupt pins with My compile testing
#define PulsesPerRevolution 3 // how many pulses does your magnets trigger per revolution
volatile unsigned long dTime; // Delt in time
volatile byte Readings;
volatile byte Pos;
volatile long SpeedInRPM[10];
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
PCintPort::attachInterrupt(RPM_INPUT_PIN, calcRPMInput, FALLING);
// attachInterrupt(digitalPinToInterrupt(RPM_INPUT_PIN), calcRPMInput, FALLING); // this is what I used for the compile test
}
void loop() {
// put your main code here, to run repeatedly:
static unsigned long _ATimer;
if ((millis() - _ATimer) >= (100)) { // see what we have 10 times a second
_ATimer = millis();
Serial.print("RPM:");
Serial.print(SpeedInRPM[(Pos-1) %10]);
int Val;
long sum;
int MinRPM;
int MaxRPM;
for (char i = 0; i < Readings; i++) {
Val = SpeedInRPM[(i) % 10];
sum += Val;
if (i < 10) {
MinRPM = min(Val, MinRPM);
MaxRPM = max(Val, MaxRPM);
}
}
Serial.print(" Min:");
Serial.print(MinRPM);
Serial.print(" Max:");
Serial.print(MaxRPM);
int Average = sum / Readings;
Serial.print(" Average:");
Serial.print(Average);
Pos = 0;
Readings = 0;
}
}
void calcRPMInput(uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
static byte ctr;
static uint32_t lTime; // Saved Last Time of Last Pulse
ctr++;
if (ctr >= PulsesPerRevolution) { // We have counted enough times to make a full revolution of the flywheele with wird magnet positions
uint32_t cTime; // Current Time
cTime = micros();// Lets get the time first.
ctr = 0;
dTime= cTime - lTime;; // Delt in time Store 10 readings for averaging
if (Readings < 10) Readings++; // So we average correctly
lTime = cTime;
SpeedInRPM[Pos++ %10] = Multiplier / dTime; // Calculate the RPM after we have reached 1 revolution worth of pulses
/*what does this do :
* Pos++ %10
* first it gets the current value of Pos and returns it.
* afterwords it increments it by 1
* then to prevent overflowing our array we test it
* by getting the remainder of the value returned
* by Pos which is a number between 0 and 9 (10 Spots)
* there is an issue with rollover but we reset the Pos counter
* it long before we get there.
*/
}
}
Threw in min max and average for testing this
I compiled it but not tested.
Z