AVR - USART:

All AVR micro-controllers have Digital Input and Output Communcation, which is explained in AVR-GPIO.  Some AVR micro-controllers have Analog-Digital Conversion, which is an important communication with the real world is explained in AVR-ADC/DAC.

 

Now, we will go through some other important and frequently used communication methods, mostly Serial Coomucations, available for AVR micro-controllers.

All AVR micro-controllers have Digital Input and Output Communcation, which is explained in AVR-GPIO.  Some AVR micro-controllers have Analog-Digital Conversion, which is an important communication with the real world is explained in AVR-ADC/DAC.

 

Now, we will go through some other important and frequently used communication methods, mostly Serial Coomucations, available for AVR micro-controllers.

USART:

USART (Universal Synchronous Asynchronous Receiver and Transmitter) : This is the highly used programmable, Full Duplex, serial communication available in AVR micro-controllers. The external pins marked as TX is used as Transmitter (data out) and RX is used as Receiver (data in). 

 

USART is a digital data FRAME FORMAT, transmitted and received by AVR micro controllers.  The frame format contains one start bit, 5 / 6/ 7/ 8 / 9 data bits, [no/odd/even] parity bit and one or two stop bits. 

 

The digital data (in frame work) is transmitted at a particular frequency to match transmitter and receiver asynchronously (no clock pulse for matching).  Where as, in synchronous transmission, one micro controller programmed as MASTER, sends clock pulse along with the data bits to match the frequency of transmission for other micro controller for processing.  The frequency at which the serial data bits is transmitted is called as BAUD RATE.  The Baud Rates are standard and may be programmed by you to set a standard baud rate, by programming UBRRH and UBRRL registers, which together is called UBRR register .  A double speed option is also available for asynchronous mode.

USART:Setting BAUD RATE:

Some of the Standard Baud Rates are : 1200, 2400, 4800, 9600, 14400 and so on.

One of the following formulae is used to set the value for UBRR register, where MCU_FREQ is the micro-controller clock frequency.

ubrr_value  = ( MCU_FREQ / (2*baud_rate) ) -1;    //for synchronous transmission

ubrr_value  = ( MCU_FREQ / (16*baud_rate) ) -1;  //for asynchronous normal (single speed) transmission

ubrr_value  = ( MCU_FREQ / (8*baud_rate) ) -1;    //for asynchronous double speed transmission

now, set the ubrr_value to UBRR Register which is combination of UBRRH (contains 8 MSB) and UBRRL (contains 8 LSB)

UBRRH = ubrr_value>>8;  // to set 8 MSB

UBRRL = ubrr_value;      // to set 8 LSB

For DOUBLE SPEED transmission, set U2X bit (bit 2) in UCSRA register, which is valid for asynchronous transmission only.

UCSRA |= (1<<U2X);

You have to set UMSEL bit for the SYNC / ASYNC transmission type in the UCSRC register.  UMSEL is set to 0 by default, which indicates asynchronous transmission.  For synchronous transmission, you have to set UMSEL to 1 as shown below, so that XCK pin acts as synchronizing clock for transmission:

UCSRC |= (1<<UMSEL);  // synchronous transmission is on, XCK pin is used for sync. clock

Due to imperfect division with some MCU_FREQ values like, 1MHz, 4MHz etc, there is some error exists while generating the exact baud rate, as expected.  But, when the transmitter and receiver is using same MCU_FREQ, then the error may not effecting the transmission.  So, for accurate or reduced error generation in baud rate, use 1.8432 MHz and its multiples, for micro controller clock frequencies, using crystal (or other means).

[for more details, refer data sheet]

USART:Setting FRAME FORMAT:

As per earlier discussion, Frame Format contains START_BIT initially, which is a mandatory bit, to understand the receiver about the starting of USART transmission.

Next is DATA BITS.  The size or number of data bits has to be set in the UCSRC and UCSRB registers, by setting the bits UCSZ2, UCSZ1 and UCSZ0 as shown below (write/use any one statement in your code as per your requirement):

UCSRC  |= (0<<UCSZ1) |(0<<UCSZ0) ;   //for 5 data bits [ all 0 by default ]

