Here we show how we can communicate two microcontrollers ATmega328P and ATmega32A using their USART. Here the ATmega328P is the transmitter which sends either character 'y' or 'n' via its USART and the ATmega32A is the receiver which upon the received character will turn LED on or off.
Two push button switches are connected to PORT D pin 7 and pin 6 of ATmega328p. If push button connected to the pin7 is pressed then ATmega328p sends 'y' character and if push button connected to pin 6 is pressed then ATmega328p sends 'n' character. At the receiver, a led is connected at the PORT D pin 4 of the ATmega32A. If the ATmega32A receives character 'y' the led is turned on and if the character 'n' is received then the led is turned off.
Below shows the ATmega328p transmitter and ATmega32A receiver along with push buttons, led and other required components(see schematic down below) on a breadboard.
The schematic diagram with animation of how the UART communication works between the microcontrollers is shown below.
The ATmega328p uses 8MHz internal RC oscillator and the ATmega32A uses an external 4MHz crystal.
In our Programming ATmega328p USART tutorial we had explained how to write program that utilizes USART.
Programming
The C program code for transmitter and receiver are provided below. Both the transmitter and receiver are configured in asynchronous mode, 9600 baud rate, 8 data bit and 1 stop bit, no parity, no frame error.
The C program code for the ATmega328p transmitter is below.
#ifndef F_CPU
#define F_CPU 8000000UL
#endif
#include <avr/io.h>
#include <util/delay.h>
#define UBRRVAL 51
void usart_init(void);
void sendbyte(unsigned char);
int main(){
DDRD &= ~(1<<PD7);
PORTD |= (1<<PD7);
DDRD &= ~(1<<PD6);
PORTD |= (1<<PD6);
usart_init();
while (1){
if((PIND & (1<<PD7)) == 0){
UCSR0B |= (1<<TXEN0);
sendbyte('g');
UCSR0B &= ~(1<<TXEN0);
}
if((PIND & (1<<PD6)) == 0){
UCSR0B |= (1<<TXEN0);
sendbyte('n');
UCSR0B &= ~(1<<TXEN0);
}
else{
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
//UCSR0A |= (1<<U2X0);
//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;
}
And the C program code the ATmega32A receiver is below.
#ifndef F_CPU
#define F_CPU 4000000UL
#endif
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#define UBRRVAL 25
void usart_init(void);
unsigned char urxchar(void);
int main(){
DDRD |= (1<<PD4);
usart_init();
while (1){
unsigned char r = urxchar();
if(r == 'g'){
PORTD |= (1<<PD4);
}
else if (r=='n'){
PORTD &= ~(1<<PD4);
}
else{
}
}
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 next step is to compile and upload the above code into the microcontroller using atmega328p programming software. If you are having difficulty in deploying and checking out whether it is working or not you can try first simple atmega328p led blink program.
Video demonstration of this intercommunication between the two microcontroller is below.