Functions for using the USART

These programs are intended for an ATMEGA8 CPU, but it should not be too difficult to adapt them for other CPU's.
If you are new to AVR or USART programming, please start with the polling routines.

... with polling

#include <stdio.h>
#include <stdint.h>
#include <avr/io.h>

#define BAUD_RATE    9600

/* Prototypes */
void uart_init(void);
int uart_rx_byte(void);
void uart_tx_byte(uint8_t);

void uart_init(void)
{
	UBRRH = (uint8_t) ((F_CPU / (BAUD_RATE * 16L) - 1)>>8);
	UBRRL = (uint8_t) (F_CPU / (BAUD_RATE * 16L) - 1);
	/* Enable UART receiver and transmitter, and receive interrupt */
	UCSRB = ((1<<RXEN)|(1<<TXEN));
	// 8N1
	UCSRC |= (1<<URSEL)|(3<<UCSZ0);
	return;
}

void uart_tx_byte(uint8_t data)
{
	while(!(UCSRA & (1<<UDRE)));	/* wait until TX buffer empty */
	UDR = data;			/* then put data to TX buffer */
	return;
}

int uart_rx_byte(void)
{
	uint8_t status;

	while(!(UCSRA & (1<<RXC)));	/* wait until data is received */
	status = UCSRA;
	if(status & (1<<FE)|(1<<DOR)|(1<<PE)) {
		return -1;
	}
	return UDR;		/* get and return data from receive buffer */
}

int main(void)
{
	uart_init();
	for(;;) {		/* Forever */
		uart_tx_byte(uart_rx_byte()); /* Echo the received character */
	}
}

usart_polling.c

... interrupt driven

#include <stdio.h> 
#include <stdint.h>   	
#include <avr/io.h>				 	
#include <avr/interrupt.h>

#define BAUD_RATE    9600

/* UART Buffer Defines */
#define UART_RX_BUFFER_SIZE 64		/* must be a power of 2, up to 2^8 */
#define UART_TX_BUFFER_SIZE 64

#define UART_RX_BUFFER_MASK (UART_RX_BUFFER_SIZE - 1)
#if (UART_RX_BUFFER_SIZE & UART_RX_BUFFER_MASK)
	#error RX buffer size is not a power of 2
#endif
#define UART_TX_BUFFER_MASK (UART_TX_BUFFER_SIZE - 1)
#if (UART_TX_BUFFER_SIZE & UART_TX_BUFFER_MASK)
	#error TX buffer size is not a power of 2
#endif

/* Static Variables */
static uint8_t UART_RxBuf[UART_RX_BUFFER_SIZE];
static volatile uint8_t UART_RxHead;
static volatile uint8_t UART_RxTail;
static uint8_t UART_TxBuf[UART_TX_BUFFER_SIZE];
static volatile uint8_t UART_TxHead;
static volatile uint8_t UART_TxTail;

/* Prototypes */
void uart_init(void);
uint8_t uart_rx_byte(void);
void uart_tx_byte(uint8_t);

/* Initialize UART */
void uart_init(void)
{
	uint8_t x;

	UBRRH = (uint8_t) ((F_CPU / (BAUD_RATE * 16L) - 1)>>8);
	UBRRL = (uint8_t) (F_CPU / (BAUD_RATE * 16L) - 1);
	/* Enable UART receiver and transmitter, and receive interrupt */
	UCSRB = ((1<<RXCIE) | (1<<RXEN) | (1<<TXEN));
	// 8N1
	UCSRC |= (1<<URSEL)|(3<<UCSZ0);
	// UCR = ((1<<RXCIE) | (1<<RXEN) | (1<<TXEN) );
	x = 0;				/* Flush receive buffer */
	UART_RxTail = x;
	UART_RxHead = x;
	UART_TxTail = x;
	UART_TxHead = x;
}

/* Interrupt handlers */
ISR(USART_RXC_vect)
{
	uint8_t data;
	uint8_t tmphead;

	/* what about checking for FE, DOR and PE ?! */
	data = UDR;				/* Read the received data */
	/* Calculate buffer index */
	tmphead = (UART_RxHead + 1) & UART_RX_BUFFER_MASK;
	UART_RxHead = tmphead;			/* Store new index */
	if(tmphead == UART_RxTail) {
		/* ERROR! Receive buffer overflow */
	}
	UART_RxBuf[tmphead] = data;		/* Store received data in buffer */
}

ISR(USART_TXC_vect)
{
	uint8_t tmptail;

	/* Check if all data is transmitted */
	if(UART_TxHead != UART_TxTail) {
		/* Calculate buffer index */
		tmptail = (UART_TxTail + 1) & UART_TX_BUFFER_MASK;
		UART_TxTail = tmptail;		/* Store new index */
		UDR = UART_TxBuf[tmptail];	/* Start transmition */
	} else {
		UCSRB &= ~(1<<UDRIE);		/* Disable UDRE interrupt */
	}
}

/* Read and write functions */
uint8_t uart_rx_byte(void)
{
	uint8_t tmptail;
	
	while(UART_RxHead == UART_RxTail);	/* Wait for incomming data */
	/* Calculate buffer index */
	tmptail = (UART_RxTail + 1) & UART_RX_BUFFER_MASK;
	UART_RxTail = tmptail;			/* Store new index */
	return UART_RxBuf[tmptail];		/* Return data */
}

void uart_tx_byte(uint8_t data)
{
	uint8_t tmphead;
	/* Calculate buffer index */
	tmphead = (UART_TxHead + 1) & UART_TX_BUFFER_MASK;
	/* Wait for free space in buffer */
	while(tmphead == UART_TxTail);
	UART_TxBuf[tmphead] = data;		/* Store data in buffer */
	UART_TxHead = tmphead;			/* Store new index */
	// was: UCR |= (1<<UDRIE);
	UCSRB |= (1<<UDRIE);			/* Enable UDRE interrupt */
}

uint8_t DataInReceiveBuffer(void)
{
	return(UART_RxHead != UART_RxTail);	/* Return 0 (FALSE) if the receive buffer is empty */
}

int main(void)
{
	uart_init();
	sei();			/* Enable interrupts => enable UART interrupts */
	for(;;) {		/* ever */
		uart_tx_byte(uart_rx_byte()); /* Echo the received character */
	}
}

usart_irq_driven.c