General ANSI C: Converting float number to characters

Go To Last Post
81 posts / 0 new

Pages

Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello,

I face a problem.  I want to convert these 2 float numbers to characters and display them on my 16x2 LCD.

celsiusValue
fahrenheitValue

 

What functions should I use?

 

Please give me your opinions.  smiley

This topic has a solution.
Last Edited: Mon. Jun 7, 2021 - 04:13 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Arduino:

    lcd.print(celeiusValue);

 

C:

    sprintf(buf, "%f", celsiusValue); lcd_puts(buf);

 

Some C libraries might have ftoa()

GCC has dtostrf()

 

Note that most functions will let you set the number of decimals and let you format nicely.

 

For someone with such opinions that you express,   I would have thought that you know the answer anyway.

 

There are multiple ways to everything.

 

David.

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

My programme has this function already:

 

uint8_t row0_disp[16] = "1234567890123456";
lcd_writeString(row0_disp, 0);

 

 

Now, I don't know how to paste celsiusValue into row0_disp[16]

 

 

I know there is a function ftoa, but I can't find it in string.h

 

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

HKPhysicist wrote:
uint8_t row0_disp[16] = "1234567890123456";

You have 16 characters there, so you won't get a NUL termination - so this is not a proper C string.

 

HKPhysicist wrote:
I don't know how to paste celsiusValue into row0_disp[16]

you can't just "paste" it.

 

As David showed, you convert it to a string.

 

david.prentice wrote:
sprintf(buf, "%f", celsiusValue);

 

Your row0_disp would be David's buf

 

EDIT

 

add David quote

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Wed. Jun 2, 2021 - 04:46 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:
You have 16 characters there, so you won't get a NUL termination - so this is not a proper C string.

Oh come on -You're an experienced freak. You should recognise that array as a representation of a line of characters on an LCD display. He almost certainly does not want a zero termination there but instead I would expect he maintains trailing spaces to the end of line to completely overwrite previously written stuff..

 

 

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

    sprintf(buf, "%f", celsiusValue); lcd_puts(buf);

avr-gcc will not, by default, link in a version of sprintf() that has float support.

 

GCC has dtostrf()

avr-libc has dtostrf().  It's apparently not standard.

