UART+AVR: функция форматного вывода printf()

разделы: AVR , UART , дата: 23 сентября 2015г.

Функция форматного вывода printf довольно мощное средство языка Си. Приминительно к микроконтроллерам, возможно, сначала не совсем понятно, что там считать за стандарный поток вывода и как здесь может работать printf(). Библиотека avr-libc содержит файл stdio.h которая включает реализацию стандарных функций ввода-вввода.

<stdio.h>: Standard IO facilities

Я взял оттуда ХеллоВорлд:

#include <stdio.h>

static int uart_putchar(char c, FILE *stream);
static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);

static int uart_putchar(char c, FILE *stream)
{
	if (c == '\n')
		uart_putchar('\r', stream);
	loop_until_bit_is_set(UCSRA, UDRE);
	UDR = c;
	return 0;
}

int main(void)
{
	init_uart();
	stdout = &mystdout;
	printf("Hello, world!\n");
	return 0;
}

И модифицировал пример из поста ATmega8: работа на Си с USART/UART через прерывание заменив функцию writeSerial(char* str) на printf. Получилась такая штука:

/* for ATMEGA-8 echo_serial.c read string via UART with symbol ':' as End-Of-Line
and write this string in UART backward
site: http://countzero.weebly.com

compile:
avr-gcc -mmcu=atmega8 -Wall -Os -o echo_serial.elf echo_serial.c
avr-objcopy -O ihex echo_serial.elf echo_serial.hex
*/

#define F_CPU 16000000UL
#define LEN 32
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <stdio.h>

char buffer[LEN];

register unsigned char IT asm("r16");
volatile unsigned char done;
volatile unsigned char IDX;

static int uart_putchar(char c, FILE *stream)
{
   if (c == '\n')
   	uart_putchar('\r', stream);
   loop_until_bit_is_set(UCSRA, UDRE);
   UDR = c;
   return 0;
}

inline void clearStr(char* str)
{
        for(IT=0;IT<LEN;IT++)
                str[IT]=0;
}
/*
void writeSerial(char* str)
{
        IT=0; while (str[IT] != 0 && IT < LEN)
        {
                while(!(UCSRA&(1<<UDRE))){};
                UDR = str[IT];
                IT++;
        }
}
*/
ISR(USART_RXC_vect)
{
        char bf= UDR;
        buffer[IDX]=bf;
        IDX++;

        if (bf == ':' || IDX >= LEN)
        {
                IDX=0;
                done=1;
        }

}

void blink13(uint8_t count)
{
        PORTB |= (1<<PB5);
        count =(count <<1);count--; //count=(count*2)-1;
        for (IT=0;IT<count;IT++)
        {
                _delay_ms(500);
                PORTB ^= (1<<PB5);
        };
};

static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);

int main(void)
{
        // USART init
        UBRRL=103;
        UCSRB=(1<<TXEN)|(1<<RXEN)|(1<<RXCIE);
        UCSRC=(1<<URSEL)|(3<<UCSZ0);

        DDRB |= (1<<PB5); //  pinMode(13,OUTPUT);

        blink13(3); //ready indication
        IDX=0;
        done=0;
        sei();

	stdout = &mystdout;
	int count=0;
        for (;;)
        {
                if (done)
                {
			count++;
                        PORTB |= (1<<PB5);
//                        writeSerial(buffer);
			printf("Recived string#%d: %s\n",count,  buffer);
                        clearStr(buffer);
                        PORTB &= ~(1<<PB5);
                        done=0;
                }
        }
        return 0;
}

Весит такая прошивка около уже 1900 байт вместо 330, но в ряде случаев, это лучше, чем изобретение велосипеда с шахматами и поэтессами.