1

I'm having a slight problem that I'm unable to work out. I am using an arduino Uno to print an incremental, but predefined wheel circumference. This is all working beautifully except it gives a negative reading during execution, and then runs into the positive etc. Without being exact, the output is something like the following:

1.85, 3.71, 5.56, 7.41, 9.27, 11.15....

When this multiple reaches 32.00 or greater, it then counts negatively back down to zero, then positively up to 32.00 again.

I can't quite work out why this would be, so hoping that one of you guys would be able to shed some light. The code is as follows:

#include <Arduino.h>

int InterruptPin = 2;
int circ = 1854; //mtrs
int km = 0;


void calculate(){
    km = km + circ;
    //float temp = km / 1000;
    float temp = (float)km / (float)1000;
    Serial.println(temp);
}


void setup(){
    pinMode(InterruptPin, INPUT);
    attachInterrupt(digitalPinToInterrupt(2), calculate, RISING);
    Serial.begin(9600);
}


void loop(){

}
4

km is never reset but continously incremented.

km = km + circ;

This leads to an overflow of the value after some time.

When you declare int km;, then int on an Arduino Uno is int16_t, it thus has a maximum positive value of 2^15 - 1 = 32767. Since circ is constant 1854, after executing the ISR a total of CEIL(32767 / 1854) = 18 times, km becomes greater than that maximum positive value. Thus an integer overflow occurs which takes you back to the maximum negative value of the int16_t. (See https://en.wikipedia.org/wiki/Integer_overflow)

You might want to use uint32_t or similiar from stdint.h if you want to cover a greater value range. I think however your underlying algorithm is flawed, since even then km will overflow after some later time. You must reset it at some point or only store the number of revolutions, which is a much smaller number. If you want to get the traveled distance then, you take the number of revolutions and multiply it by the circumference.

Also you should not not use any Serial printing within in interrupt service routine! And you should also declare your used interrupt variables as volatile. Read this article for more info.

  • I would recommend unsigned long for large integer values. (it is uint32_t on 8-bit AVR) – Juraj Apr 14 '18 at 20:09
  • Thanks, some very constructive critisism and a brilliant explanation. – user4163554 Apr 14 '18 at 20:36

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.