In non-AVR Arduino "Cores", dtostrf is implemented using ... sprintf()!  ( https://github.com/arduino/Ardui... )

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

My given functions and parameters:

uint8_t row0_disp[16] = "1234567890123456";
lcd_writeString(row0_disp, 0);

celsiusValue
 

 

 

I find that ftoa is only in C90.

 

Any similar function in C99?

 

 

I have tried memcopy but it requires me to input 3 parameters.  I only have 2 parameters:

celsiusValue

row0_disp

 

sad

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

I Googled " lcd_writeString" without success.   Please post a link to your "lcd" library documentation.

 

The first lcd_writeString() argument has no NUL terminator.   What is the second argument ( 0 ) supposed to do ?

 

I gave you possible C library functions.   You simply Google for the function description and use.

 

Please give a real life example that you want to display.   e.g.

    float expr = 123.456;

    // I want to display "123.46" on the LCD at row #2, column #5

 

David.

Last Edited: Thu. Jun 3, 2021 - 01:04 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

HKPhysicist wrote:
I find that ftoa is only in C90.

 

Any similar function in C99?

David gave you two to choose from - what more do you want?

 

  1. sprintf is standard.
  2. dtostrf from avr-libc:
    https://www.nongnu.org/avr-libc/...

 

 

I have tried memcopy but it requires me to input 3 parameters.  I only have 2 parameters:

celsiusValue

row0_disp

Go on - the 3rd parameter is just the size of your buffer,  and you know what that is

 

But there's no need for memcpy with either of those two functions mentioned above

 

EDIT: Or were you trying to use memcpy to pad the string out to 16 characters - see #11

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Thu. Jun 3, 2021 - 02:07 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You appear to be making heavy weather of this. Two suggestions have already been made. Perhaps it is not clear to you how to use them? Say you have:

float celsiusValue = 23.141592;

then to display it first you need a character array to put the display characters into like:

char tempString[20];

then you use one of these to ways to get the float value converted into a string of characters:

sprintf(tempString, "%f", celsiusValue);
dtostrf(celsiusValue, 5, 2, tempString);

In either case you end up with tempString[] containing something like "23.146" or whatever. All that remains is to then output this to your LCD:

lcd_writeString(tempString, 0);

(I assume the ,0 in this is saying which line you want it to appear on?)

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

clawson wrote:
In either case you end up with tempString[] containing something like "23.146" or whatever. All that remains is to then output this to your LCD:

lcd_writeString(tempString, 0);

That was my assumption, but Neil seems to think that lcd_writeString() is not intended to work with a C NUL-terminated string:

N.Winterbottom wrote:
He almost certainly does not want a zero termination there but instead I would expect he maintains trailing spaces to the end of line to completely overwrite previously written stuff..

in which case there would be an extra step of padding the result from sprintf or dtostrf with spaces. sprintf helps with that, as it returns the number of characters generated.

 

EDIT: maybe this is where memcpy() came in ?

(I assume the ,0 in this is saying which line you want it to appear on?)

that'd be my guess

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Thu. Jun 3, 2021 - 02:04 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 2

david.prentice wrote:
I Googled " lcd_writeString" without success.   Please post a link to your "lcd" library documentation.
THIS!

 

None of us here can possibly guess what the API to lcd_writeString() is without the library being used being identified.

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

We can only guess.   I have never heard of lcd_writeString()

 

The OP was asking about C.   So we are not talking about an object from a C++ class.

I suspect that the function expects a char array.   e.g. a regular NUL terminated string of char

 

Surely he must have lots of clever Chinese neighbours who could help him.

If he is too proud to ask,   he can always Google.   I assume that Google works in HongKong.

 

David.

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

I googled for "lcd_writeString(row0_disp" (with quotes so it looks for the exact character sequence) and the one and only hit on the entire internet was: https://www.microchip.com/forums...

 

Rather curiously that is a PIC not AVR support page but, given other posts from HKPhysicist (who seems to be a big PIC/MPLAB fan) I perhaps should not be too surprised? So does this LCD library originate with PIC perhaps? Maybe we're talking about a PIC->AVR port here?

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

I can find

void LCD_Write_String(char*); // Write A String To LCD

LCDWriteString(unsigned char *) – For Writing Text Message at Current cursor position.

 

But nothing with the OP's spelling.  And nothing with two arguments.

 

It seems crazy.   A reader only has to post a link or quote a library example by name.

We can see exactly what the problem is.   And a solution appears within minutes or hours.

 

And members are happy to answer questions or explain some document.

 

David.

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

It is because I am running MPLAB X IDE with a MCC library for this Click Board:

https://www.mikroe.com/lcd-mini-...

 

It was hand-written by Microchip Engineers.  I talked with the Curiosity Guy Christopher a few times.  He debugged this library for me.  That is why I have become a die-hard developer of Microchip.  cheeky

 

Their tutorials suggest to avoid using print function in MCU development.  no

Last Edited: Thu. Jun 3, 2021 - 04:11 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Okay, I find these functions written by a netizen.  It may work:

https://www.geeksforgeeks.org/co...

 

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

You still have answered the question of what that  lcd_writeStrin() function actually does - what are its 2 parameters ?

 

HKPhysicist wrote:
Okay, I find these functions written by a netizen.  It may work

So you're ignoring the 2 already given & explained?

 

How is that one any better?

 

The linked article even states that sprintf would be the easier way to do it!

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Thu. Jun 3, 2021 - 04:24 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sprintf will eat up much memory as Microchip told me.  sad

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

Because I don't understand them.  I can only understand simple functions: cheeky

 

void lcd_sendNibble(uint8_t nibble, bool RSbit){
    uint8_t packet = (nibble << 4) | (RSbit << 2);
    expander_setOutput(packet);
    expander_setOutput(packet | (1<<3));
    DELAY_milliseconds(1);
    expander_setOutput(packet);
    DELAY_milliseconds(40);
}

void lcd_sendByte(uint8_t byte, bool RSbit){
    uint8_t nibbleHigh = byte >> 4;
    uint8_t nibbleLow = byte & 0xF;
    uint8_t packetHigh = (nibbleHigh << 4) | (RSbit << 2);
    uint8_t packetLow = (nibbleLow << 4) | (RSbit << 2);

    expander_setOutput(packetHigh);
    DELAY_milliseconds(2);
    expander_setOutput(packetHigh | (1<<3));
    DELAY_milliseconds(2);
    expander_setOutput(packetLow);
    DELAY_milliseconds(2);
    expander_setOutput(packetLow | (1<<3));
    DELAY_milliseconds(40);
}

void lcd_returnHome(void){
    lcd_sendByte(0b10, false);
    DELAY_milliseconds(2);
}

void lcd_clearDisplay(void){
    lcd_sendByte(0b1, false);
    DELAY_milliseconds(2);
}

void lcd_setAddr(uint8_t row, uint8_t character){
    lcd_sendByte(0x80 | (character + (row*40)), false);
}

void lcd_writeChar(uint8_t character){
    lcd_sendByte(character, true);
}

void lcd_writeString(uint8_t* string, uint8_t row) {
    lcd_setAddr(row, 0);
    uint8_t i = 0;
    for (i = 0; i < 16; i++) {
        if (string[i]) {
            lcd_writeChar(string[i]);
        }
    }
    lcd_returnHome();
}

void lcd_setContrast(uint8_t contrast){
    digipot_setWiper(contrast);
}

void lcd_setup(){
    LATAbits.LATA3 = 1; /* set LCDMini_nCS output high */
    LATAbits.LATA1 = 1; /* set LCDMini_nCS2 output high */
    LATDbits.LATD0 = 1; /* set LCDMini_nReset output high */
    expander_setup();
    expander_setOutput(0);
    DELAY_milliseconds(40);
    lcd_sendNibble(0b11, false);
    DELAY_milliseconds(10);

    lcd_sendNibble(0b11, false);
    DELAY_milliseconds(10);
    lcd_sendNibble(0b11, false);
    DELAY_milliseconds(10);
    lcd_sendNibble(0x2,false);
    lcd_sendByte(0x2C, false);
    lcd_sendByte(0b1100, false);
    lcd_sendByte(0x06, false);
    lcd_sendByte(0x0C, false);
    DELAY_milliseconds(2);
    lcd_returnHome();
    lcd_clearDisplay();
}

 

Last Edited: Thu. Jun 3, 2021 - 04:39 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

I googled for "lcd_writeString(row0_disp" (with quotes so it looks for the exact character sequence) and the one and only hit on the entire internet was: https://www.microchip.com/forums...

 

Rather curiously that is a PIC not AVR support page but, given other posts from HKPhysicist (who seems to be a big PIC/MPLAB fan) I perhaps should not be too surprised? So does this LCD library originate with PIC perhaps? Maybe we're talking about a PIC->AVR port here?

 

Yes, it is me.  I helped to debug it until its present fine status.  Microchip engineers also use this click board for many demo codes.

I can control this LCD contrast and backlight through a potentiometer.  yes

Last Edited: Thu. Jun 3, 2021 - 04:35 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:

sprintf(buf, "%f", celsiusValue); lcd_puts(buf);

 

 

 

Okay.  Let me try sprintf first and check the overall codes quality.  cool

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

HKPhysicist wrote:
I find that ftoa is only in C90.

 

Huh? There's no such thing as `ftoa` and there has never been, neither in C90 nor in any other C standard. The only standard conversion routine for this purpose in C is `printf` family. There are no alternatives. 

Dessine-moi un mouton

Last Edited: Thu. Jun 3, 2021 - 04:43 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

HKPhysicist wrote:
Because I don't understand them

But you must at least know what they do, and what the parameters are - otherwise how you you possibly use them correctly?!

 

You should be able to point us to the documentation, or copy/paste the relevant section.

 

void lcd_writeString(uint8_t* string, uint8_t row) {
    lcd_setAddr(row, 0);
    uint8_t i = 0;
    for (i = 0; i < 16; i++) {
        if (string[i]) {
            lcd_writeChar(string[i]);
        }
    }
    lcd_returnHome();
}

that will not stop at a NUL - it will always go through 16 bytes, and send everything that's not a NUL.

 

As the C programming language has a specific meaning for "string" - it's unhelpful at best and misleading at worst  to call anything else a string in a C program.

 

frown

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Cliff's guess was correct.   Never in my wildest dreams did I consider this API:

void lcd_writeString(uint8_t* string, uint8_t row);

@ HKPhysicist ,

 

I suspect that there is an "lcd.h" to go with this "lcd.c" stuff.   And there might even be a "lcd.html" or "lcd.pdf" that documents the library code.

 

Yes, sprintf() is the official "C" way to format human readable data.   It does take up quite a lot of Flash memory.   And most IDEs will link with a cut-price printf() that omits floating point as a default.

 

Seriously,  you should apply some common sense.   Any C program running on 16k and bigger AVR can afford the memory used by the full-fat printf() functions.

 

Obviously you will avoid this if you are using a Tiny2313.

In which case you will try and use integer-only methods.   Not too difficult but not as easy as the "Standard C Library" method.

 

Most beginners have plenty of spare Flash memory.   Or they can explain their hardware and ask advice.

Most beginners start with a 32kB ATmega328P e.g. in a Uno or Nano.

 

Some beginners think it is easier to start with an 8-pin ATtiny25.   This is not a good idea.

However it is an interesting challenge for an experienced programmer.    

I am sure that you have experience with 2kB PIC and with 32kB PIC and understand the differences.

 

David.

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

david.prentice wrote:
Cliff's guess was correct

Almost - but Neil was also right about it not being a NUL-terminated string

 

So it won't "just work" with the output of any standard C string functions - including sprintf - it will need padding to 16 characters.

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

HKPhysicist wrote:
I can only understand simple function
It'd be interesting to know:

 

a) what micro this is? If it's 1K/2K I can maybe understand your concerns about using sprintf("%f") as it can cost 2K. If the micro is 8/16/32K then I don't see the issue. If it is a "small one" that is why dtostrf() exists - but it still costs a bit (I think it might be more like 0.7K).

 

