I’m using a TMP36 and the MEASURING THE TEMPERATURE example. I would like to get the result to 74.1
// -----------------
// Read temperature
// -----------------
// Create a variable that will store the temperature value
double temperature = 0.0;
void setup()
{
// Register a Spark variable here
Spark.variable("temperature", &temperature, DOUBLE);
// Connect the temperature sensor to A7 and configure it
// to be an input
pinMode(A7, INPUT);
}
void loop()
{
int reading = 0;
double voltage = 0.0;
// Keep reading the sensor value so when we make an API
// call to read its value, we have the latest one
reading = analogRead(A7);
// The returned value from the Core is going to be in the range from 0 to 4095
// Calculate the voltage from the sensor reading
voltage = (reading * 3.3) / 4095;
// Calculate the temperature and update our static variable
temperature = (voltage - 0.5) * 100 * 9.0 / 5.0 + 32; //
}
@rastapasta 's solution is perfect and can be used wherever rounding is required.
But just for completeness - if someone else should happen to drive by this thread - I’d like to mention two more solutions, depending on the respective needs.
One is the easiest mathematical approach. Just add 0.5 and then truncate away the decimal places. To achieve a round after the 0.1 place, you’d again do what @rastapasta said: multiply-divide by ten.
This is good if you are doing some mathematical operations beforehand anyway, then you can incorporate that quite easily and thus save some processing cycles.
temperature = ((int)(((v - 0.5) * 100.0 * 9.0 / 5.0 + 32.0 + 0.5) * 10)) / 10.0;
// (v - 0.5) * 100.0 to get °C
// 9.0 / 5.0 + 32.0 to convert into °F
// ((int)(... + 0.5) * 10) / 10.0 to round to 0.1°F precision
// or mathematically reduced and streamlined for speed,
// but less readable/divisable into above sub calculatioins
temperature = ((int)(1800.0 * v - 867.5)) / 10.0;
or if you only want to print out a rounded value, but otherwise want to keep the precision in the variable you just do this (which was not the intention of the original question, but for “completeness” )
// e.g. for Serial output
temperature = (v - 0.5) * 100.0 * 9.0 / 5.0 + 32.0;
Serial.print(temperature, 1);
You cannot rely on that entirely. E.g. the decimal 0.2 (1/5th) has a recurring representation in base 2, and numbers in C (and on the Spark and Arduino, therefore) are stored base 2. 1/5th can be represented entirely accurately in decimal but it is an endlessly recurring number in binary. 0.2(base 10)=0.0011001100110011…(base 2). It matters not what you do with round() or other functions, the internal representation will never be exactly 1/5th if stored as a float or a double. What you can do is either store the value as the number of tenths, as an integer, but this is cumbersome
float temperature;
int temperature_tenths;
temperature_tenths = (int)round(temperature * 10);
or ignore the problem entirely and only worry about it during comparisons (you cannot compare for equality to 1/5th for the reason given above). Outputting the number will ordinarily cause the binary to be transformed into decimal. I use printf or sprintf
char s[22];
//printing a float to one rounded decimal digit of accuracy
sprintf( s, "%.1f", temperature);
//printing an integer representing number of tenths
sprintf( s, "%d.%d", temperature_tenths/10, abs(temperature_tenths)%10);
//comparing a float for equality to 0.2
if( fabs(temperature-0.2) < 0.0001) almostequal=true else almostequal=false;
@ScruffR can you pls tell me what I'm doing wrong here....
I would like value to appear in console as eg: 50.1 % so 1 decimal place..
Currently it is printing six zero after decimal place. I have pulled my hair out playing around with the resultstr function and data types with no luck...
int TnkLvlPV_RAW = A0;
float Tx01 = 0.0;
char resultstr[64];
void setup () {
pinMode(TnkLvlPV_RAW,INPUT);
}
void loop() {
// Read alalogue value assigned to TAG "TankLevelPV_RAW"
Tx01 = analogRead(TnkLvlPV_RAW);
Tx01 = map(Tx01, 0, 4095, 0, 100);
sprintf(resultstr, "{"value":%.4f}",Tx01);
You are already using snprintf() for your result string, just post that instead of String(Tx01).
And if you use "%.1f %%" as format string, you’ll only see one decimal place and the percent sign as well in it.
But since map() will only give you integer results AFAIK, you won’t even need that one decimal place.
This won't compile since you are not using it right.
Means
// not like this
// Spark.publish("Tx01", sprintf(Tx01) + " %");
// but
snprintf(resultstr, sizeof(resultstr), "%.1f %%",Tx01);
particle.publish("Tx01", resultstr, PRIVATE); // keep things private too
Yup, the normal mathematical way - linear interpolation/extrapolation.
This is the implementation for the standard map()
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;
}
Rename the function and change all datatypes to double and you'll be fine.
For the original question the topic title refers to that won't help really.
Binary floating point data types cannot store every arbitrary value and hence even if you have results that would only result in a few decimal places the binary representation would sometimes only approximate that result and hence the conversion from float to string needs to take care of the number of decimal places you are interested in.
That's why you had to add the second parameter in your Serial.print() statement.
For the last, the intent is not only to round the result but also map (rescale) the original value.
If this should merely drive views on that video we'd have to consider this spam tho'