How to create function that accepts characters and integers

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

Im working on microchip studio with atmega8 and I want to create function(in C ) similar to lcd.print() from Arduino which accepts characters as well as integers and display it on lcd. I have succesfully created functions for printing texts and numbers on screen but occasionally i would like to print integer variables on lcd screen too. Can someone explain how functions like lcd.print() accept characters and integers ? Thanks.

This topic has a solution.
Last Edited: Tue. Jul 20, 2021 - 05:03 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 2

Rishi_kesh wrote:
which accepts characters as well as integers and display it on lcd.

 

Theres no real difference.  What makes them different per se, is how they are treated

 

char mychar,

is an 8 bit unsigned variable

 

uint8_t mychar;

is an 8 bit unsigned variable.

 

 

But if I write:

int8_t mychar;

Then mychar is a SIGNED 8 bit variable.

 

 

To accept two different types one could simply write:

void FOO(char mychar, int myinteger)

Then you do what you wish inside your function with each.

 

Jim

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

Last Edited: Tue. Jul 20, 2021 - 03:12 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 2

Arduino's print() family of functions uses function overloading (multiple functions with the same name but different parameters) to handle multiple types of input. C++ (which Arduino uses) supports function overloading, but C does not. With C, you'll either have the functions have different names (e.g. print_string( char const * ), print_character( char ), print_int( int )), or create a function that behaves like printf() (https://en.cppreference.com/w/c/...). sprintf() could be leveraged under the hood to do all the actual formatting.

build-avr-gcc: avr-gcc build script

toolchain-avr-gcc: CMake toolchain for cross compiling for the AVR family of microcontrollers

avr-libcpp: C++ standard library partial implementation (C++17 only) for use with avr-gcc/avr-libc

picolibrary: C++ microcontroller driver/utility library targeted for use with resource constrained microcontrollers

picolibrary-microchip-megaavr: picolibrary HIL for megaAVR microcontrollers

picolibrary-microchip-megaavr0: picolibrary HIL for megaAVR 0-series microcontrollers

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

apcountryman wrote:
or create a function that behaves like printf()

 

Or, create a function that keeps track of the cursor position in the LCD, and calls the appropriate Print_char() or Print_int() functions accordingly?

 

Jim

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

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

To accept two different types one could simply write:

void FOO(char mychar, int myinteger)

Then you do what you wish inside your function with each.

In this case wouldn't i need to necessarily provide 2 values (one character one integer) as input ? If i only provide integer value will the function automatically assign in to variable 'myinteger' ?

Last Edited: Tue. Jul 20, 2021 - 03:34 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Are you talking about turning thinhs from binary to human readable ASCII representation? Usual candidates are itoa() and sprintf().

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

I wasn't aware about function overloading! Now i see how they do it angel

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

Rishi_kesh wrote:
In this case wouldn't i need to necessarily provide 2 values (one character one integer) as input ?

 

Yes.  In your OP:

Rishi_kesh wrote:
which accepts characters as well as integers and display it on lcd.

 

Are you trying to auto sense the type?

 

JIm

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

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

I was wondering about how one function(like lcd.print) could take int or char at a time and print it to screen as it is(if char is provided) or process the value to convert it to individual ASCII values( if int is provided). apcountryman kinda cleared how its done on Arduino.

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

Are you trying to auto sense the type?

Yes. Is it even possible in C ?

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

Rishi_kesh wrote:

Are you trying to auto sense the type?

Yes. Is it even possible in C ?

 

I don't think so.  Look at my reply in #2.  Unless YOU implicitly tell what the type is of the variable how will the program/compiler know?

 

JIm

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

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

You can't do in C what can be done in C++, so why not just use normal C string functions, sprintf() to create a formatted string containing text + data and place it in a buffer, then send this string to your lcd_print_string() function?

 

 

Jim (not all freaks are named Jim, but it helps)

 

 

 

 

(Possum Lodge oath) Quando omni flunkus, moritati.

"I thought growing old would take longer"

 

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Rishi_kesh wrote:
Yes. Is it even possible in C ?
Not using exactly the same function name, no. "Overloading" is a feature of C++.

 

Of course in C you can have:

lcd_print_char('x');
lcd_print_int(12345);
lcd_print_float(3.141592);
lcd_print_string("hello");

// which is using...

void lcd_print_char(char c) {
    LCD_putc(c);
}

void lcd_print_int(int n) {
    char buff [14];
    itoa(buff, n, 10);
    for (int i=0; i < strlen(buff); i++) {
        LCD_putc(buff[i]);
    }
}

void lcd_print_int(float f) {
    char buff [14];
    dtostrf(f, 2, 3, buff);
    for (int i=0; i < strlen(buff); i++) {
        LCD_putc(buff[i]);
    }
}

void lcd_print_string(char * str) {
    while (*str) {
        LDC_putc(*str++);
    }
}

all that really changes in C++ is that it's pretty much the same code but they all provide different versions of the same thing:

Lcd lcd;

lcd.print('x');
lcd.print(12345);
lcd.print(3.141592);
lcd.print("hello");

// which is using...

class Lcd {
public:
    Lcd(void) {};

    void print(char c) {
        LCD_putc(c);
    }

    void print(int n) {
        char buff [14];
        itoa(buff, n, 10);
        for (int i=0; i < strlen(buff); i++) {
            LCD_putc(buff[i]);
        }
    }

    void print(float f) {
        char buff [14];
        drostrf(f, 2, 3, buff);
        for (int i=0; i < strlen(buff); i++) {
            LCD_putc(buff[i]);
        }
    }

    void print(char * str) {
        while (*str) {
            LDC_putc(*str++);
        }
    }
};

What's changed is that all the functions are now called print() and it's whether the passed parameter is char, int, float or char* that determines which one is called. 

 

But you still end up writing "different bodies" to handle different parameter types in different ways - there's no real "magic" here apart from the fact of C++ recognizing which parameter type is used and hence which of the overloads to call.

 

The upside for the user is simply that they don't have to remember "now is it lcd_print_int() or lcd_print_integer() or whatever?" - they just get to print() whatever it is and the code adapts.

Last Edited: Tue. Jul 20, 2021 - 04:36 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Rishi_kesh wrote:

Im working on microchip studio with atmega8 and I want to create function(in C ) similar to lcd.print() from Arduino which accepts characters as well as integers and display it on lcd. I have succesfully created functions for printing texts and numbers on screen but occasionally i would like to print integer variables on lcd screen too. Can someone explain how functions like lcd.print() accept characters and integers ? Thanks.

lcd.print() is a C++ overloaded function.   The Compiler knows the expression type at compile-time.   And calls the appropriate specific function.

 

God gave you printf() in C.   Far nicer to use than lcd.print() but you need to tell printf() the argument type.   e.g. printf("%04X", integer_expression);

You can create nicely formatted output on your LCD.   (or any output device)

 

I suggest that you just learn how to use printf() e.g. with UART or with LCD.

There should be plenty of tutorials on the Internet.

 

When you are experienced with using printf() you can inspect the library code.   It is quite tricky the way that it pulls the correct size of argument from the stack.

The actual formatting of the expressions is pretty straightforward.

 

David.

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

I see ! I need to stick with creating different functions for handling char and int values.

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

Rishi_kesh wrote:
I need to stick with creating different functions for handling char and int values.

or, as many have already suggested, just use printf/sprintf ...

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

I suggest that you just learn how to use printf() e.g. with UART or with LCD.

There should be plenty of tutorials on the Internet.

Yeah Thanks ! I will do that as i learn more about programming...

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

or, as many have already suggested, just use printf/sprintf ...

Im not sure how to use printf/sprintf for my lcd project at this point.But i will try to find out. Thanks!

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

Rishi_kesh wrote:
Im not sure how to use printf/sprintf for my lcd project at this point.But i will try to find out. Thanks!
Example in user manual:

 

https://www.nongnu.org/avr-libc/...

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

Rishi_kesh wrote:
Im not sure how to use printf/sprintf for my lcd

Using sprint is just a matter of creating text in a buffer, and then sending that text to your LCD:

char buffer[LCD_BUFFER_SIZE+1]; // "+1" to allow for the NUL termination

sprintf( buffer, format, args ... );

lcd_print_string( buffer );

 

clawson showed how to do printf direct to the LCD.

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

I suggest that you just learn how to use printf() 

 

For the avr, the printf is small enough to just use it whenever you can. Once you decide to use it, and learn how to use it, it will simplify so many things and eliminates all the other little functions that you otherwise need. 

 

A simple example in C-

https://godbolt.org/z/1GaoTnWzn

obviously the lcd low level code is missing, but the idea is there. In this case an lcd_print function was created, but can also deal with using fprintf and the rest of the stdio family of functions if wanted. Now you can print to the lcd, and the control codes in this case are simply \t for cls+home and \n for next line.

 

C++ has more options that result in better syntax or ease of creation/use, but the above shows C can also get the same results.

 

Probably none simpler than the avr for hooking your own put function into the mix. Can use it for uart, lcd, whatever you can dream up. When you get to an arm cortex-m, then not so simple anymore and you end up using snprintf with a temp buffer, then move the formatted data to the device. (I wan't happy with using snprintf on 32bit, so wrote a cout << style replacement and no longer use stdio functions there).

Last Edited: Tue. Jul 20, 2021 - 08:58 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

curtvm wrote:
Probably none simpler than the avr for hooking your own put function into the mix.

 

Actually, some parts from avrlibc were used to replace areas of newlibc (mostly the stdio streams stuff, I guess, e.g., printf) in picolibc, which allows using printf and still fit on memory-constrained ARM (and RISC-V) devices. My understanding is that newlibc allocates a substantial block of memory (>2k) on the heap to do all the tricky printf/scanf things, but avrlibc does all that work with nearly a dozen bytes in global memory. It looks like the developer had some headaches with floats. I hope that connecting put/get to the pico stdio stream will be similarly easy (ARM/picolibc is on my five-year plan).

 

update: link for those with time to kill disposable time: https://github.com/picolibc/pico...

Last Edited: Tue. Jul 20, 2021 - 07:40 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

ron_sutherland wrote:
but avrlibc does all that work with nearly a dozen bytes in global memory.
This in fact ( http://svn.savannah.gnu.org/view... ) :

 

 

So it's using an 11 byte buffer on the stack in fact. The float support seems to just use that same buffer:

 

 

so it presumably thinks that it is large enough for float too.

 

Last Edited: Wed. Jul 21, 2021 - 09:20 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

curtvm wrote:
When you get to an arm cortex-m, then not so simple anymore and you end up using snprintf with a temp buffer, then move the formatted data to the device. (I wan't happy with using snprintf on 32bit, so wrote a cout << style replacement and no longer use stdio functions there).

 

Please elaborate.    Surely you can use printf() on any target.   e.g. Unix, MAC, Windows, ARM, ...

You just have to set the output function for stdout to your desired device e.g. LCD

 

printf() is only fprintf(stdout)

 

Yes,  you might be careful with the number of formatted characters being sent to the output stream on a small target like an AVR.

Oh,  personally I think it is wise to use standard library functions whenever possible.   These are already debugged.   Much safer than you "rolling your own".

 

David.

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

I have a distant memory of the printf() in ARM's newlibc requiring you to have implemented _sbrk() or something? It's not as simple as the AVR-LibC solution for AVR (or Codevision for example).

 

A quick Google reminds me that it's something about needing to implement malloc/free - I think __sbrk may be a symbol that identifies a memory location where the heap is placed or something?

 

Either way I remember being surprised how difficult it was to use printf() after the relatively easy experience in AVR-LibC.

Last Edited: Wed. Jul 21, 2021 - 10:03 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have similar memories.

 

frown

 

I tend to just use the sprintf-to-buffer approach.

 

A number of chipmakers provide a "simple printf" of their own ...

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

I think what I was most interested in was that the ARM was supposed to be able to do "hosted printf" via the debugger. So you didn't need a UART-USB link separately, but, in theory, could pipe your debug printf()s back up the wire through the debugger and the IDE would show the output in some kind of terminal. But I remember it being a nightmare to try and get it to work!

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

Yes: in theory it's possible, but ...

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

I guess you are talking about the semihost stuff, that I don't understand, it looks like pico has code for a few CPU. I guess it can be connected to stdin and stdout, but I don't understand where it shows up (the other end of stream), are you saying it goes to the debugger?

 

https://github.com/picolibc/pico...

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

You just have to set the output function for stdout to your desired device e.g. LCD

All fine when you want just a single use printf, where you can override _write where you call to your device. Now get another device involved and its no longer simple. Anything else turns into a mess because of trying to fit into something that is not really suited to the smaller mcu. The only good option is to use snprintf and send the results where you want. Or you go chase the various smaller printf implementations and hope you find something good.

 

I'll take my 600 lines of header code that really only has a couple functions that do the hard work (numbers to strings, print strings), and a third that deals with floats/double if needed (if unused, there is no code). The number function is about 40 lines of code, the string 10, and float/double 30. The rest is all supporting code for the various options/modifiers. There is no parsing of strings, so the code is actually simple and there is not much to go wrong. Any problems that show up, show up at compile time. I also added a modifier setwmax(n) so can limit output, either to truncate output or to simply prevent rogue strings that are not 0 terminated from doing anything harmful (still possible, but less likely, as reading from addresses that are not readable usually sends you to an exception so hopefully truncated before that point with the max limit in place, or hope you hit a 0 before that).

 

It also becomes an snprinf replacement, as a buffer class can inherit the Format class just as anything else can, and can make additions to the buffer class that always keep it 0 terminated, and provide other useful functions inside the class. I created the Format code in the online compiler, so effectively the pc was where the code was created and tested, then simply moved to the mcu as it is all standard c++ code. using the pc means I can compare to printf and cout to see if what I have also acts the same.

 

stm32g031k8 simple example

empty main - 432 bytes
below code - 2992 bytes

 

Uart uart1{ Uart1_A9B7, 1000000 };
Uart uart2{ Uart2_A2A3, 1000000 };

int main(){
    u32 count = 0;
    while(1){
        uart1 
            << FG GREEN "Hello World : " 
            << Hex0x << setwf(8,'0') << count++
            << endl;

        uart2

            << FG GREEN "Hello World : " 
            << Hex0x << setwf(8,'0') << count++
            << endl;

        delayMS(10);

        }

}

 

This same code with a single uart in use, using printf and overriding _write, the code size is 6168 bytes. With snprintf and 2 uarts, 4376 bytes.

 

For an nRF52, I had about 30K used when using snprintf, and about 500 bytes more when I switched it all over to the Format class (mostly debugging info going out via seggerRTT which of course uses the Format class).

 

 

Last Edited: Wed. Jul 21, 2021 - 09:57 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ron_sutherland wrote:
I guess you are talking about the semihost stuff,

Yes.  There's also SWO.

 

And Segger have a thing called "RTT" where the debugger "pulls" from a RAM buffer: 

 

https://www.segger.com/products/debug-probes/j-link/technology/about-real-time-transfer/

 

clawson wrote:
"hosted printf" via the debugger. So you didn't need a UART-USB link separately

I guess that's less of an issue nowadays - as debuggers often now have a UART-USB built-in.

 

But it does still consume a hardware UART on the Target.

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...