b) in the code you quote it would be interesting to know what expander_setoutput() is doing. Is this a small pin device that is then connected to something like a 74HC595 port expander?

 

c) are you aware of "Fleury"? That is: http://www.peterfleury.epizy.com... this is direct support to an LCD but it expects the LCD module (HD44780) pins to be connected direct to the micro, not via a port expander - but being so widely used you will find a lot of people who use this library and can offer help.

 

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

@ HKPhysicist

I think you should try compiling with sprintf vs the ftoa you linked and see exactly what the difference is in the file sizes.

You may be surprised...

David

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

Yes, there is a lcd.h but it contains only declarations. Nothing more information:  frown

 

#ifndef LCD_H
#define	LCD_H

#include <stdint.h>

void lcd_setup(void);
void lcd_returnHome(void);
void lcd_clearDisplay(void);
void lcd_writeChar(uint8_t character);
void lcd_writeString(uint8_t* string, uint8_t row);
void lcd_setContrast(uint8_t contrast);
void lcd_setAddr(uint8_t row, uint8_t character);

#endif

 

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

Ha - Interesting.

void lcd_writeString(uint8_t* string, uint8_t row) {
    lcd_setAddr(row, 0);
    uint8_t i = 0;
    for (i = 0; i < 16; i++) {
        if (string[i]) {
            lcd_writeChar(string[i]);
        }
    }
    lcd_returnHome();
}

