One way use 'printf()' function to output char to UART

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

Recently,I found a code written by Joerg Wunsch which about using printf() function and scanf() function in AVR Studio .It help me resolving my project fast.Thank you very much Joerg Wunsch .I guess that would be useful to many novice.So ,I share that code with you.
At first,you must initialize the UART port.Such as Baud rate, F_CPU.The F_CPU must accordance with the clock source.In order to acquire accurate Baud rate,we often use external 7.3728MHz crytal.Let me look at below code.

void	uart_init(void)
{
#if F_CPU < 2000000UL && defined(U2X)
  UCSR0A = _BV(U2X);             /* improve baud rate error by using 2x clk */
  UBRR0L = (F_CPU / (8UL * UART_BAUD)) - 1;
#else
  UBRRL = (F_CPU / (16UL * UART_BAUD)) - 1;
#endif
  UCSRB = _BV(TXEN) | _BV(RXEN); /* tx/rx enable */
}

Then you need to write the uart_putchar function like this.

int	uart_putchar(char c, FILE *stream)
{

  if (c == '\a')			//'\a'
    {
      fputs("*ring*\n", stderr);  
      return 0;
    }

  if (c == '\n')			//
    uart_putchar('\r', stream);
  loop_until_bit_is_set(UCSRA, UDRE);
  UDR = c;

  return 0;
}

In the end you need to write uart_getchar function which can be called by scanf()function.

int	uart_getchar(FILE *stream)
{
  uint8_t c;
  char *cp, *cp2;
  static char b[RX_BUFSIZE];
  static char *rxp;

  if (rxp == 0)
    for (cp = b;;)
      {
	loop_until_bit_is_set(UCSRA, RXC);
	if (UCSRA & _BV(FE))
	  return _FDEV_EOF;
	if (UCSRA & _BV(DOR))
	  return _FDEV_ERR;
	c = UDR;
	/* behaviour similar to Unix stty ICRNL */
	if (c == '\r')
	  c = '\n';
	if (c == '\n')
	  {
	    *cp = c;
	    uart_putchar(c, stream);
	    rxp = b;
	    break;
	  }
	else if (c == '\t')
	  c = ' ';

	if ((c >= (uint8_t)' ' && c <= (uint8_t)'\x7e') ||
	    c >= (uint8_t)'\xa0')
	  {
	    if (cp == b + RX_BUFSIZE - 1)
	      uart_putchar('\a', stream);
	    else
	      {
		*cp++ = c;
		uart_putchar(c, stream);
	      }
	    continue;
	  }

	switch (c)
	  {
	  case 'c' & 0x1f:
	    return -1;

	  case '\b':
	  case '\x7f':
	    if (cp > b)
	      {
		uart_putchar('\b', stream);
		uart_putchar(' ', stream);
		uart_putchar('\b', stream);
		cp--;
	      }
	    break;

	  case 'r' & 0x1f:
	    uart_putchar('\r', stream);
	    for (cp2 = b; cp2 < cp; cp2++)
	      uart_putchar(*cp2, stream);
	    break;

	  case 'u' & 0x1f:
	    while (cp > b)
	      {
		uart_putchar('\b', stream);
		uart_putchar(' ', stream);
		uart_putchar('\b', stream);
		cp--;
	      }
	    break;

	  case 'w' & 0x1f:
	    while (cp > b && cp[-1] != ' ')
	      {
		uart_putchar('\b', stream);
		uart_putchar(' ', stream);
		uart_putchar('\b', stream);
		cp--;
	      }
	    break;
	  }
      }

  c = *rxp++;
  if (c == '\n')
    rxp = 0;

  return c;
}

Except that ,you also need set ' uart_str'point like this

FILE uart_str = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);
stdout = stdin = &uart_str;

Now you can use the printf() and scanf() function.That is easy ,is't it ?

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

Gee! someone should tell Joerg to put something like that in the user manual.

Oh ... wait a minute ... he already did ;-)

http://www.nongnu.org/avr-libc/u...

User manuals: not the pointless resource to be ignored until the smoke finally escapes after all eh?

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

Thanks to clawson .You let me find the way to use printf output characters to LCD.That's I need !