Fixed Point Print Formatters? [solved]

Go To Last Post
11 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Greetings -

 

I have a uint32 variable that I need to convert to a decimal character string. Problem is, this variable is a fixed point one in which the lowest several bits (2 or 3, not sure which, yet) represent fractional parts, 1/2, 1/4, and maybe 1/8. I really need to convert those to decimal ASCII character strings such as 123.5 or 9347.75, for example.

 

I don't see printf() or its cousins doing that. Is there a "simple" ( eg, not a huge code increase over using printf() ) resource to do that, or do I need to kluge up something, myself? Its not THAT hard but it would be nice, not to have to do it.

 

Oh, yes, the obligatory details: AS7.x and corresponding gcc toolchain. MCU = M328P.

 

Many thanks

Jim

This topic has a solution.

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

Last Edited: Mon. Apr 17, 2017 - 06:55 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

uint32_t number = 7654321;

If 2 decimal places bits:

printf("%ld.%d", number/4, (int)(number & 0x03)*25);

If 3 decimal places bits:

printf("%ld.%d", number/8, (int)(number & 0x07)*125);

 

Edit: (updated for uint32_t)

If 4 bits:

printf("%ld.%04d", number/16, (int)(number & 0x0F)*625);

 

Edit2: changed "decimal places" to "bits"

David (aka frog_jr)

Last Edited: Mon. Apr 17, 2017 - 05:21 PM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Go on,  Jim.   printf("%f", val * 0.125)

 

Note that you have to enable f-p printf().

Alternatively,  use dstrtof()

 

Yes,  there is a code increase.    But this is seldom a problem with a 32kB AVR.   Bad news on a 2kB chip.

 

If you are printing the value from a temperature chip:  float degrees = val / 256.0

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ka7ehk wrote:
I don't see printf() or its cousins doing that.
It's in the Embedded C standard.

ka7ehk wrote:
Is there a "simple" ( eg, not a huge code increase over using printf() ) resource to do that, or do I need to kluge up something, myself?
Roll your own because the fixed point types are not a match (precision) in AVR GCC and not certain printf for fixed point is in AVR GCC.

 

P.S.

ka7ehk wrote:
Oh, yes, the obligatory details: AS7.x and corresponding gcc toolchain. MCU = M328P.
Sometimes the tools one needs aren't with the MCU but with a MPU (arbitrary precision arithmetic)

Not applicable if the MCU has to do the printf (operator's display, etc)

 


ISO/IEC

C - Project status and milestones

TR 18037: Embedded C

http://www.open-std.org/JTC1/SC22/WG14/www/projects#18037

http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1169.pdf

(page 19, 4.1.9  Formatted I/O functions for fixed-point arguments)

https://gcc.gnu.org/wiki/avr-gcc#Fixed-Point_Support 

 

"Dare to be naïve." - Buckminster Fuller

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This happens to be an implementation of "total seconds" with more resolution than 1 second. I'd like steps of 01.sec but I don't see how to get that from the async 32.768KHz oscillator and the available prescale and counter chain (in M328P). Oh, well, 1/4 or 1/8 second will have to do.

 

Just realized that another option is to save the data as a standard int (converted to ASCII) and tell the end user to divide that by 4 or 8. This is going into CSV file on an SD card as part of a datalogger. Yet another option is to keep the integer part as a standard format uint32_t and have a second variable for the fractional part. The two can then be combined when it is time to print. This would allow the use of basic itoa(), I think. The fractional part could be done with the equivalent of a "lookup table" (containing the ASCII strings for the fractional parts).

 

Frankly, I do not use printf very often and David's example is a bit of a surprise. I would not have expected that to work! I really do appreciate your help!

 

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

Last Edited: Mon. Apr 17, 2017 - 05:06 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

ka7ehk wrote:
David's example is a bit of a surprise. I would not have expected that to work!

Honest question: What was the surprise?

 

The expression

val * 0.125

results in a floating point value. This is true wherever it would occur.

 

The

printf("%f", ...)

will pick up the second parameter (here marked with ...) and format it as a float before outputting it.

 

This is a equivalent, although somewhat more convoluted, variant:

 

float floatVal;
floatVal = val * 0.125;
printf("%f", floatVal);

Is the surprise on the second or third line in that?

Happy 75th anniversary to one of the best movies ever made! Rick Blane [Bogart]: "Of all the gin joints, in all the towns, in all the world, she walks into mine."

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

Last Edited: Mon. Apr 17, 2017 - 05:13 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I had forgotten that val*0.125 produces an internal float. Again, I don't work with those details much, and I forget the rules pretty easily. I would have expected for that operation to do a right-shift by 3 bits and have those three bits "fall off the right end" of the integer. Thats what faulty (human) memory gets you! I probably would have tried val/8 rather than val*0.125, also forgetting that those could/will produce different results.

 

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

Last Edited: Mon. Apr 17, 2017 - 05:19 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you for the answer, Jim!

 

Reason for me asking is that I am genuinely interested in what is difficult when you study and learn coding in a "high-level" compiled language like C.

 

Your answer strengthens my hypothesis that one obstacle (or outright mystery ;-) ) is the concept of types. This seems to be extra so when previous experience is coding in assembler for a long time.

 