UCSRC  |= (0<<UCSZ1) |(1<<UCSZ0)   //for 6 data bits

UCSRC  |= (1<<UCSZ1) |(0<<UCSZ0)   //for 7 data bits

UCSRC  |= (1<<UCSZ1) |(1<<UCSZ0)   //for 8 data bits [highly used]

Some more settings are required for transmitting / receiving 9 bit data. i.e., The UCSZ2 bit should be set to 1 in UCSRB register as shown below:

UCSRC  |= (1<<UCSZ1) |(1<<UCSZ0);   //for 9 data bits [rarely used]

UCSRB  |= (1<<UCSZ2);   //for 9 data bits [rarely used]

Where as UCSZ2 need NOT set for 5 to 8 bit data transfer and may omit the following line or optional.

UCSRB  |= (0<<UCSZ2)   //for 5 to 8 data bits [by default]

The actual data is to be written or read from UDR register, which is 8 bit long as shown below:

unsigned char val  = 0x3F ;   // declaring & setting value for a variable

UDR  = val;  // the value 0x3F is set for transmission

val = UDR   // the value in UDR register is read and set to variable "val" for further processing

 

For transmitting/receiving NINTH BIT, the LSB eight bits may be set/read as explained above.  But, the ninth bit (MSB) data has to be written_to / read from TXB8 bit (0th position) of UCSRB register as shown below:

unsigned char val_h  = 0x01 ;   // declaring & setting value for a 9th bit as 1 for variable

 

Transmitter side:

UCSRB &= 0xFE;   // clear TXB8 bit of UCSRB, if any

UCSRB |= (val_h & 1);   // set TXB8 bit of UCSRB, as set in the variable

Receiver side:

val_h  = UCSRB ;   // reading full UCSRB register & setting value for a variable

val_h  = val_h & 0x01;   // filtering the 9th bit & setting value for a variable again

Then. PARITY BIT is set in the frame format.  The parity bit is useful to check the error while transmission of data,  The parity may be either ODD or EVEN or NONE.  Odd Parity bit setting is commonly used.  In case parity bit is set, the Transmitter automatically sends the parity value in the frame format.  The receiver check the parity value with the received data.  On error on reception, PE flag in UCSRA is set.  You may write code to check the PE value and necessary action code on receiver section.   For Parity bit setting, you may write any one statement in your code as per your requirement:

UCSRC  |= (0<<UPM1) |(0<<UPM0);   //for NO PARITY CHECK [ all 0 by default ]

UCSRC  |= (1<<UPM1) |(0<<UPM0);   //for EVEN PARITY CHECK

UCSRC  |= (1<<UPM1) |(1<<UPM0);   //for ODD PARITY CHECK

The Frame format ends with STOP BIT(S).   ONE or TWO Stop bit(s) are used to indicated end of frame format transmission, which is set by USBS bit in UCSRC register.  You may use any one following line in your code.

UCSRC  |= (0<<USBS);   //for ONE stop bit, by default [  0 by default ]

UCSRC  |= (1<<USBS);   //for TWO stop bits

USART:Setting TRANSFER DIRECTION:

As discussed, an AVR micro-controller can send and receive the serial data simultaneously, called as Full-Duplex transmission.  But, you may program to either transmit or receive or both on the same micro-controller.  The transmit or receive option may be selected by setting TXEN or RXEN bits in UCSRB register as shown below.

UCSRB  |= (1<<TXEN) | (1<<RXEN);   //for both transmit and receive data

UCSRB  |= (1<<TXEN)                          //for only transmit data

UCSRB  |= (1<<RXEN)                          //for only receive data

USART: Start TRANSMITION (TX):

Once the settings are completed, then the data bits may be transmitted, by simply writing the data in UDR register.  The status of transmission is indicated by two flags UDRE (Usart Data Register Empty) or TXC (Transmission Complete).  You may read any one flag (normally checked in loop) to know the status, as shown below (use magenta colour code only for 9 bit transmssion):

int val = 0x1A9;                     //set sending value to a variable

while ( !( UCSRA & (1<<UDRE) ) )    // wait until the Transmit buffer is emptied

