Go Down

Topic: Serial.print() of a 64-bit DOUBLE (Read 4 times) previous topic - next topic

BKnight760

I've read in the Reference section that the DOUBLE data type on the Due is a 64-bit variable.  Unfortunately, the Serial.print won't handle a 64-bit variable.  I haven't been able to print out a uint64_t either.

Any ideas of how to print this?

I've looked into bit shifting the top 32-bits into an unsigned int, and then printing the high 32-bits followed by the low 32-bits, but apparently the bit shift operator defaults to a 32-bit operation as well.

The reason I'm trying to do this is because I stuck a 16 GB SD card into my wifi shield and can read it using the SD library, but it won't show the correct size of the SD card because it's so large.  The unsigned int will only show up to ~4 GB.  (0xFFFFFFFF = 4294967295 decimal).

Time to program the BigInt class?

robtillaart

#1
Jan 19, 2013, 08:01 pm Last Edit: Jan 19, 2013, 08:20 pm by robtillaart Reason: 1
Made this code for printing int64_t and uint64_t some time ago on an UNO - IDE 0.22;  

Should work for DUE too I guess, but is not tested other than on my UNO (so all disclaimers apply ;).
Just received my first DUE yesterday not downloaded the IDE for that to play with it.

Add this snippet to print.cpp to print the 64 bit integers, mind you! a simple sketch adds about 8KB!

Snippet for print.cpp
Code: [Select]

#ifdef SUPPORT_LONGLONG

void Print::println(int64_t n, uint8_t base)
{
 print(n, base);
 println();
}

void Print::print(int64_t n, uint8_t base)
{
 if (n < 0)
 {
   print((char)'-');
   n = -n;
 }
 if (base < 2) base = 2;
 print((uint64_t)n, base);
}

void Print::println(uint64_t n, uint8_t base)
{
 print(n, base);
 println();
}

void Print::print(uint64_t n, uint8_t base)
{
 if (base < 2) base = 2;
 printLLNumber(n, base);
}

void Print::printLLNumber(uint64_t n, uint8_t base)
{
 unsigned char buf[16 * sizeof(long)];
 unsigned int i = 0;

 if (n == 0)
 {
   print((char)'0');
   return;
 }

 while (n > 0)
 {
   buf[i++] = n % base;
   n /= base;
 }

 for (; i > 0; i--)
   print((char) (buf[i - 1] < 10 ?
     '0' + buf[i - 1] :
     'A' + buf[i - 1] - 10));
}
#endif


patched version of print.h
Code: [Select]

/*
 Print.h - Base class that provides print() and println()
 Copyright (c) 2008 David A. Mellis.  All right reserved.

 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation; either
 version 2.1 of the License, or (at your option) any later version.

 This library is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 Lesser General Public License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#ifndef Print_h
#define Print_h

#include <inttypes.h>
#include <stdio.h> // for size_t

#include "WString.h"

#define DEC 10
#define HEX 16
#define OCT 8
#define BIN 2
#define BYTE 0

// uncomment next line to support printing of 64 bit ints.
#define SUPPORT_LONGLONG

class Print
{
 private:
   void printNumber(unsigned long, uint8_t);
#ifdef SUPPORT_LONGLONG
void printLLNumber(uint64_t, uint8_t );
#endif
   void printFloat(double, uint8_t);
 public:
   virtual void write(uint8_t) = 0;
   virtual void write(const char *str);
   virtual void write(const uint8_t *buffer, size_t size);
   
   void print(const String &);
   void print(const char[]);
   void print(char, uint8_t = BYTE);
   void print(unsigned char, uint8_t = BYTE);
   void print(int, uint8_t = DEC);
   void print(unsigned int, uint8_t = DEC);
   void print(long, uint8_t = DEC);
   void print(unsigned long, uint8_t = DEC);
   void print(double, uint8_t = 2);

   void println(const String &s);
   void println(const char[]);
   void println(char, uint8_t = BYTE);
   void println(unsigned char, uint8_t = BYTE);
   void println(int, uint8_t = DEC);
   void println(unsigned int, uint8_t = DEC);
   void println(long, uint8_t = DEC);
   void println(unsigned long, uint8_t = DEC);
   void println(double, uint8_t = 2);
   void println(void);

#ifdef SUPPORT_LONGLONG
void println(int64_t, uint8_t = DEC);
void print(int64_t, uint8_t = DEC);
void println(uint64_t, uint8_t = DEC);
void print(uint64_t, uint8_t = DEC);
#endif

};

#endif



Can you confirm this works on DUE?
Code: [Select]
void setup()
{
 Serial.begin(9600);
 Serial.print(1000000000000LL, 10);
 Serial.println();
 Serial.print(-1000000000000LL, 10);
 Serial.println();
 Serial.println(1000000000000LL, 10);
 Serial.println(-1000000000000LL, 10);
}

void loop(){}


printing doubles I did not investigate yet but can be tackled in the same way as printing floats are handled using the printing of longs (on UNO)
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

robtillaart

Just had a look at the 1.0 IDE version, (still not downloaded DUE IDE )

The code should be extended with size_t return values, and some math to calc the right value ...
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

BKnight760

I made those modifications to print.cpp and print.h, and it worked just great on my DUE.  I am now able to display the true size of my 16 GB SD Card:

Code: [Select]
Volume size (bytes): 15923150848

I didn't change the methods to size_t though, it worked fine without that change.  (I did try it, and it threw a bunch of errors, so I left them as void).

As you noted, the change does add about 8KB, but heck, I've got a DUE with 512K program memory, so I can spare the extra 8K.  Woot.

robtillaart

good to hear it works!

Is the performance fast enough?
can you test printing 100 int64's @115200 and time it with micros?
and do the same with 100 int32's?

The size_t thing should be solved someday but apparently not now ;)

You also stated that you were not able to print a double ? but floats works?
(there is definitely no x.yyyE-nnn engineering format yet)
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Go Up