Serial.print() vs sprintf() and typecasting

Having some problems with basic C++ / Arduino typecasting… I think.

I’m playing with the Nightshade energyShield and trying to Spark.publish() a sprintf’d JSON string but the numbers are getting messed up, and I can’t figure out whether it’s the Wire() not working or if it is a sprintf typecasting problem.

Variables in question:

  • (int) Voltage in mW
  • (int) Current in mA
  • (int) Percent of charge in 0.5% increments
  • (int) Temperature in 0.125 C increments

When I Serial.print(variable) any of these, they produce some reasonable looking numbers:

  • Voltage (mV) 4079 mV
  • Current(mA) -2 mA
  • Charge (%) 90.0 %
  • Temperature © 25.37 C
  • Adapter Voltage (mV) 3079 mV

But after a sprintf() into this:

sprintf(publishString,"{\"mV\": %i, \"mA\": %i, \"percent\": %3.3f, \"temp\": %3.3f, \"Vadp\": %i}",Voltage,Current,Percent,Temperature,AdapterVoltage);

… and Spark.publish(), I get something like this:

{"data":"{\"mV\": 9993, \"mA\": 5118, \"percent\": 127.500, \"temp\": 255.875, \"","ttl":"60","published_at":"2014-11-17T04:42:21.680Z","coreid":"xxxxx"}

Code examples are more or less this test script and the .cpp and .h files for the energyShield. Does this look like a typecasting problem or am I screwing something else up?

Hi @emc2

Looks like you are running into the 63 character limit for Spark publish. You can make your fields names shorter and gain some more string space or publish twice with differnent parts. The limits are 63-characters with a once per second average but a burst of up to four allowed.

Unfortunately it doesn’t appear to be the old 63-char limit this time.

That publish response was the entire listener object from the cloud. I just tried reducing the publish char variable down to 64 bytes, and now am only publishing this:

sprintf(publishString,"{\"mV\": %i}",Voltage);
Spark.publish("esStatus",publishString);

And yet still the voltage is being published as 9993 instead of the 4079 expected out of the Serial.print() statement.

@emc2, it might be a silly question, but have you tried to Serial.println(publishString); to see if it’s a sprintf or a Spark.publish problem?

sprintf() doesn’t do type casts and cannot. [Technical reason: the printf family use varargs, the va_list contains no variable type information.].

You are printing Percent, declared int, using a float format %3.3f. You must explicitly do the cast yourself, printing (float)Percent/200.0.

Similarly for Temperature.

2 Likes

The strange values might (=won’t) be a side effect of exceeding the 63 char limit: Why would Spark.publish() screw up the part of the text that contains the numbers and not corrupt the part of the text that contains the variable names? (=!) No the damage happened earlier, before Spark.publish() was called.

Assuming, that is, that the expected values are the values @emc2 reported.

Hi @emc2

You are definitely hitting the limit since (1) I counted them out (the double-quotes are funny when you count since they are escaped) and (2) the entire “Vadp” parameter is missing in your result.

It sounds like you are having other problems too. As others have said, sprintf can’t cast–it just interprets what you give it in the type you say.

@emc2 I am having the same issue. It is not you. When I power my spark core via the USB and read the serial output from NightShade’s RealAll example, I get perfectly good measurements. Note that I only have lines running from the SparkCore for GND, D0 and D1. The Core is essentially powered from USB and the EnergyShield is only loaded by its internal circuits:

Voltage (mV)    Current(mA)     Charge (%)      Temperature (C) Adapter Voltage (mV)
3990 mV         5118 mA         78.0 %          35.38 C         48362 mV
3990 mV         5117 mA         78.0 %          35.50 C         51441 mV
3990 mV         5117 mA         78.0 %          35.63 C         51392 mV
3990 mV         5118 mA         78.0 %          35.63 C         51099 mV

I then modified the read all example to output the reading via Spark.publish(). And it produced fine results output to the event bus:

Voltage Current Charge Temperature Adapter Voltage
3989 mV 5118 mA 78.000 pct 36.125 temp 48802 Vadp
3989 mV 5117 mA 78.000 pct 36.125 temp 51197 Vadp
3989 mV 5118 mA 78.000 pct 36.125 temp 51955 Vadp
3989 mV 5118 mA 78.000 pct 36.125 temp 51808 Vadp

Then I mounted everything up on ShieldShield and disconnected all power sources… this is when I started getting this:

9993 mV 5118 mA 127.500 pct     255.875 temp    24 Vadp
9993 mV 5118 mA 127.500 pct     255.875 temp    24 Vadp
9993 mV 5118 mA 127.500 pct     255.875 temp    24 Vadp

I also noted that while the LED on the Core was flashing a nice steady breathing rate, it would periodically flicker. 10 Raoid Cyan flashes followed by about 5 even more rapid flashed. Everything keeps running fine.

Here is my Publish code just in case I did something not so right:

n = sprintf(message,"%i mV\t%i mA\t%3.3f pct\t%3.3f temp\t%i Vadp\0",Voltage,Current,Percent,Temperature,AdapterVoltage);
Spark.publish("energyShield", message);

I think my big question at this point is… where do I get I2C connections when using the ShieldShield… It looks like these readings are almost empty/null value readings. Looking at the docs, it would seem that my Core I2C pins are being routed to:

Spark Core D0 / SDA to Shield Shield D3
Spark Core D1 / SCL to Shield Shield D5

Problem is, on the Shield Shield, the I2C pins are now 5V pins. Will I need a logic level shifter to get them to talk… 3.3V I2C Fuel Guage on the EnergyShield and 5.5V I2C on the Shield Shield? Got to dig up a shifter and test. Might abandon the Shield Shield for this application.

Thought!!??!!??

Thanks in advance!

Chris

Originally, I did end up hitting the Spark.publish() character limit, but as you have noticed that was a separate problem.

I now think that this problem is related to the Shield shield and the communication pins that the energyShield uses. Page 7 of the energyShield Product Manual outlines the two sets of I2C solder junctions that you can change to switch between UNO and R3 pin locations.

I have only tried using jumpers to bring the default I2C pins down to the D0/D1 pins, which still does not seem to work - I haven’t tried soldering/desoldering those jumpers yet. If you decide to try soldering, post back with results!

Side note - I was testing the energyShield on an Uno R3, and THAT is where the Serial.print() results worked properly. I have NOT been able to get the communication to work at all with the Spark Shield shield, at all.

Looking like it might be Shield Shield and the TI Logic Level converter used to raise the voltage to 5V.