I ran into a bug yesterday that I'd encountered once before. I was running code that was tested and working. This time, I happened to have the right pieces on my desk to figure this out.
Currently, nearly all development I do in this environment is using the Teensyduino 3.x. It's fast, small, and a little bit different. Here's one of the ways.
I like my streams of numbers to line up for readability, especially floats. It's more trouble than it ought to be in most languages.
For the Arduino, there is a function dtostrf() that will print a fixed format float. However, there is a bug that causes it to display wacky numbers, usually when the value of the number is << 0.1, but for other cases as well. Using different boards at different times, I didn't notice the pattern. It turns out that this bug only occurs on the Teensy 3, which uses an ARM processor. In AVR-based boards such as the Arduino Uno and the Teensy 2, it works fine.
The work-around* for the T3 is to use a more standard and powerful printf() or sprintf(). These do not work for floating point numbers when compiled for AVR. (It would be nice if they did.)
*Per these current versions (Arduino 1.6.5, Teensy 1.2.4)
For Arduino and Teensy 2, use dtostrf()
dtostrf(y, 10, 5, cbuf);
Serial.println(cbuf);
-0.07071?
0.00354?
For Teensy 3, use sprintf()
sprintf(cbuf, "%10.5f", y); // correct on T3
Serial.println(cbuf);
-70711
-0.07071
35355
0.00354
test code:
// formatted float printing: Teensy 2 vs 3
char cbuf[20] = "";
void setup() {
while (!Serial && millis() < 5000) {} // with timeout
Serial.begin(9600);
float y;
// -nn.nnnn
y = -(sin(3.1416 / 4)) / 10;
dtostrf(y, 10, 5, cbuf); // incorrect on T3
Serial.println(cbuf);
sprintf(cbuf, "%10.5f", double(y));
Serial.println(cbuf);
y = +(sin(3.1416 / 4)) / 200;
dtostrf(y, 10, 5, cbuf);
Serial.println(cbuf);
sprintf(cbuf, "%10.5f", y); // correct on T3
Serial.println(cbuf);
}
void loop() {
;
}
No comments:
Post a Comment