bzw. wo diese Puffer festgelegt werden?
Diese Puffer sind im Prinzip String Variablen, da sie auch im Interrupt behandelt werden müssen sie Volatile sein.
volatile unsigned char uc_receivepuffer[128]; // Wäre ein Puffer mit 128Byte Speicherkapazität.

Bei mir schaut dann die komplette Initialisierung für den Empfangspuffer so aus ( CodeVision AVR! )
Code:
// USART Receiver buffer
#define RX_BUFFER_SIZE 514
volatile char rx_buffer[RX_BUFFER_SIZE];

#if RX_BUFFER_SIZE<256
unsigned char rx_wr_index,rx_rd_index,rx_counter;
#else
unsigned int rx_wr_index,rx_rd_index,rx_counter;
#endif

// This flag is set on USART Receiver buffer overflow
bit rx_buffer_overflow;

// USART Receiver interrupt service routine
interrupt [USART_RXC] void usart_rx_isr(void)
{
char status,data;
status=UCSR0A;
data=UDR0;
if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
   {
   rx_buffer[rx_wr_index]=data;
   if (++rx_wr_index == RX_BUFFER_SIZE) rx_wr_index=0; //Diese Zeile setzt den Pointer am Pufferende wieder auf 0
   if (++rx_counter == RX_BUFFER_SIZE) //Diese Zeile setzt das Flag für einen Overflow
      {
      rx_counter=0;
      rx_buffer_overflow=1;
      };
   };
}
Initialisierung des USART muss natürlich auch noch gemacht werden.

Die Daten aus diesem Puffer kann man sich dann mit getchar Byteweise abholen.
Code:
#ifndef _DEBUG_TERMINAL_IO_
// Get a character from the USART Receiver buffer
#define _ALTERNATE_GETCHAR_
#pragma used+
char getchar(void)
{
char data;
while (rx_counter==0);
data=rx_buffer[rx_rd_index];
if (++rx_rd_index == RX_BUFFER_SIZE) rx_rd_index=0;
#asm("cli");
--rx_counter;
#asm("sei");
return data;
}
#pragma used-
#endif
Getchar wird im Main Loop natürlich nur dann aufgerufen, wenn auch tatsächlich Daten im Puffer sind.
Code:
if(rx_counter>0)
            {
            //Ein Byte wird geschrieben
                c=getchar();
            }
Das Byte steht nun in der Variable c zur weiteren Verarbeitung.

Die Code Beispiele sind für CodeVision AVR, bei AVR GCC wird das eventuell etwas anders aussehen.