how to direct printf function from USART0 to USART1 in codevision - Page 1
Forum section: electronics / general

author: tariq
author_rank: Contributor
timestamp: July 14, 2021, 06:44:44 pm
content: hiI'm using ATMEGA128A and codevision .I want to use printf for both usarts but printf only works for one.in stdio.h lib its only defined functions i can't see the codes using for printf function.appreciate your help.

author: T3sl4co1l
author_rank: Super Contributor
timestamp: July 14, 2021, 07:19:50 pm
content: Consider the PC equivalent. You want to print to CONsole two different ways; what sense does that make?Well, operating systems do often have multiple ways, but you have to specify what. printf() uses the default CON so you're kind of stuck with that (and however it's assigned by libc (I forget exactly), or whatever CodeVision is using). You can open a file and use fprintf() to write to stdout, stderr, CON, COM1, /dev/ttyS0, etc., whatever you like.In any case, on an MCU, you of course don't have an operating system providing the underlying functionality. You have to implement that yourself (usually with callback functions). You could cheat it at this point, by changing what your callback outputs to. Mind, this may corrupt output due to buffering -- make sure to flush buffers before changing things over (or choose an unbuffered file mode or whatever).I suppose the most "proper" way, is to implement an interface for each port, and open them in respective files. It is then trivial to pipe the output into a logfile say (if you happen to add logging at some point), or test the code on PC (it's portable), etc.BTW, it may be worth avoiding use of printf() and friends. It's a very heavy-weight function, adding a lot of code that you're probably never going to use. Often better to use simple string functions, like itoa(), puts(), etc. (and all the other friends in <string.h>) on embedded systems.Tim

author: nctnico
author_rank: Super Contributor
timestamp: July 14, 2021, 08:00:55 pm
content: The usual way is to implement putchar() yourself and have it output to both UARTs. Maybe puts() needs to be re-implemented as well.Quote from: T3sl4co1l on July 14, 2021, 07:19:50 pmThis is really bad advice because it makes code very difficult to read/maintain and sooner or later you'll pull vuprintf (the usual printf core function) in one way or another. The right way is to implement a lightweight version of printf / vuprintf. Several can be found through Google. The creators of the C standard library have been really clever in keeping the interfaces lightweight and lean. That doesn't need fixing; just fix the core of the problem and that is using a less eloborate function.

author: ledtester
author_rank: Super Contributor
timestamp: July 14, 2021, 08:06:41 pm
content: Does Codevision have a sprintf function?Then you sprintf into a buffer and output the buffer through the USART.

author: SiliconWizard
author_rank: Super Contributor
timestamp: July 15, 2021, 05:47:48 pm
content: Quote from: nctnico on July 14, 2021, 08:00:55 pmWe had a whole thread about using or not using the xxprintf() family of functions - started by Nominal Animal. I suggest reading it.There are many reasons for willing to avoid using them. And good ones too.

author: SiliconWizard
author_rank: Super Contributor
timestamp: July 15, 2021, 05:59:28 pm
content: Anyway, if you want to do this using the xxprintf() family of functions, and do it cleanly, this is what I'd suggest:- Use fprintf() instead of printf(). Since you have two "channels" to address, the most obvious, yet standard-looking approach would be to address them with fprintf(stdout, ...) and fprintf(stderr, ...) respectively.- Implement your own _write() function. You can normally override it. It would look like this:Code:int _write(int file, char *data, int len){if ((file != STDOUT_FILENO) && (file != STDERR_FILENO)){errno = EBADF;return -1;}if (file == STDOUT_FILENO){// Send buffer pointed to by 'data' of length 'len' to USART0....}else if (file == STDERR_FILENO){// Send buffer pointed to by 'data' of length 'len' to USART1....}return len;}Do not mess with putchar(). The lowest level for doing this properly is as above: implementing the _write() function.Note that if you do the above, printf() will also work and send to USART0. printf() and fprintf(stdout, ...) are equivalent.The above approach should work if you're using GCC and newlib, which is the ubiquitous environment for many, if not most MCUs these days.Now I don't know Codevision and ATMEGA, so I don't know if the above is doable, and/or if it is, but in a different way.

author: T3sl4co1l
author_rank: Super Contributor
timestamp: July 15, 2021, 07:06:38 pm
content: Quote from: SiliconWizard on July 15, 2021, 05:47:48 pmSpecifically:https://www.eevblog.com/forum/programming/constructing-short-c-strings-in-limited-or-constrained-situations/(ah nice, the forum search found it easily for once!)Yeah, I wouldn't be so harsh about it. One can always write a mess, and a mess is always going to be a mess. Don't forget,printf itself can be abused...There's no guarantee that one will write clear code, nor any that someone else will find it easy to understand. That's just communication. Good communication comes when familiar structures are understood by both parties, and this can occur with any set of functions.Comparing, say, PC to embedded development, the greater diversity of  functions needed/used, and the lack of IO abstraction, makes things different, sure. But to a fellow embedded developer, I would be surprised if anyone were confused by the use of standard library string functions?One can even write withwhollyoriginalfunctions and have it be... well, you decide... it's certainly not intractable, at least.Tim

author: nctnico
author_rank: Super Contributor
timestamp: July 15, 2021, 08:39:22 pm
content: Quote from: SiliconWizard on July 15, 2021, 05:47:48 pmNo and no. I have seen this go bad too many times. Also Nominal Animal made a mistake by stating snprintf doesn't include a null termination character. It does and it is the reason I use snprintf instead of strncpy. I used to use my own stncpy() variant but that made code less portable / less readable. Also not using formatting strings is not a wise decission. If you look at the actual implementation of a small printf (which can be made thread safe / re-entrant as well; been there, done that) you'll see the overhead is minimal. Probably less than calling seperate functions for each part of a formatted string! Again, the inventors of C and the standard library have developed these libraries on extremely limited machines while maximising code effectiveness. Dimissing that and writing your own code is simply the worst example of re-inventing the wheel (or an example of the not-invented-here syndrome).

author: tariq
author_rank: Contributor
timestamp: July 16, 2021, 03:37:35 pm
content: thank you everyone for your answers.i found my answer in below codes and it's working:unsigned char poutput;void putchar(char c){switch (poutput){case USART0: // the output will be directed to USART0while ((UCSR0A & DATA_REGISTER_EMPTY)==0);UDR0=c;break;case USART1: // the output will be directed to USART1while ((UCSR1A & DATA_REGISTER_EMPTY)==0);UDR1=c;break;};}this function must be defined before main functionso when i want to send data by printf through usart0 i do this:poutput=USART0;printf("USART0\r");and through usart1 :poutput=USART1;printf("USART1\r");this codes are working fine.