0

I'm using an analog to digital converter to read a voltage value from 0 to 3.3V. The ADC gives an output from 0x00 to 0x0FFF (0 to 4095). I want to print the voltage reading with two decimal places. I have read a number of answers but nothing I've tried has worked. Here's my code:

uint32_t pui32ADC0Value[1]; // ADC0 data value
double D0v;                 // Decimal value

// Read value from ADC
ADCSequenceDataGet(ADC0_BASE, 3, pui32ADC0Value);

// Convert to decimal
D0v = (double)pui32ADC0Value[0] / 4095 * 3.3;

// Print to console
UART0printf("\n\r> D0 = %.2d V", D0v);

The output I get is: D0 = ERROR2d V

pui32ADC0Value prints without any problems and gives the expected values, so I know that it is working.

What does this error mean?

NOTE: UART0printf is a pre-defined UART function on the TIVA TM4C microcontroller I am using.

UPDATE: I wrongly assumed UART0printf is identical to printf, as I have used it before with %u, %s, and %x. However for numbers it only supports %c, %i, and %u. I am re-working my code and will update if I don't get anywhere.

UPDATE 2: Could I do something like this? I know it will round incorrectly...

uint32_t pui32ADC0Value[1]; // ADC0 data value
uint32_t D0v[2];                 // Decimal value

// Read value from ADC
ADCSequenceDataGet(ADC0_BASE, 3, pui32ADC0Value);

// Convert to decimal
for ( int i = 0; i <= 2; i++){
    D0v[i] = (pui32ADC0Value[0]/10^i) / 4096 * 3.3;
}

// Display the AIN0 (PE0) digital value on the console.
UART0printf("\n\r> D0 = %d.%d%d V", D0v[0],D0v[1],D0v[2]);
LShaver
  • 285
  • 1
  • 5
  • 14
  • 1
    What is `UART0printf`? Are you sure it supports the same format-string syntax as C's `printf`? – Dai Nov 13 '15 at 21:48
  • 2
    why uint32_t pui32ADC0Value[1]; ? instead of uint32_t pui32ADC0Value; ?? – Nandu Nov 13 '15 at 21:57
  • @Nandu: I'm going to go on a limb and assume ADCSequenceDataGet takes a pointer to a `uint32_t`, so `uint32_t[1]` gets the free implicit conversion. I don't think it was a good idea though. – Mooing Duck Nov 13 '15 at 22:03
  • This is from the ADC manufacturer. The call to ADCSequenceDataGet will only get one element for the array so I define it that way. – LShaver Nov 13 '15 at 22:11
  • 1
    OK I lied, turns out UART0printf isn't identical to printf - it only supports %d %i and %u... meaning I've got a different question. I'll close this one out. – LShaver Nov 13 '15 at 22:20
  • @LShaver Then it might be possible to use the real `printf` and redefine the `putchar` (might not be exactly this) to print via your UART interface. – nnn Nov 13 '15 at 22:26

2 Answers2

4

If this function works printf like:

UART0printf("\n\r> D0 = %.2f V\n", D0v);

Also your code may work a little faster if you use:

D0v = (double)pui32ADC0Value[0] * (3.3 / 4095);

The compiler will precompute 3.3 / 4095 and will do a single floating point multiply operation. Otherwise it's possible that the division is done first (which usually takes much more CPU cycles than a multiply) and then the multiply * 3.3 will be done.

Also since you seems to need only 2 digit precision, you could use float (single precision) instead of double. It may execute faster (but it's possible to be even slower), this depends on the platform.

Update for UPDATE2 in the question:

Try this:

uint32_t pui32ADC0Value[1]; // ADC0 data value
uint32_t D0v;               // Decimal value

// Read value from ADC
ADCSequenceDataGet(ADC0_BASE, 3, pui32ADC0Value);

// Convert to millivolts
D0v = pui32ADC0Value[0] * (3300.0 / 4095);

// Display the AIN0 (PE0) digital value on the console.
UART0printf("\n\r> D0 = %d mV", D0v); // If it's OK for you to display in mV
UART0printf("\n\r> D0 = %d.%03d V", D0v / 1000, D0v % 1000); // Print in V
nnn
  • 3,980
  • 1
  • 13
  • 17
  • @Dai Still a integer division have to be done then and on a specific platform I've seen that a single precision multiply (float) is faster than a integer division. – nnn Nov 13 '15 at 21:58
  • I don't think `float` is usually any faster than `double`, I'm pretty sure on most architectures they're computed identically. The only difference is accuracy during storage. – Mooing Duck Nov 13 '15 at 22:04
  • @MooingDuck Right, this may depend on the actual platform. But on microcontrollers not having FPU (with float div implemented in SW), I think it will be faster. – nnn Nov 13 '15 at 22:08
  • I've got FPU, how would this affect it? – LShaver Nov 13 '15 at 22:12
  • @LShaver It's good then and I can't say precisely which one is faster (`float` or `double`). You may be able to determine by using a timer to measure execution (or look in the CPU instruction set architecture for details regarding this). But if the operation is not so frequently done, maybe don't bother with it. – nnn Nov 13 '15 at 22:16
  • Quite simply, TI's UARTprintf() does not work with floats. It's not a full implementation of printf(). Break the float into two ints: integer part and fractional part. Then you can use UARTprintf() on the parts. Alternatively you COULD use sprinyf() but you may have to increase the stack size. I prefer to avoid using sprintf() on this platform for production code, but for a quick test program it's fine. – GC78 Jul 26 '17 at 11:23
2

There is no such printf format string as

%.2d

The formatter %d means integer, so there are no decimal-precision options for it. The %. is being parsed as an error (as it does not exist), and the 2d is making it verbatim into your output.

The formatter for floating-point values is %f, so:

%.2f

However, all this is based on the assumption that UART0printf, which you do not identify in your question whatsoever, is identical to printf.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055