So if he does zero terminate, then left-over crap at the trailing end of the LCD line doesn't get cleared.

If he does not zero terminate, then the complete LCD line gets written.

 

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

awneil wrote:

david.prentice wrote:
Cliff's guess was correct

Almost - but Neil was also right about it not being a NUL-terminated string

 

So it won't "just work" with the output of any standard C string functions - including sprintf - it will need padding to 16 characters.

 

It is.  [16] declaration will add the last \0 automatically.

uint8_t row0_disp[16] = "1234567890123456"

 

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

clawson wrote:

HKPhysicist wrote:
I can only understand simple function
It'd be interesting to know:

 

a) what micro this is? If it's 1K/2K I can maybe understand your concerns about using sprintf("%f") as it can cost 2K. If the micro is 8/16/32K then I don't see the issue. If it is a "small one" that is why dtostrf() exists - but it still costs a bit (I think it might be more like 0.7K).

 

b) in the code you quote it would be interesting to know what expander_setoutput() is doing. Is this a small pin device that is then connected to something like a 74HC595 port expander?

 

c) are you aware of "Fleury"? That is: http://www.peterfleury.epizy.com... this is direct support to an LCD but it expects the LCD module (HD44780) pins to be connected direct to the micro, not via a port expander - but being so widely used you will find a lot of people who use this library and can offer help.

 

