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.
}