I have been thinking a lot in the past on how one should give a good coherent explanation of this concept. This awakened my thinking..

 

Best regards,

Johan

Happy 75th anniversary to one of the best movies ever made! Rick Blane [Bogart]: "Of all the gin joints, in all the towns, in all the world, she walks into mine."

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Johan - 

 

I think you may be correct. Most of my coding experience has been with assembler and I tend to use C like it is a "more powerful assembly language". I'm aware of types but they are sort of "oh,yes, types.... now lets see if I can remember how that works".

 

This is doubly interesting because a good fraction of my current programming is with a language called XOJO (cross platform object-oriented BASIC). That is a strongly typed environment but conversion between types is almost invisible, and, again, it almost fades into obscurity UNTIL you run into one of those rare situations where it has to be confronted, head-on. As I think about it, though, this is another situation (like assembler) where you pretty much don't have to worry about types. Interesting! I didn't choose that because of type handling but because of the cross-platform capability, but it has not helped.

 

Best wishes, 

 

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Since the original question has been answered I risk holding on to the sidetrack for a while. ;-)

 

I have no experience at all with XOJO, so won't comment on that.

 

Re "don't have to worry about types in assembler" this is also "think-worthy". Actually I see it just the other way around:

 

In assembler I always have to be aware of it. All of the time. The responsibility is completely on me. E.g. if I'm storing a few 16-bit integers and want to add two of them together it is on me to know that this needs one ADD followed by one ADC.

 

This is one aspect of "type" in high(er) level languages. It abstracts the details of the assembler, basic storage units (an 8-bit byte when we're talking about AVRs) and their relation to more complex "things" (I was about to type "type" there but that would just mess things up. Oops.. Just did ;-) ). This abstraction is not necessarily implying "type safety" which is a somewhat different aspect of types.

 

As a side note your surprise/memory-loss is OK. There is room for confusion here. Different high level languages go different ways with division:

- Some make int/int an int (e.g. "C", Java, C#...)

- Others make any division result, regardless of the types of the operands, a float (e.g. Pascal (where the name of the type is "real"))

- (Don't ask about COBOL ;-) )

 

BR,

Johan

Happy 75th anniversary to one of the best movies ever made! Rick Blane [Bogart]: "Of all the gin joints, in all the towns, in all the world, she walks into mine."

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

Last Edited: Mon. Apr 17, 2017 - 06:19 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the insight, Johan -

 

I really do appreciate your comments. You are correct, of course, about always having to have "types" right in the front of your mind when working in assembler. Guess I was thinking more differences in how mixed-type operations are handled in different environments. 

 

And, yes, I do consider the original question as solved.

 

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

Last Edited: Mon. Apr 17, 2017 - 06:53 PM