I am testing this on a PIC18F47Q10 with 128KB.  It has a built-in temperature sensor.  Cool! yes

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

HKPhysicist wrote:
  [16] declaration will add the last \0 automatically.

uint8_t row0_disp[16] = "1234567890123456"

No, it won't - see #4

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

N.Winterbottom wrote:
if he does zero terminate, then left-over crap at the trailing end of the LCD line doesn't get cleared.

indeed; see #24 - it will write whatever leftover crap happens to be in the buffer to the trailing LCD positions.

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:

N.Winterbottom wrote:
if he does zero terminate, then left-over crap at the trailing end of the LCD line doesn't get cleared.

indeed; see #24 - it will write whatever leftover crap happens to be in the buffer to the trailing LCD positions.

 

 

It is easy.  I simply add these 2 lines before sprintf.  Microchip's official library is very easy to read and to use:  wink

lcd_clearDisplay();
lcd_returnHome();
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

HKPhysicist wrote:

It is.  [16] declaration will add the last \0 automatically.

uint8_t row0_disp[16] = "1234567890123456"

Where will it place this 17th char "\0" in your disp[16] array? 

Check your map file and see what is getting clobbered by this action.

 

Jim

 

 

 

 

(Possum Lodge oath) Quando omni flunkus, moritati.

"I thought growing old would take longer"

 

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

HKPhysicist wrote:

awneil wrote:

 

 

david.prentice wrote:

Cliff's guess was correct

 

Almost - but Neil was also right about it not being a NUL-terminated string

 

So it won't "just work" with the output of any standard C string functions - including sprintf - it will need padding to 16 characters.

 

It is.  [16] declaration will add the last \0 automatically.

uint8_t row0_disp[16] = "1234567890123456"

 

 

No, it won't. If you specify array size as 16 and also supply an initializing string literal of length 16, nothing will get "added automatically" to the array. The trailing zero terminator will get dropped. In the above example `row0_disp` is not a string, i.e. it is not zero terminated.

 

This is a C-specific feature, which does not exist in C++. In C++ the above initialization would be considered ill-formed.

Dessine-moi un mouton

Last Edited: Thu. Jun 3, 2021 - 07:29 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ki0bk wrote:

Where will it place this 17th char "\0" in your disp[16] array? 

Check your map file and see what is getting clobbered by this action.

 

Nothing will get clobbered by this. The terminating '\0' will simply get dropped. This is a classic and well-defined feature of C language, intended to provide support for so called "fixed-width strings".

 

Dropping the trailing '\0' when initializing a character array is an archaic obsolete feature (C++ never bothered to allow this), but it still exists in C.

Dessine-moi un mouton

Last Edited: Thu. Jun 3, 2021 - 07:37 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

HKPhysicist wrote:
Their tutorials suggest to avoid using print function in MCU development.  no
Yet examples of standard output, or alternatively, Data Visualizer (Microchip Studio extension, MPLAB X plug-in, application)

