I am having difficulty setting up an interrupt to count how many times the magnet passes so that I can count something like every 100 ms the actual speed.

I have a little code put together from the Internet:

const byte LED_pin =13;
const unsigned long wheel_circumference = 431800UL * 2UL * 31416UL; // = 94,248,000
unsigned long Speed = 0;
unsigned long PrevSpeed = 0;
volatile byte hall_rising = 0; // interrupt flag
volatile unsigned long irqMicros;
unsigned long startMicros;
unsigned long elapsedMicros;
unsigned long ledFlashStartMillis;
const unsigned long ledFlashWaitMillis = 10;
unsigned long displayStartMillis;
const unsigned long displayWaitMillis = 100;

void wheel_IRQ()
  irqMicros = micros();
  hall_rising = 1;

void setup()
  pinMode( 2, INPUT_PULLUP ); // pin # is tied to the interrupt
  pinMode( LED_pin, OUTPUT );
  Serial.begin( 9600 ); // can this be faster? faster would be better
  delay( 1000 );

  attachInterrupt( 0, wheel_IRQ, RISING ); // pin 2 looks for LOW to HIGH change

void loop()
  if ( hall_rising == 1 )
    elapsedMicros = irqMicros - startMicros;
    startMicros = irqMicros;
    hall_rising = 2;
  else if  ( hall_rising == 2 )
    if ( millis() - ledFlashStartMillis >= ledFlashWaitMillis )
      hall_rising = 0;

  // print speed 1000/Wait (10) times per second
  if ( millis() - displayStartMillis >= displayWaitMillis )
    Speed = wheel_circumference * 0.0009 / elapsedMicros;

    displayStartMillis += displayWaitMillis;
    if ( Speed != PrevSpeed )
      Serial.print(Speed); // this shows mm/sec with no remainder
      Serial.println(" kmh");
    PrevSpeed = Speed;

But when I use this code in U8glib to display the value on a GLCD . Values are totally wrong. Can someone help me?

  • What hall effect sensor are you using? Do the values come out correct when used with the serial monitor? Could you post what values you are getting with the hall effect sensor that are totally wrong, with the values of should be, how are sure they are wrong or right??
    – RSM
    Jul 5 '16 at 17:51
  • 1
    count how many times the magnet passes. In your entire code, you never count the number of times the interrupt is fired. You're code assumes that the loop function is called at least as many times as the interrupt is fired. If the loop function takes longer, by e.g. using the GLCD library, multiple interrupts could have fired, leading to elapsedMicros being a multiple of the value you expect. Leading to your code thinking the motor is running at half, or one-third, etc. the speed.
    – Gerben
    Jul 5 '16 at 18:32
  • so this code is obtained from elsewhere. I think the code counts the time between two magnets passes hence my 0*0009 coefficint to convert everything to kmh. when i put the code the output is 1/2 km h instead of 40 km h like in serial output. I still want to sample this way so that the speed output will be constant and will not slow down with the speed. How can i improve the code to handle the wheel circumference in meters? how can i show when the bike is not running? Is there any way to make this simpler? Jul 5 '16 at 19:12

You either need to change your code to count the number of revolutions in the interrupt. Then divide that value in your main loop by the elapsed time to get the angular velocity. This may or may not work, as the number of revolutions may be small or even zero when you do the calculations. Thus contributing to errors.

Or, change your code to record the elapsed time between rising edges in the interrupt. Then find the inverse of this value. This may be better as you could even miss an event in your main loop and still calculate the speed. Careful not to take the inverse of zero.

To calculate speed you need to find the rotational speed of the wheel, and, consequently, how fast you are bicycling. Use this equation: enter image description here ...where omega is the revolutions per time as calculated by the 1st method above or reported by the interrupt routine in the 2nd method above. Do not forget that the interrupt routine is probably using milliseconds and not seconds.

Also, do not forget to clear out the last value reported by the interrupt. No matter which of the above 2 approaches you take.

Also consider special cases. For instance, when you stop bicycling the interrupt will never fire. In your main loop you may have a second counter which, when exceeded, indicates that your speed is zero.

  • The code is already in micros to get a good resolution. Actually its for a motorcycle. Can you explain the 0kmh thing? Jul 6 '16 at 6:15
  • I did not say in the answer, but, from what you said, I think the U8glib display library is taking too much time to execute and the code to calculate speed, not being robust, is failing. I think you need to change the code from counting revolutions to counting the time between revolutions. As for 0kmh, you need a second way of timing to indicate there has not been a revolution for a long time. Perhaps more than a dozen seconds. When this occurs, replace the last displayed speed with zero.
    – st2000
    Jul 6 '16 at 12:07
  • So i should use an interrupt that says time = x microseconds every impulse? Jul 7 '16 at 14:44
  • That is the approach I would use. Remember to convert from ms to hours.
    – st2000
    Jul 7 '16 at 17:00

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.