I am experimenting using the map() method in an ArduinoIDE sketch in an attempt to obtain a pixel position for a horizontal meter in the range 0-320 from an input value in the range 0-5. However, when I do this I see in the method that the input must be 'long' type. Here's my example code:
float voltage = 2.5;
float meterPosition = map(voltage, 0, 5, 0, 320);
tft.fillRect(0, 0, meterPosition, 10, TFT_GREEN);
tft.setCursor(10, 70);
tft.setTextSize(3);
tft.println(voltage);
tft.println(meterPosition);
But when I run this, despite the input value being 50% of the input range, I expected the meterPosition value to be 160, but it is 128, due I think because the values for this method must be of type 'long' and so the 'float' value is rounded and becomes a 'long' type (I think that's what is happening!!).
I am confused as to the function of the map() method if you are unable to map any range to any other range without using decimals as the input. I am obviously missing something here, so what do I need to change in my map() method code for it to work in my example please, if I am unable to use floats?
Thanks. John
2 Answers 2
As you already noticed, the map()
function is meant to work with the
long
data type. Here is its implementation:
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;
}
If you want to use floats, you could write a version of this function
that works with floats. Note, however, that since you are using zeros
for both in_min
and out_min
, the expression simplifies itself to the
point of becoming trivial:
float meterPosition = voltage * 320 / 5.0;
I would suggest two small changes to this expression though:
add parentheses around
(320 / 5.0)
: this ratio will then be evaluated at compile-time and you will save an expensive run-time floating-point divisionround to the nearest integer in order to minimize the error: your pixel position will have to be an integer anyway.
With these suggestions, we have:
int meterPosition = round(voltage * (320 / 5.0));
Do not forget the .0
in 5.0
, otherwise you would get an integer
division.
Note that using map()
with ranges scaled by a factor 100 is not a
terribly good idea: you will waste quite a lot of CPU cycles doing
useless computations, and the result will be polluted by two rounding
errors instead of one.
Apologies for my stupidity folks! I think I have realised how to do this, it is simply a matter of scaling the input values and input range by 100.
float meterPosition = voltage * 64.0 ;
?