actually using itoa() with Peter Fleury's LCD library - Page 1
Forum section: electronics / general

author: Simon
author_rank: Unknown
timestamp: October 30, 2019, 03:15:53 pm
content: Hopefully this topic will get some decent replies and anyone else like me will find it in the future and find it helpfulI need to print a variables value on an LCD. Peters library can only print characters and strings presumably relying on itoa() rather than rewrite what already exists:lcd_puts (const char *s)char* itoa ( int val,char * s,int radix)So what do I do with this? I have an 8 bit value (0-100) that I need to put on the screen. Do I do something like:Code:lcd_puts (itoa(my_value, out_put, 4);I think I have seen the output (char * s) setup as an array on other sites trying to explain it.

author: edavid
author_rank: Super Contributor
timestamp: October 30, 2019, 03:25:16 pm
content: I don't think you want radix 4 - is that supposed to be the string length?If so, try something like this:Code:char buf;sprintf(buf, "%4d", my_value);lcd_puts(buf);

author: Simon
author_rank: Unknown
timestamp: October 30, 2019, 03:30:07 pm
content: sorry radix should have been 10. I need a buffer of 4, 3 characters plus the string termination

author: Simon
author_rank: Unknown
timestamp: October 30, 2019, 03:31:44 pm
content: so is "s" supposed to be the buffer length? and the function returns the start address of the string?

author: Masa
author_rank: Contributor
timestamp: October 30, 2019, 03:32:53 pm
content: The third parameter in itoa() is the base, so you would probably want to have 10 there instead of 4.You need to have empty array for the resulting string, and give pointer to that as parameter to the itoa.Code:int my_value = 3;char display_message = {""};itoa(my_value, display_message, 10);lcd_puts(display_message);You could also use sprintf, if you want to have leading zero's or other formatting to the number string.Code:int my_value = 3;char display_message = {""};sprintf(display_message, "%d", my_value);lcd_puts(display_message);If you want to have it with leading zeros and 4 digit precision, you can format the sprintf like this:Code:sprintf(display_message, "%04d", my_value);

author: rstofer
author_rank: Super Contributor
timestamp: November 01, 2019, 07:49:05 pm
content: I would expect sprintf() to bring in a LOT of code whereas itoa() is fairly lightweight. In fact, I usually copy the code for itoa() right out of "The C Programming Language" (Kernighan and Ritchie) so that I don't bring in ANY library code. For memory constrained projects, you are often better off writing your own string and conversion functions. Among other things, your own string functions won't require a heap.Just about everything you will ever need in the way of library code is in that book.Code:#include <stdio.h>int mystrlen(char *s) /* return length of string s */{int n;for (n = 0; *s != '\0'; s++)n++;return (n);}void reverse(char s[]) /* reverse string s in place */{int c, i, j;for (i = 0, j = mystrlen(s)-1; i < j; i++, j--) {c = s;s = s;s = c;}}void itoa(int n, char s[]) /* convert n to characters in s */{int i, sign;if ((sign = n) < 0) /* record sign */n = -n;i = 0;do { /* generate digits in reverse order */s[i++] = n % 10 + '0'; /* get next digit */} while ((n /= 10) > 0); /* delete it */if (sign < 0)s[i++] = '-';s = '\0';reverse(s);}int main(void){char s; /* changed length to accommodate a 32 bit integer plus a sign plus a NULL */itoa(-123,s);puts(s);return (0);}REVISED to ANSI C You should probably have the original version of the book plus the newer ANSI version.This code is known to work BUT... The strlen() function has to be renamed to avoid conflict with the library function so I called it mystrlen()This is pretty short code and it doesn't use the heap.===========================================================================================]Be aware that this algorithm pukes on -2147483648 which is the maximum negative number. You can't do n = -n when n is the maximum negative number because it exceeds the range of the maximum positive number. I suppose there is a way to code around it and, obviously, it's been done. I just don't know if it matters in any application where we're dealing with much smaller numbers.

author: thm_w
author_rank: Super Contributor
timestamp: November 01, 2019, 10:13:30 pm
content: There are lightweight printf libraries, I used this one:https://github.com/mpaland/printf

author: I wanted a rude username
author_rank: Frequent Contributor
timestamp: November 01, 2019, 10:52:02 pm
content: Quote from: rstofer on November 01, 2019, 07:49:05 pmK&R's code is elegant. Especially how it adapts depending on the magnitude of n, avoiding wasted operations.I once re-implemented atoi() to avoid its modulos and divisions, which are slow on AVR ... a total of thousands of cycles if fed a large 32-bit number. The algorithm counted the value of each decimal place by iteratively subtracting progressively smaller powers of 10 from it. This was indeed tighter and much quicker for large numbers, but in hindsight I would have learned more from meditating upon K&R's algorithm ... and the debug time would have been shorter.Quote

author: T3sl4co1l
author_rank: Super Contributor
timestamp: November 02, 2019, 12:20:47 am
content: Mind, using built in library functions usually results in tighter code -- it's tightly integrated with the compiler so that minimal overhead can be emitted. Here's an example from the project I'm playing with right now;Code:00000fcc <__itoa_ncheck>:fcc:bb 27eorr27, r27fce:4a 30cpir20, 0x0A; 10fd0:31 f4brne.+12; 0xfde <__itoa_ncheck+0x12>fd2:99 23andr25, r25fd4:22 f4brpl.+8; 0xfde <__itoa_ncheck+0x12>fd6:bd e2ldir27, 0x2D; 45fd8:90 95comr25fda:81 95negr24fdc:9f 4fsbcir25, 0xFF; 255fde:0c 94 f2 07jmp0xfe4; 0xfe4 <__utoa_common>00000fe2 <__utoa_ncheck>:fe2:bb 27eorr27, r2700000fe4 <__utoa_common>:fe4:fb 01movwr30, r22fe6:55 27eorr21, r21fe8:aa 27eorr26, r26fea:88 0faddr24, r24fec:99 1fadcr25, r25fee:aa 1fadcr26, r26ff0:a4 17cpr26, r20ff2:10 f0brcs.+4; 0xff8 <__utoa_common+0x14>ff4:a4 1bsubr26, r20ff6:83 95incr24ff8:50 51subir21, 0x10; 16ffa:b9 f7brne.-18; 0xfea <__utoa_common+0x6>ffc:a0 5dsubir26, 0xD0; 208ffe:aa 33cpir26, 0x3A; 581000:08 f0brcs.+2; 0x1004 <__utoa_common+0x20>1002:a9 5dsubir26, 0xD9; 2171004:a1 93stZ+, r261006:00 97sbiwr24, 0x00; 01008:79 f7brne.-34; 0xfe8 <__utoa_common+0x4>100a:b1 11cpser27, r1100c:b1 93stZ+, r27100e:11 92stZ+, r11010:cb 01movwr24, r221012:0c 94 0b 08jmp0x1016; 0x1016 <strrev>As you can see, it's no ordinary function, it has multiple entry points! There is no preamble, saving registers or setting a stack frame, as it doesn't use either (only clobber registers (r18-r25) are used, and the buffer is external).Heh. That's silly, and a little annoying: strrev isn't called from anywhere else, and it immediately follows this call (0x1016 is the very next instruction). Wasted jump. One of the downsides to linking premade object (I think?), it doesn't try to optimize it.Anyway, can be better than compiled code, but clearly, also can be worse in some respects. YMMV.One notable downside is whether the libraries include different platform support or not. ATtiny doesn't do MUL (IIRC?). So you have to use subtraction or (shift-accumulate) division.If you're only using chars and not ints, you could save even more (only needs to parse 3 digits, not 5?), but if you need both sizes, you're stuck with the bigger one.If you do have MUL handy, you can implement division by 10 as multiplication by 6553, keeping a few extra bits to account for the fact that it's actually 6553.6 in fixed point (which requires 24 bits; avr-gcc supports __uint24 if you wish to do it in C). I've written this before (in asm) and it's competitive in speed and size.Tim

author: Nominal Animal
author_rank: Super Contributor
timestamp: November 02, 2019, 03:06:10 pm
content: Quote from: Simon on October 30, 2019, 03:15:53 pmCreate a wrapper function:Code:void lcd_put_uint8(uint8_t value){char buffer;char *p = buffer + sizeof buffer;/* Construct number from right to left, starting with the end-of-string mark. */*(--p) = '\0';do {*(--p) = '0' + (value % 10);value /= 10;} while (value > 0);lcd_puts(p);}The buffer needs to be one longer than the longest value supplied. Forint32_t:Code:void lcd_put_int32(int32_t value){char buffer;char *p = buffer + sizeof buffer;uint32_t u = (value < 0) ? -value : value;/* Construct number from right to left, starting with the end-of-string mark. */*(--p) = '\0';do {*(--p) = '0' + (u % 10);u /= 10;} while (u > 0);/* Prepend sign, if necessary. */if (value < 0)*(--p) = '-';lcd_puts(p);}Note thatpinitially points to past the end of the buffer, and then to the first character in the buffer, so it is important to decrementpbefore prepending a new character. That is what*(--p) = CHAR;does: decrementspfirst, then dereferences it, assigning a character there.Because of the way they work,itoa()must use a static (global) buffer. The wrapper function, on the other hand, uses the stack for the small buffer, and only for the duration of thelcd_puts()call.

author: Jeroen3
author_rank: Super Contributor
timestamp: November 02, 2019, 04:01:56 pm
content: If you are working with a display you're going to need some fancy string printing soon anyway.Just use snprintf. It's easy. It should be included in your toolchain.Code:char display;int value;snprintf(display, sizeof(display),"%03d", value);You may be able to choose whether you want include the %f option with linker flags. Since that takes the most ROM.If it then still doesn't fit in ROM, then maybe go find a lighter version, but I'm afraid you might have made the wrong choice somewhere leading up to this.

author: Jan Audio
author_rank: Frequent Contributor
timestamp: December 09, 2019, 05:34:25 pm
content: Code:const char str1[ 3 ] = {' ',' ','1'};..const char str100[ 3 ] = {'1','0','0'};const char*const pText[ 100 ] = {str1,..str100,};