I have an issue when sending floats to sprint(). I'm pretty sure the issue I have is that i'm using the signed int specifier on values that return floats which is causing my sprintf to go out of whack (See screenshot below where the println is normal but sprint is messed up).
That being said I can't seem to find a good resource showing how to use the %f specifier on sprintf(). I know I need to specify the decimal points but my Google-Fu is failing me trying to find the formatting that %f expects. The only link I've found is the one below but it lacks what I'm looking for.
Here's my code and a screenshot showing the issue.
int LED = 13;
int loopCounter = 0;
const int pressureInput = A1; //select the analog input pin for the pressure transducer
const int pressureZero = 97; //analog reading of pressure transducer at 0psi
const int pressureMax = 921.6; //analog reading of pressure transducer at 100psi
const int pressuretransducermaxPSI = 100; //psi value of transducer being used
const int baudRate = 9600; //constant integer to set the baud rate for serial monitor
const int sensorreadDelay = 500; //constant integer to set the sensor read delay in milliseconds
int pressureValue = 0; //variable to store the value coming from the pressure transducer
int pressurePSI = 0;
void setup()
{
pinMode(LED, OUTPUT);
Serial.begin(baudRate);
}
void loop()
{
digitalWrite(LED, HIGH);
pressureValue = analogRead(pressureInput);
float voltage = (pressureValue*5.0)/1024.0;
//for some off reason the voltage calculation returns < 0 randomly
if (voltage >= 0)
{
pressurePSI = ((pressureValue-pressureZero)*pressuretransducermaxPSI)/(pressureMax-pressureZero);
char buffer[80];
sprintf(buffer,"{\"psi\": \"%d\",\"voltage\": \"%d\",\"analogRead\": \"%d\",\"loop\": \"%d\"}", pressurePSI,voltage, pressureValue, loopCounter);
Serial.println(buffer);
Serial.println(pressurePSI);
Serial.println(voltage);
Serial.println(pressureValue);
Serial.println(loopCounter);
}
delay(sensorreadDelay); //delay in milliseconds between read values
digitalWrite(LED, LOW);
loopCounter++;
if (loopCounter == 2000)
{
loopCounter = 0;
}
}
I don't want to be a d1ck and sound ungrateful but did you read the question? I know I need to use %f but I don't know how to tell it the decimal points to expect.
A floating point number does not contain a specific number of digits after the decimal point.
With 32 bit floats, you get about 6 or 7 meaningful digits, total. With 64 bit doubles, in the few Arduino MCUs where doubles are actually implemented, you get about 15 meaningful digits, total.
As stated above, on most Arduinos, sprint() does not support floats or doubles.
It's not the number to of digits to "expect" or how many are "sent". It's the number to print. As already noted, a 32-bit floating point number is good for 5-7 significant digits. You can print out beyond that, but those extra digits will be garbage.
Thank you @jremington@Blackfin, Now I understand why sprtinf wasn't working with %f. I went ahead and implemented dtostrf and everything is working now.
Final code for anyone else who may be stumble upon this:
int LED = 13;
int loopCounter = 0;
const int pressureInput = A1; //select the analog input pin for the pressure transducer
const int pressureZero = 97; //analog reading of pressure transducer at 0psi
const int pressureMax = 921.6; //analog reading of pressure transducer at 100psi
const int pressuretransducermaxPSI = 100; //psi value of transducer being used
const int baudRate = 9600; //constant integer to set the baud rate for serial monitor
const int sensorreadDelay = 500; //constant integer to set the sensor read delay in milliseconds
int pressureValue = 0; //variable to store the value coming from the pressure transducer
int pressurePSI = 0;
void setup()
{
pinMode(LED, OUTPUT);
Serial.begin(baudRate);
}
void loop()
{
digitalWrite(LED, HIGH);
pressureValue = analogRead(pressureInput);
float voltage = (pressureValue*5.0)/1024.0;
pressurePSI = ((pressureValue-pressureZero)*pressuretransducermaxPSI)/(pressureMax-pressureZero);
char vBuffer[15];
dtostrf(voltage,4,2, vBuffer);
char buffer[80];
sprintf(buffer,"{\"psi\": \"%d\",\"voltage\": \"%s\",\"analogRead\": \"%d\",\"loop\": \"%d\"}", pressurePSI, vBuffer, pressureValue, loopCounter);
Serial.println(buffer);
//Serial.println(pressurePSI);
//Serial.println(voltage);
//Serial.println(pressureValue);
//Serial.println(loopCounter);
delay(sensorreadDelay); //delay in milliseconds between read values
digitalWrite(LED, LOW);
loopCounter++;
if (loopCounter == 2000)
{
loopCounter = 0;
}
}
So yes, you are correct that I'm sending the data to another system and in fact I am using Node-Red upstream. However, I want to separate the data at the moment of ingestion, and formatting it into JSON directly out of the Arduino allows me to program node-red to separate the deserialized objects without the need for conversion.
Unless there is something I'm missing here. How else would node separate multiple incoming values without the need to write some logic to split based on a separator?
The Function node allows you to run any JavaScript code against the message. This gives you complete flexibility in what you do with the message, but does require familiarity with JavaScript and is unnecessary for many simple cases. More information about writing Functions is available here.
The Change node provides a lot of functionality without needing to write JavaScript code. Not only can it modify message properties, but it can also access flow- and global-context.
It provides four basic operations:
Set a property to a value,
Change a String property by performing a search and replace,
Delete a property,
Move a property.
The take-away IMO is that one should approach a solution appropriate to their need and comfortable enough that they can support and extend the software.