#define FOSC 16000000
#define BAUDRATE 9600
#define UBRR_VAL (FOSC/16/(BAUDRATE-1))
#define BUFF_SIZE 16 //for ease, make a power of 2 (16, 32, 64 etc)
typedef struct RX_s
{
volatile uint8_t vRXHead;
volatile uint8_t vRXTail;
volatile uint8_t grRXBuffer[BUFF_SIZE];
}RX_t;
RX_t sRX;
typedef struct TX_s
{
uint8_t idx;
uint8_t numBytes;
volatile uint8_t grTXBuffer[BUFF_SIZE];
}TX_t;
TX_t sTX;
void setup()
{
//UART setup/////
//baud rate
pinMode( 0, INPUT_PULLUP);
pinMode( 1, OUTPUT );
UBRR0H = (uint8_t)(UBRR_VAL >> 8);
UBRR0L = (uint8_t)UBRR_VAL;
//Enable receiver and transmitter; enable receive interrupt
UCSR0B = _BV(RXEN0) | _BV(TXEN0) | _BV(RXCIE0);
//asyn; no parity; 1-stop bit; 8 data, 1 stop bit
UCSR0C = _BV(UCSZ01) | _BV(UCSZ00);
sRX.vRXHead = 0;
sRX.vRXTail = 0;
sTX.idx = 0;
sTX.numBytes = 0;
}//setup
void loop()
{
CheckForRXBytes();
}//loop
ISR(USART_RX_vect)
{
//receive interrupt
uint8_t status = UCSR0A;
char rxbyte = UDR0;
if( status & (_BV(FE0) | _BV(DOR0)))
{
//handle framing (e.g. break character received) or data overrun error
//not done here for brevity
}//if
else
{
//put character received in RX buffer
//should check to see if head bumps into tail but
//mainline code is expected to be fast enough to prevent this
sRX.grRXBuffer[sRX.vRXHead] = rxbyte;
sRX.vRXHead = (sRX.vRXHead + 1) & (BUFF_SIZE-1);
}//if
}//UART RX interrupt
ISR(USART_UDRE_vect)
{
//transmit interrupt
//put next character in TX register
UDR0 = sTX.grTXBuffer[sTX.idx];
//bump the index
sTX.idx++;
//if the index == the number of bytes we can turn off the interrupt
if( sTX.idx == sTX.numBytes )
{
//finished; disable interrupt
UCSR0B &= ~_BV(UDRIE0);
sTX.idx = 0;
sTX.numBytes = 0;
}//if
}//TX interrupt
void CheckForRXBytes()
{
uint8_t
p = 0;
//if head doesn't equal tail, there is one or more characters
//in the receive buffer
//in this example, I copy them to a TX buffer and send them out
//using interrupts
if( sRX.vRXTail != sRX.vRXHead )
{
//repeat until the tail pointer == the head pointer
do
{
//copy the byte there to the TX buffer
sTX.grTXBuffer[p++] = sRX.grRXBuffer[sRX.vRXTail++];
//bump the number of bytes (TX count)
sTX.numBytes++;
//local index and tail pointer; & operation
//keeps them within the RX buffer
p = p & (BUFF_SIZE-1);
sRX.vRXTail = sRX.vRXTail & (BUFF_SIZE-1);
}while( sRX.vRXTail != sRX.vRXHead );
//enable the TX interrupt to echo the message back
sTX.idx = 0;
UCSR0B |= _BV(UDRIE0);
}//if
}//CheckForRXBytes