AVR USART explained

The Universal Synchronous and Asynchronous serial Receiver and Transmitter (USAR) is powerful and useful interface in many projects. It is usually used for code debugging and other user interaction while sending and receiving data form PC. Lets analyse how USART works on Atmega8. The main features of Atmega8 USART are:

  • Full Duplex Operation with Independent Serial Receive and Transmit Registers);

  • Asynchronous or Synchronous Operation;

  • Master or Slave Clocked Synchronous Operation;

  • High Resolution Baud Rate Generator;

  • Data OverRun Detection;

  • Framing Error Detection;

  • Supports Serial Frames with 5, 6, 7, 8, or 9 Databits and 1 or 2 Stop Bits;

  • Odd or Even Parity Generation and Parity Check Supported by Hardware;

  • Multi-processor Communication Mode;

  • Double Speed Asynchronous Communication Mode;

  • Noise Filtering Includes False Start Bit Detection and Digital Low Pass Filter;

  • Three Separate Interrupts on TX Complete, TX Data Register Empty and RX Complete;

As USART is pretty complex peripheral I will just go through it. Detailed information may be found on data-sheets!

USART is separated in three modules: Clock generator, Transmitter and Receiver.

USART Clock generator

Depending on data transfer mode there can be four different clock generation modes:

  • normal asynchronous;

  • double speed asynchronous;

  • Master synchronous;

  • Slave synchronous.

Most commons asynchronous internal clock generation. There Baud Rate Register (UBRR) is used where is value stored for down counter. Each time the down-counter value reaches zero a clock is generated. You can calculate what UBRR value you need to write depending on desired baudrate and MCU clock speed by formula: BAUD= fck / (16(UBRR+1)).

Using the value above (8 MHz and 9600 baud) we get the value of 51.08333333 for UBRR. So it's 51. The actual baud rate is 9615 baud, dividing this by 9600 gives 1.0016 and therefore an error of 0.16%.

This will work, but it's not perfect. That's why you can you usually has to use crystals as 7.3728 MHz: Using that one for 9600 baud gives UBRR = 47 and no error. Tables with various clock/baud combinations you will find in the AVR datasheets.

Synchronous mode and external clocking is don via XCK pin (refer to datasheet).

USART Transmission

USART transmitter is enabled by setting TXEN bit in UCSRB register. Normal port operations is overridden by USART (XCK pin in synchronous operations will be overridden too).

Simple transmission is very simple operation:

void USART_SendByte(uint8_t Data)

{

// Wait if a byte is being transmitted

while((UCSRA&(1<<UDRE)) == 0);

// Transmit data

UDR = Data;

}

USART Reception

The USART Receiver is enabled by writing the Receive Enable (RXEN) bit in the UCSRB Register to one. When the Receiver is enabled, the normal pin operation of the RxD pin is overridden by the USART and given the function as the Receiver’s serial input. The baud rate, mode of operation and frame format must be set up before any transfer operations.

uint8_t USART_vReceiveByte()

{

// Wait until a byte has been received

while((UCSRA&(1<<RXC)) == 0) ;

// Return received data

return UDR;

}

Data frame of USART usually starts with START bit, then follows bait (D to D7) then follows STOP bit. Between byte and stop bit there may be CB bit. The whole frame is 10 or 11 bit length:

In asynchronous transfer operation each bit is synchronized and recovered using following model: sampling is 16 times baud rate in normal mode. When clock recovery logic detects a high to low transition (start bit), sequence is initiated and in normal mode logic uses 8,9,10 samples to validate reception of start bit and further bits:

There is a lot material to talk about USART and its modes. Bat what is written in datasheet isn't necessary to repeat. We better concentrate to practical approach.

And at the end one example of using USART in normal mode:

#include <stdint.h>

#include <avr/io.h>

// Define baud rate

#define USART_BAUD 115200ul

#define USART_UBBR_VALUE ((F_CPU/(USART_BAUD<<4))-1)

void USART_vInit(void)

{

// Set baud rate

UBRRH = (uint8_t)(USART_UBBR_VALUE>>8);

UBRRL = (uint8_t)USART_UBBR_VALUE;

// Set frame format to 8 data bits, no parity, 1 stop bit

UCSRC = (0<<USBS)|(1<<UCSZ1)|(1<<UCSZ0);

// Enable receiver and transmitter

UCSRB = (1<<RXEN)|(1<<TXEN);

}

void USART_vSendByte(uint8_t u8Data)

{

// Wait if a byte is being transmitted

while((UCSRA&(1<<UDRE)) == 0);

// Transmit data

UDR = u8Data;

}

uint8_t USART_vReceiveByte()

{

// Wait until a byte has been received

while((UCSRA&(1<<RXC)) == 0);

// Return received data

return UDR;

}

int main(void)

{

uint8_t u8Data;

// Initialise USART

USART_vInit();

// Send string

USART_vSendByte('A');

// Repeat indefinitely

for(;;)

{

// Echo received characters

u8Data = USART_vReceiveByte();

USART_vSendByte(u8Data);

}

}

Comments

I'm looking all over Internet and every website tries to help me with my code. I have the code, I have a working example. Just tell me how do I connect my microcontroller with my computer and what software do I need on the computer. I know this article is 5 years old and I'm not leaving any contact info to reply me but I just needed to cry somewhere. Thank you for reading.

Well Mr. N. :)You'll need MAX232 chip, a female Serial connector, 3 x 0.1 uF capacitors and any kind of free terminal ;) like putty or sth. like that :)Every Atmel (or any other brand) has some pins that are marked as RX and TX and that's what you need to pair to max232.Use google, "MAX232 ATMEGA Serial communication" ;)Don't cry, answer is just a step away! ;)

Great site, thank you for the tutorial.I did some additional research on setting the baud accurately and found the header util/setbaud.h in Atmel Studio 6.So you can:#define 16000000UL#define BAUD 9600#include <util/setbaud.h>And from there you can use the calculated properties contained within setbaud.h, EG:UBRRL = UBRRL_VALUE;There are many more values found within setbaud.h, it's licensed under a BSD compatible.Be sure to have the #defines before the #include.Thanks again for the tutorial.