if (val & 0x0100) // check bit 9 of val, in case of 9 bit transmission.  else ignore

   UCSRB |= 1;        // set 1, if truefor only transmit data

else  

   UCSRB &= 0xFE; //set 0, if false

UDR = val              // once the value is written or changed, then transmission starts automatically

USART: Start RECEIVING (RX):

Once the settings are completed, then USART starts receiving the data automatically and the status is indicated by RXC (Receiving Completed) flag in USCRA register.  The data should be read when the RXC flag is set to 1.  The error flags FE (Frame Error), DOR (Data Over Run) and PE (Parity Error) should be read before processing the received data. The example code is shown below (use magenta colour code only for 9 bit reception)::

int val;                     //declare or initiate a variable

int 9th_bit;             //declare or initiate another variable for 9 th bit, if required

int status;               //declare or initiate a variable for reading status

while ( !( UCSRA & (1<<RXC) ) )    // wait until the Receive buffer is full and ready to read

status = UCSRA       // read the status

9th_bit = (8<<(UCSRB & 1));        // read 9th bit value, in case of 9 bit transmission

val = UDR             // read upto 8 bit data

if (status & (1<<FE) | (1<<PE) | (1<<DOR)) // check for transmission error, if any

   return ERROR;        // stop processing and return an error code set by you

 

return (9th_bit|val);  // return the received value for further processing.

USART: APPLICATION:

So far, you learned the concepts about Transmitting (TX) and Receiving (RX) the serial data using USART.  Now, a full example code is written below using C functions.  The initUsart is used for inital USART settings and call the function only once in the main().  Where as the sendUsart function may be called whenever data is to be sent.  Similarly, readUsart function may be called / used, whenever received data is to be read. The full example code is shown below ( magenta colour code indicates only for 9 bit data transmission)::

#define F_CPU 1000000L // frequency of AVR micro-controller, by default 

void initUsart ( long baud_rate )   //initialization or initial setup for USART

{

   int ubrr_value;

   //for asynchronous normal (single speed)

   ubrr_value  = ( F_CPU / (16L*baud_rate) ) -1;

   UBRRH = ubrr_value>>8;  // to set 8 MSB of ubrr_value

   UBRRL = ubrr_value;      // to set 8 LSB of ubrr_value

   UCSRC  |= (1<<UCSZ1) |(1<<UCSZ0)   //for 8 data bits [highly used]

      UCSRB  |= (1<<UCSZ2);   // incase  9 data bits [rarely used]

     //omit the following line, if parity check is not required

   UCSRC  |= (1<<UPM1) |(1<<UPM0);   //for ODD PARITY CHECK

     //omit the following line for ONE stop bit

   UCSRC  |= (1<<USBS);   //for TWO stop bits

      //enable both transmit and receive data

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

}

void sendUsart ( int the_data )   //sends the data through usart

{

      // wait until the Transmit buffer is emptied

   while ( !( UCSRA & (1<<UDRE) ) ) 

   if (the_data & 0x0100) // check bit 9, in case of 9 bit transmission.  else ignore

      UCSRB |= 1;        // set 1, if true 

   else  

      UCSRB &= 0xFE; //set 0, if false

   UDR = the_data              

      // once the value is written, then transmission starts automatically

}

int ERROR=0x1000;  // the 12th bit is set to 1, which is beyond 9th bit, to easily check error code.

int readUsart ( )   //reads and returns the usart data 

{

   int the_data;                     //declare or initiate a variable

   int 9th_bit;             //declare or initiate another variable for 9 th bit, if required

   int status;               //declare or initiate a variable for reading status

   while ( !( UCSRA & (1<<RXC) ) )    // wait until the Receive buffer is full and ready to read

   status = UCSRA       // read the status

   9th_bit = (8<<(UCSRB & 1));        // read 9th bit value, in case of 9 bit transmission

   the_data = UDR             // read upto 8 bit data

   if (status & (1<<FE) | (1<<PE) | (1<<DOR)) // check for transmission error, if any

      return (ERROR|status);   // stop processing and return exact error code

   return (9th_bit|val);  // return the received value for further processing.

}