Fast clock og better code for more accurate RPM reading

Im building a project where im using a capacitive pick up to detect rpm.
This is my first real arduino project, so excuse me if it is a little to easy.

This the way i got the signal transformed into some thing readable.

My code is based on the attachInterrupt() function. The one used in the playground example.
http://playground.arduino.cc/Main/ReadingRPM

I have tested it on a motor to around 3000 rpm with different count intervals. Found 15 to be a good medium between speed and resolution.

I need to be able to detect up to 12.000 rpm. My concern is the code or the board isn't fast enough.

Would it help to use a board with a faster clock speed or do you think i can optimize the code.
Please let me know.

Just to clarify your requirements, your talking about using capacitive effects from a cable clamped to a HT lead to measure engine RPM?

Would it help to use a board with a faster clock speed or do you think i can optimize the code.
Please let me know.

The Frequency counter library here looks like it will work up to 8MHz on an AVR (65MHz on a Teensy) so plenty of headroom from the 12KHz your looking for. You will need to post your code so we can how it can be optimized.

Some notes on your requirement, circuit and reference to code:

  • Your 12,000 rpm speed = 200Hz.
  • The output pulse duration of the NE565 is set to 1.1ms which limits the max frequency to 909Hz or 54,545 rpm.
  • The output pulse looks like this (Wikipedia)The code you've referred has limited resolution because it uses the millis() timer which will give poor resolution and cause jitter in your readings. Should also use RISING mode for your interrupt so the timing measurement doesn't include any instability of the RC timing circuit. Also, the code is more than fast enough, but the measurement time would become a problem at lower RPM.

Perhaps you could try this:

const byte rpmInputPin = 2;
const byte rpmMeasurementCycles = 2;
const byte printInterval = 500;

volatile unsigned long startTime, stopTime;
volatile byte rpmCount, testState;
unsigned long rpmPeriod, currentMillis, previousMillis = 0;;
float rpmFrequency, rpm;

void setup()
{
  Serial.begin(115200);
  pinMode(rpmInputPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(rpmInputPin), rpmMeasure, RISING);
}

void loop()
{
  if (testState == 2) EIMSK &= ~bit(INT0); // disable INT0 interrupt
  currentMillis = millis();

  if (currentMillis - previousMillis >= printInterval) {
    previousMillis = currentMillis;
    if (testState == 2) {    // testing completed, results are ready
      noInterrupts();
      rpmPeriod = (stopTime - startTime) / rpmMeasurementCycles;
      interrupts();
      rpmFrequency = 1000000.0 / rpmPeriod;
      rpm = rpmFrequency * 60.0;
      Serial.print(rpm);
      Serial.print(" RPM  ");
      Serial.print(rpmFrequency);
      Serial.println(" Hz");
      rpmCount = 0;
      testState = 0;        // clear testState
      EIFR |= bit(INTF0);   // clear INT0 interrupt flag
      EIMSK |= bit(INT0);   // enable INT0 interrupt
    }
  }
}

void rpmMeasure() {
  switch (testState) {
    case 0:
      startTime = micros();
      testState = 1;
      break;
    case 1:
      rpmCount++;
      if (rpmCount == rpmMeasurementCycles) {
        stopTime = micros();
        testState = 2;
      }
      break;
  }
}

Thanks for both the super fast responses.

I need the rpm reading for optimisation of a fuel map.

I need to log rpm, throttle position and an o2 sensor signal. This i got covered.

Thanks for the new code. Tried looking it though. I understand very little of it. Will sit down with the arduino wiki and learn the function of the code.

Thomas Harbo

I have now looked at you code with google as my friend.
I think i got the basic idea of how it works.
Only one things i don't understand.

How do you use the switch function?
Does it run the next case every time at imput on pin 2 is detected?

Hi,
How long is the output pulse from the LM555?
This will have an effect on the max RPM this part will work to.

Thanks.. Tom.. :slight_smile:

Dont know about the lenght of the pulse.
Just copied the schematic i found online.

I have tried looking in to how the size of each resister and capacitor effect the output pulse, but without luck.

I thought the value of R was 10K, but when I zoom in, it seems like its 18K (not sure). Anyways, the formula and description is here in Wikipedia under Monostable (Monostable Multivibrator).

The formula for the pulse duration is simply 1.1 x R x C. If the resistor (circled below) is 18K, then the pulse duration is 1.1 x 18000 Ohm x 0.0000001 Farad = 0.00198 seconds which is about 2ms.

I don’t understand why there is any need for the 555 timer. Can’t the input to the timer be fed to an external interrupt pin on the Arduino? If you need a chip to protect the Arduino for damaging voltages I would use a schmidt trigger chip.

Use an interrupt to count the number of pulses. After every N pulses record the value of micros() and subtract it from the pervious value to get the time for N pulses.

…R

Thanks for explaining the function of the 555s resister ans capacitor.

That means this circuit will work at 12000 rpm?

12,000/60 = 200hz

1/200 = 5ms > 2ms

From what i have read, the 555 both protect and clean the pulse from the capacitive pickup.
Haven't seen the wave i try to pick up, but from an early post, it looked wierd.

How do you use the switch function?
Does it run the next case every time at imput on pin 2 is detected?

Yes, it just sequences through 3 states.

For the first input rising edge, case 0 just records the startTime and changes the testState variable to 1. This is like starting a stop-watch and the pulse could be considered a start pulse. Its not counted because a full period hasn't elapsed yet.

The next pulse (case 1) and subsequent pulses are counted until rpmCount equals "rpmMeasurementCycles". Then the stopTime is recorded and testState is changed to 2.

There is no case 2 in the ISR, so it just exits. The main loop checks for testState == 2 which is used to calculate, print and reinitialize everything to start the next test.

Sorry for necro al old thread. I have used the sketch and it works great. But is there any way which we can also get the number of times that the sensor has been triggered?

I mean, can we get the speed (rpm) and a counter of triggers?

Just be wary of any circuits you get like this from Sport Devices as they may be just for preliminary explanation of operation, not necessarily practical circuits.