I am using an Arduino Mega to control the speed of an internal combustion engine.

The speed is sensed via a Variable Reluctance Sensor (VRS) on the crankshaft. This signal is then converted into a 5V square wave which is feed into Interupt 2 (Pin 21) on the Arduino.

The flywheel of the engine, onto which the VRS is sensing has one tooth. Therefore one square wave blip (from 5v to 0V) as it is passing it and then back up to 5v. The interupt that this is attached to increases a counter by 1. The time taken for the counter to reach 20 is recorded. I want to use this speed reading value in a PID algorithm which then in turn actuates a servo.

This methodology was sucessfully used in a very similar engine with a 22 toothed flywheel but is not working on this engine with 1 tooth.

The problem is the speed reading - the values that I am recording for the time taken for 20 revs ( in micro seconds), and displayed on the serial terminal is wrong and I do not know why. The numbers printed are all mulitples of one another e.g. 440960,551200,661440,771680 which all divide into one another with an even fraction. The correct reading here is 661440, this has been verified with observation of the square wave input through and oscilloscope.

I cannot find why!

I have attached the code here

  • Why are you using an interrupt instead of Input Capture? – Ignacio Vazquez-Abrams Jul 20 '16 at 14:29
  • Are you suggesting using PulseIn? – Gawnie Jul 20 '16 at 14:32

Your methodology there is somewhat flawed. Not only will you never see that Counter1 >= 20 (since you immediately set it to 0 before returning the count), but if you never get a pulse (engine is stalled) you'll never reach 20 pulses anyway.

A better method is to reverse everything and instead of timing how long it takes to get 20 pulses, count the number of pulses you get in a pre-defined time period.

Your interrupt remains the same, counting each pulse as it arrives, but you then sit and watch the clock (using millis()) and when a certain (to be decided by you) time has elapsed (the sample time) you record the pulse count and reset it to 0. You then have a number of rotations per time period.

If you set that time period to be 1 second (the simplest) then you immediately have the number of rotations per second.

void loop() {
    static uint32_t ts = millis();
    uint32_t pulses;

    if (millis() - ts >= 1000) {
        ts += 1000;
        uint8_t sr = SREG;
        pulses = Counter1;
        Counter1 = 0;
        SREG = sr;
        Serial.println(" revolutions per second");

Decreasing the sample time means you can respond faster, but you are working with smaller numbers and hence less accuracy. For instance, setting it to 100ms instead of 1 second you need to multiply your count by 10 to get the current pulses per second. It all depends on how fast your engine runs as to what a good sample time would be.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.