USART Communication between ATmega microcontrollers

 Here simple USART(Universal Synchronous Asynchronous Receiver Transmitter) communication between two ATmega microcontrollers is demonstrated. The ATmega microcontrollers used are ATmega328p and ATmega32A. The ATmega328p is used as the transmitter and the ATmega32A is used as a receiver. Command message is sent from the transmitter to receiver microcontroller to turn on and off a LED connected at the receiver using two push button which are connected to the transmitter.

Circuit Diagram

The following shows the circuit diagram of interfacing the two microcontroller for USART communication.

usart communication between two ATmega microcontrollers

In the above circuit schematic, the ATmega328P transmitter USART pin 3(PD1) is connected to the ATmega32A receiver USART pin 14(PD0). Two push buttons are connected to the ATmega328p at pins 12(PD6) and 13(PD7). The push button at PD7 and PD6 are used to send g character to turn on and n character character message to turn off the LED respectively to the receiver microcontroller via the USART. Depending on the message received the LED connected receiver micrcontroller(the ATmega32A) to pin 18(PD4) is turned ON or OFF.

The following is animation of how the circuit works.

usart communication between two ATmega microcontrollers

Program Code

Transmitter code

The full program code for the ATmega328p transmitter is below.

#include <avr/io.h>
#include <util/delay.h>

#ifndef F_CPU
#define F_CPU 8000000UL
#endif

#define UBRRVAL 51

void usart_init(void);
void sendbyte(unsigned char);

int main(){ 
	//Set Port pins for push buttons
	DDRD &= ~(1<<PD7);
	PORTD |= (1<<PD7);
	DDRD &= ~(1<<PD6);
	PORTD |= (1<<PD6);
	//initialize the USART module
    usart_init();
   
   //continously check for button states
   	while (1){
	  
	if((PIND & (1<<PD7)) == 0){
     // send message to turn on LED
		UCSR0B |= (1<<TXEN0);
		sendbyte('g');
		PORTD |= (1<<PD4);
		UCSR0B &= ~(1<<TXEN0);
	}
	   
	else if((PIND & (1<<PD6)) == 0){
    // send message to turn off LED
		UCSR0B |= (1<<TXEN0);
		sendbyte('n');
		PORTD |= (1<<PD4);
		UCSR0B &= ~(1<<TXEN0);
	}
	else{
		// disable USART transmission
		UCSR0B |= ~(1<<TXEN0);
	}

      }
   
   return 0;
 }
 
void usart_init(void){
    //Set baud rate
	UBRR0H= (unsigned char)(UBRRVAL>>8);   //high byte
    UBRR0L=(unsigned char)UBRRVAL;     	   //low byte
	//Enable Transmitter and Receiver and Interrupt on receive complete
    UCSR0B |= (1<<TXEN0);
    //Set data frame format: asynchronous mode,no parity, 1 stop bit, 8 bit size
    UCSR0C |= (1<<UCSZ01)|(1<<UCSZ00); 
}

void sendbyte(unsigned char MSG){
    // Wait if a byte is being transmitted
    while((UCSR0A&(1<<UDRE0)) == 0);
    // Transmit data
    UDR0 = MSG;  
}

In the above code ,we have made use of two libraries- the io.h which contains the port map information of the microcontroller and the delay.h which is included so that we can use the _delay_ms() delay function later in the program. The F_CPU is defined here so that we can use the _delay_ms() function.

The constant UBRRVAL with value 51 is used to set the baud rate of 9600bps for UART communication. This value 51 will be loaded into the USART Baud Rate Registers(UBRR0L and UBRR0H). The value required for specific baud rate is determined using the following equation which is provided ATmega328p datasheet.

\( UBRR0 = \frac{f_{osc}}{16 \times BAUD}-1 \)

where UBRR0=UBRRVAL=51 with \(f_{osc}=8MHz\) and BAUD=9600bps.

This formula is for the normal asynchronous mode and of USART operation.

In order to simplify the program we have created two functions the usart_init() and the sendbyte(). 

The usart_init() function is used to configure the USART module of the ATmega328p microcontroller. If this function is called, the value of UBRRVAL of 51 is loaded in the USART baud rate registers(high and low registers). This sets the baud rate of 9600bps. Then we enable the transmission by setting the transmit enable bit in the UCSR0B register. Also we set the message format by setting the bits in the UCSR0C register which includes mode of operation, number of data bits, stop bits, parity bit etc.

The sendbyte() function is used to send one character from the USART transmit section out of TXD pin or the PD1 pin. First we check to see if there any leftover byte in the transmit register. If it is empty then we load the message character into the UDR0 register(USART Data Register 0). This loaded character in the register is then sent by the ATmega328p USART.

In the main function, we first have set up the Port pins for the two push button as an input. Then we have called the usart_init() function to set up the USART. Using if else statements within a while() loop we continuously check the state of the two button. If the push button connected to the PD7 is pressed then we send 'g' character to the USART module which is then sent to the ATmega32A receiver microcontroller. Similarly, if the push button connected to the PD6 is pressed then character 'n' is sent. 'g' character is sent to turn on the LED and 'n' character is sent to turn off the LED at the receiver. 

Receiver code

The program code the ATmega32A which is the receiver of USART message is below.


#include <avr/io.h>
#include <util/delay.h>

#ifndef F_CPU
#define F_CPU 4000000UL
#endif

#define UBRRVAL 25

void usart_init(void);
unsigned char urxchar(void);

int main(){ 
	//set LED pin as output
	DDRD |= (1<<PD4);
	//initialize USART
    usart_init();
   
   while (1){
	  
	unsigned char r = urxchar();

	if(r == 'g'){
		PORTD |= (1<<PD4);
	}
	else if (r=='n'){
        PORTD &= ~(1<<PD4);
	}
	else{
		//do nothing
	}
	
      }
   
   return 0;
 }
 
void usart_init(void){
    //Set baud rate
    UBRRH= (unsigned char)(UBRRVAL>>8);   //high byte
    UBRRL=(unsigned char)UBRRVAL;     //low byte
    //Enable Transmitter and Receiver and Interrupt on receive complete
    UCSRB |= (1<<RXEN);
    //Set data frame format: asynchronous mode,no parity, 1 stop bit, 8 bit size
    UCSRC |= (1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0); 
    
}

unsigned char urxchar(void){
	while(!(UCSRA & (1<<RXC)));
		return UDR;
}


The receiver program code is very similar to the transmitter code explained above. The baud rate is 9600bps which must match with the transmitter baud rate. The ATmega32A receiver uses 4MHz crystal for clock so the value to be loaded into the USART baud rate register is 25. This value can be found in the ATmega32A datasheet. The formula for calculating this same as for ATmega328p which was provided above. As in the transmitter case, the usart_init() function sets up the USART. It uses the same USART message format(which must be same as used in the transmitter. The receiver enable bit is used to enable the receiver USART for receiving the message. 

In the main function we have set up the LED pin as an output. Then we have called the usart_init() function to set the USART. In the continous while() loop we check for any incoming message from the transmitter microcontroller. If message 'g' is received then the LED is turned on and if the message 'n' is received the LED is turned off. 

In this way we can communicate two AVR microcontroller using their USART module. ATmega328p used here is a microcontroller which is popularly used in the Arduino board. For Arduino USART communication see the tutorial Serial communication between two Arduinos.

Post a Comment

Previous Post Next Post