Microchip Technology partners create the displays; Microchip Technology creates MCU for segment LCD (up to 160 segments for XMEGA B, up to 480 segments for PIC24)

 

https://github.com/microchip-pic-avr-examples/?q=print

Atmel AVR XMEGA B Manual (page 299)

PIC24F GU/GL/GP Family | Microchip Technology

on sale this month :

Part Number: DM240018 - PIC24F LCD and USB Curiosity Development Board | Microchip Technology Inc. | World's Largest Inventory of Microchip Products

 

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

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

HKPhysicist wrote:
I am testing this on a PIC18F47Q10 with 128KB. 
Then you would be far better off asking at:

 

https://www.microchip.com/forums/

 

Sure Microchip "own" and control both those forum and Freaks but Freaks is primarily for AVR support. We don't know what the LIBC with the PIC compilers is likely to have in the way of "ftoa" style functions. It almost certainly does NOT have dtostrf() that's for sure. The people who use PIC on the Microchip forum will have a much clearer idea of what their compilers offer the programmer.

 

EDIT oh and if it is a 128K micro then surely you have no worries using a function like sprintf(). Even a hugely inefficient implementation on a "difficult" CPU cannot surely "cost" more than about 4K for %f support?

Last Edited: Fri. Jun 4, 2021 - 08:54 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:

 

indeed; see #24 - it will write whatever leftover crap happens to be in the buffer to the trailing LCD positions.

 

HKPhysicist wrote:
It is easy.  I simply add these 2 lines before sprintf.  Microchip's official library is very easy to read and to use:  wink

lcd_clearDisplay();
lcd_returnHome();

That won't help - you will still get whatever leftover crap happens to be in the buffer written into the trailing LCD positions

 

Example:




+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '0' | '1' | '2' | '3' | '4' | '5' | '6' |  initial row0_disp[]
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+

float celsiusValue = 23.141592;
sprintf( row0_disp"%f", celsiusValue );

+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| '2' | '3' | '.' | '1' | '4' | '1' | '5' | '9' | '2' | NUL | '1' | '2' | '3' | '4' | '5' | '6' |  result in row0_disp[]
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
                                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   leftover crap in the buffer! 

lcd_writeString( row0_disp );

+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| '2' | '3' | '.' | '1' | '4' | '1' | '5' | '9' | '2' |     | '1' | '2' | '3' | '4' | '5' | '6' |  display on LCD ^
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ 
                                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   will appear on the display!

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:

awneil wrote:

 

indeed; see #24 - it will write whatever leftover crap happens to be in the buffer to the trailing LCD positions.

 

HKPhysicist wrote:
It is easy.  I simply add these 2 lines before sprintf.  Microchip's official library is very easy to read and to use:  wink

lcd_clearDisplay();
lcd_returnHome();

That won't help - you will still get whatever leftover crap happens to be in the buffer written into the trailing LCD positions

 

Example:




+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '0' | '1' | '2' | '3' | '4' | '5' | '6' |  initial row0_disp[]
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+

float celsiusValue = 23.141592;
sprintf( row0_disp"%f", celsiusValue );

+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| '2' | '3' | '.' | '1' | '4' | '1' | '5' | '9' | '2' | NUL | '1' | '2' | '3' | '4' | '5' | '6' |  result in row0_disp[]
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
                                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   leftover crap in the buffer! 

lcd_writeString( row0_disp );

+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| '2' | '3' | '.' | '1' | '4' | '1' | '5' | '9' | '2' |     | '1' | '2' | '3' | '4' | '5' | '6' |  display on LCD ^
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ 
                                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   will appear on the display!

 

 

I see.

 

I recall last time I tried ftoa on C90.  There were also crap left.  I then defined row0_disp[16] as a long string of " ".  It solved the problem.

 

I also find sprintf on Brian's ANSI C book.  I will test it this weekend.

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

HKPhysicist wrote:
I recall last time I tried ftoa on C90.  There were also crap left.

Of course there would be: the NUL marks the end of the string - why would it do anything after that?

 

  I then defined row0_disp[16] as a long string of " ".  It solved the problem.

