AVR Serial (USART) Tutorial

Serial communication on an embedded system is quite possibly the easiest and cheapest way to gain insight as to what is going on with your code. On most AVR microcontrollers serial communication is built right in. They have a peripheral called either a USART (Universal Synchronous/Asynchronous Receiver/Transmitter) or UART (Universal Asynchronous Receiver/Transmitter).

In this tutorial we are going to focus on the asynchronous mode since it is much more common. I’m giving example code for an ATMega328P. That just so happens to be the same microcontroller Arduinos use. This code will either work as is on other AVRs, or require slight modifications to work, mainly registers being called something else.

There are 4 basic steps to setting up the USART.
1. Set your BAUD rate
2. Enable the Receiver and Transmitter (RX and TX pins)
3. Set your data mode (we are going to use 8-bit, 0 stop bits, 0 parity bits)

Then we get to actually use the USART!

Setting the BAUD rate

Setting the BAUD rate on the AVR (and most microcontrollers in general) isn’t as simple as setting a register to 9600 BAUD. Serial communication needs to happen at some interval of the real clock frequency. That is why the clock needs to be stable and why certain frequencies work better than others. On the AVR you set a register value to a number that allows the microcontroller to do its magic. What this ‘magic’ number actually does is out of the scope of this article. The datasheet for your AVR of choice will usually have this formula defined.

Magic value = (((CPUSPEED / (DESIREDBAUDRATE * 16UL))) - 1)

We will use this define to use this in our code.

//The baud rate that we want to use
#define BAUDRATE 19200
//The formula that does all the required
#define BAUD_PRESCALLER (((F_CPU / (BAUDRATE * 16UL))) - 1)

BAUD_PRESCALLER will now contain that ‘magic’ number that needs thrown into the USART BAUD Rate Register (UBRRx)

I also use a single function to initialize the USART in one go.

void USART_init(void)
//Set USART baud rate
UBRR0H = (uint8_t)(BAUD_PRESCALLER>>8);

//Enable USART Receiver and Transmitter
UCSR0B = (1<<RXEN0)|(1<<TXEN0);

//8-bit, 0 stop bits, 0 parity bits
UCSR0C = ((1<<UCSZ00)|(1<<UCSZ01));

The USART BAUD Rate Register is a 16-bit register split into 2 8-bit registers, namely UBRRxH and UBRRxL for high and low registers respectively. You’ll notice in the USART_init method above that we shift the high register over a full 8 bits to get the bits we care about. The rest of the method does the other 2 steps listed at the beginning of this article.

We enable both the receiver and transmitter circuitry by setting bits in the USART Control and Status Register (UCSRxn). This register has several pieces to it, usually marked A, B and C. Each register is responsible for different aspects of the USART. Here we use part B to actually enable the receiver and transmitter circuitry. We then use part C to set our data mode (8-bit, 0 stop bits, 0 parity bits). If you want to use a different data mode or other USART options refer to your datasheet.

All we need now are some simple methods to read and write to and from the USART.

void USART_send(unsigned char data)
while(!(UCSR0A & (1<<UDRE0)));
UDR0 = data;

unsigned char USART_receive(void)
while(!(UCSR0A & (1<<RXC0)));
return UDR0;

void USART_sendString(char* ptrString)
//Send chars until we encounter a null char (end of string)
while(*ptrString!= 0x00)
//Send a single char at a time
//We increment the pointer so we can read the next char

If you’d like a complete, ready to load version of this project and code let me know. I’ll throw something together.

Tagged with: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,

Leave a Reply

Your email address will not be published. Required fields are marked *