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(){
}
1 Answer 1
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)2018年04月14日 20:09:33 +00:00Commented Apr 14, 2018 at 20:09 -
Thanks, some very constructive critisism and a brilliant explanation.user4163554– user41635542018年04月14日 20:36:26 +00:00Commented Apr 14, 2018 at 20:36