Not really - it just masked the symptoms.

 

The underlying problem is that your function is not written to work with C strings.

 

Why not just fix the function - make it stop at the NUL.

 

It could either clear the line first, or write spaces after the end of the string.

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
sprintf( row0_disp"%f", celsiusValue );

 

How do I write sprintf if I want to show number in this form? 

 

123.12

 

It should be good enough to show room temperature.

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

It's the same standard format specifiers as printf() - see any C reference.

 

eg, https://www.cplusplus.com/reference/cstdio/printf/ (don't worry about "cplusplus" - it's the same for C)

 

EDIT

 

That page even has an example that you can edit & run online.

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Fri. Jun 4, 2021 - 09:28 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Why do you need floating point printf at all?

 

Separate the result into a whole number part and a fraction, then print the two with a decimal point between them:

 

// warning - untested code - beware of assumptions
// two decimal place print

float temp;
int whole;
int frac;

    whole = (int) temp;
    frac = (int)((temp - (float) whole) * 100);
    printf ("%03d.%02d" whole, frac);

Neil

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

Converting floating point values to characters is very hard. I have seen multiple top-tier C programmers trying, and failing, to debug edge cases in this. (Why weren't they just using printf, you ask? Because we were the library maintainer for the OS, and someone found an edge case bug in our float conversion...)

 

In practice, it is probably the case that you will be better off converting to an integer value at a suitable scale, converting that to digits, and adding a decimal point yourself.

 

And yes, that lcd_writeString function is horrible. It should not continue writing after reaching a NUL.

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

the_real_seebs wrote:
And yes, that lcd_writeString() function is horrible. It should not continue writing after reaching a NUL.

 

It will stop writing if it reaches a NUL.

 

The discussion arose because the initialised array does not contain a NUL.   

 

It is fairly likely that there will be a NUL somewhere in the memory.   Even if it means wrapping round to the beginning of registers / SRAM.

However,  if this saviour NUL is more than 64 bytes away from &row0_disp[0] you will see characters being printed on the second row of the LCD.

 

In practice the random saviour NUL is nearer.   The lcd_writeString() will stop writing to the HD44780 row #0 memory out of human view.

 

I cannot believe that a thread can get to message #48 and the OP still does not understand that you need

char row0_disp[16] = "1234567890123456";  //allocates 16 bytes i.e. without NUL
char row0_disp[17] = "1234567890123456";  //allocates 17 bytes i.e. with NUL
char row0_disp[] = "1234567890123456";  //allocates 17 bytes i.e. with NUL

David.

 

 

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

david.prentice wrote:
It will stop writing if it reaches a NUL

No, it won't:

void lcd_writeString(uint8_t* string, uint8_t row) {
    lcd_setAddr(row, 0);
    uint8_t i = 0;
    for (i = 0; i < 16; i++) {
        if (string[i]) {
            lcd_writeChar(string[i]);
        }
    }
    lcd_returnHome();
}

all it does is check for NUL and not write it - it does not exit the loop there!

 

So the loop carries on writing whatever follows the NUL

 

The discussion arose because the initialised array does not contain a NUL.   

 

EDIT

 

So, in fact, after skipping a NUL it won't even over-write the entire LCD row - so my diagram in #41 is not quite right ...

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Sat. Jun 5, 2021 - 07:02 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Oops.   I had never actually studied the code posted in #20

 

I simply read the signature i.e. to see the names of the arguments.

And just assumed that it wrote a NUL-terminated string.

 

The lcd_setAddr() function in #20 is wrong too.

 

I suspect that there are several other "features" in #20.

Which is why it seems wise to use proven library code whenever possible.

 

David.

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

david.prentice wrote:
I simply read the signature i.e. to see the names of the arguments.

And just assumed that it wrote a NUL-terminated string.

I think that is entirely reasonable:

in #24, I wrote:
As the C programming language has a specific meaning for "string" - it's unhelpful at best and misleading at worst  to call anything else a string in a C program.

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...

Pages