I am trying to calculate the value of the potentiometer equivalent to the angle, so I need to multiply by 180 and then divide by the range. Upon doing so, I noticed that the number I'm getting is not the number I was expecting so I started debugging by multiplying by 180 only and realized the output was not as predicted. Here is the simple code that outputs the weird readings: `
#define POTENTIOMETER_PIN A0
int val;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
}
// put your main code here, to run repeatedly:
void loop()
{
val = analogRead(POTENTIOMETER_PIN);
Serial.println(val*180);
delay(250);
}
`
A value between (0 to 1023)*180 was expected, rather the serial monitor spits out values such as: -18932 -18752 -18572 -18392 -18392
CodePudding user response:
It would seem that your compiler defines int as being a 16 bit signed number.
Thus there is a limit of 32383 to -32384.
You are exceeding this and so the values 'wrap around'.
Try changing the code to use 'long' instead of 'int'.
CodePudding user response:
Take a look at the map()
function for your use case
https://www.arduino.cc/reference/en/language/functions/math/map/
int val = 0;
void loop()
{
val = analogRead(POTENTIOMETER_PIN);
val = map(val, 0, 1023, 0, 180);
Serial.println(val);
}
Internally, this makes use of a larger type than the humble int
, using a long
, which is (probably) 32-bits rather than 16
From the documentation above
long map(long x, long in_min, long in_max, long out_min, long out_max) {
return (x - in_min) * (out_max - out_min) / (in_max - in_min) out_min;
}
The reason this works better for you and can do the math correctly is because a 16-bit number doesn't contain enough precision for the multiplication, while map()
uses a 32-bit number internally to represent the value while it does the math on it!
Specifically, if, during your logic you rely on 16-bit math, the value exceeds that ~32768 range, it will wrap around and become negative!
https://www.arduino.cc/reference/en/language/variables/data-types/int/
On the Arduino Uno (and other ATmega based boards) an int stores a 16-bit (2-byte) value. This yields a range of -32,768 to 32,767 (minimum value of -2^15 and a maximum value of (2^15) - 1).
Finally, (and there is much debate, including why Arduino chooses to supply int
at all) it's generally good practice to always specify exactly the type you you're after such as uint32_t
, rather than relying on int
, which frustratingly can have a different size on different device targets
On the Arduino Due and SAMD based boards (like MKR1000 and Zero), an int stores a 32-bit (4-byte) value. This yields a range of -2,147,483,648 to 2,147,483,647 (minimum value of -2^31 and a maximum value of (2^31) - 1).