ESP32 UART Communication (Serial): Set Pins, Interfaces, Send and Receive Data (Arduino IDE)

This is a simple guide about UART serial communication protocol with the ESP32 using Arduino IDE. We’ll take a look at the basics of UART, default and custom UART pins, basic functions, and communication between boards.

ESP32 UART Communication Serial Set Pins,  Interfaces, Send and Receive Data

Table of Contents:

Throughout this guide, we’ll cover the following topics:

Prerequisites

This tutorial focuses on programming the ESP32 using the Arduino core. Before proceeding, you should have the ESP32 Arduino core installed in your Arduino IDE. Follow the next tutorial to install the ESP32 on the Arduino IDE, if you haven’t already.

Alternatively, you can also use VS Code with the PlatformIO extension to program your boards using the Arduino core:

Introducing ESP32 UART Communication Protocol

UART (Universal Asynchronous Receiver-Transmitter) is a serial communication protocol that allows two devices to communicate.

Unlike SPI or I2C, which are synchronous, UART is asynchronous, meaning it does not use a clock signal to synchronize the data transmission between devices. However, both devices must agree on the baud rate (speed of transmission).

UART communication with ESP32 explained

In UART communication, data is transferred serially, bit by bit (hence the term serial), at a pre-defined baud rate (bits per second). UART uses a single data line for transmitting (TX) and one for receiving (RX).

UART ports allow us to communicate with other devices, such as other microcontroller boards (an Arduino, an ESP8266, another ESP32 board, or others), the computer, sensors, GPS or Bluetooth modules, some types of displays, and more.

UART Interface

For UART communication, you need the following lines:

  • TX (Transmit): Sends data.
  • RX (Receive): Receives data.
  • GND: Common ground

ESP32 UART Peripherals

The ESP32 supports up to three UART interfaces: UART0, UART1, and UART2, depending on the ESP32 board model you’re using.

  • UART0 is usually reserved for communication with the serial monitor during upload and debugging. However, you can also use it for communication with other devices after uploading the code if the Serial Monitor is not needed.
  • UART1 and UART2: available to communicate with external devices.

ESP32 Default UART Pins

Like I2C and SPI, these UART pins can be mapped to any GPIO pin on the ESP32. However, they have a default pin assignment on most board models.

For most ESP32 boards the UART pin assignment is as follows:

UART PortTXRXRemarks
UART0GPIO 1GPIO 3Used for Serial Monitor and uploading code; Can be assigned to other GPIOs;
UART1GPIO 10GPIO 9Must be assigned to other GPIOs
UART2GPIO 17GPIO 16Can be assigned to other GPIOs

About UART1 (GPIO 9 and GPIO10) – these GPIOs are connected to the ESP32 SPI flash memory, so you can’t use them like that. To use UART1 to communicate with other devices, you must define different pins using the HardwareSerial library. 

If you’re using an ESP32-S3, the assignment is completely different. The following table shows the default UART0, UART1, and UART2 RX and TX pins for the ESP32-S3:

UART PortTXRXRemarks
UART0GPIO 43GPIO 44Cannot be changed
UART1GPIO 17GPIO 18Can be assigned to other GPIOs
UART2Assign any pins of your choice

Note: Depending on the board, the default UART pins might be different. Always check the pinout for your specific board. You can also reassign UART pins in code if your board doesn’t have them pre-assigned.

UART0 and the Serial Monitor

In most IDEs like the Arduino IDE or PlatformIO, the Serial Monitor interacts with the ESP32 over a USB connection. This is internally mapped to UART0 on the ESP32, so when you open the Serial Monitor, you are using UART communication to send and receive messages.

Note: you can use UART0 to communicate with other devices after uploading code to the board if you don’t use the Serial Monitor.

Here’s a basic example that shows a two-way communication between the ESP32 and the Serial Monitor (your computer).

/*********
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Complete instructions at https://RandomNerdTutorials.com/esp32-uart-communication-serial-arduino/
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*********/

String receivedMessage = "";  // Variable to store the complete message

void setup() {
  // Start the Serial Monitor at a baud rate of 115200
  Serial.begin(115200);
  
  // Print an initial message to the Serial Monitor
  Serial.println("ESP32 is ready. Please enter a message:");
}

void loop() {
  // Check if data is available in the Serial buffer
  while (Serial.available()) {
    char incomingChar = Serial.read();  // Read each character from the buffer
    
    if (incomingChar == '\n') {  // Check if the user pressed Enter (new line character)
      // Print the message
      Serial.print("You sent: ");
      Serial.println(receivedMessage);
      
      // Clear the message buffer for the next input
      receivedMessage = "";
    } else {
      // Append the character to the message string
      receivedMessage += incomingChar;
    }
  }
}

View raw code

When you use Serial.begin(115200) you are initializing a serial communication using UART0 at a 115200 baud rate.

Serial.begin(115200);

To write data to the Serial Monitor, you use the print() or println() methods on the Serial instance.

Serial.println("ESP32 is ready. Please enter a message:");

You can also send data from the Serial Monitor to the ESP32. To read that data, you can use the read() method. To check if there are any available bytes to read, you can use the available() method.

if (Serial.available()) {
    char incomingData = Serial.read();   // Read the incoming data from Serial Monitor

Testing the Example

Upload the code to your ESP32. After uploading, open the Serial Monitor at a baud rate of 115200. Then, press the ESP32 RST button to start running the program.

Uploading code to ESP32 Arduino IDE

It should print a message “ESP32 is ready. Please enter a message.

There’s a field on the Serial Monitor where you can write data to send to the ESP32 (highlighted in yellow). Write something on that field and press enter to send it to the ESP32. It will be printed back.

Testing the Serial Monitor UART communication

ESP32 Setting Custom UART Pins

Setting custom UART pins is quite simple. As we’ve seen previously, the ESP32 has three UART ports you can use: UART0, UART 1 and UART 2.

To use any of those ports, you just need to create an HardwareSerial instance on the desired UART port. For example, the following line creates a serial instance called mySerial using UART2.

HardwareSerial mySerial(2);

Then, you can use any pins of your choice. You just need to pass them to the begin() method like this:

mySerial.begin(GPS_BAUD, SERIAL_8N1, RX_GPIO, TX_GPIO);

In which RX_GPIO and TX_GPIO are the UART pins of your choice.


UART Communication with Other Devices

Now, let’s take a look at how to use UART to communicate with other devices. We’ll see an example to communicate with a GPS module, and an example to communicate with another ESP32.

Serial Communication with a GPS Module

To start a UART communication in your ESP32 code, you need to specify the UART port, baud rate, and pin mapping. Here’s an example of initializing UART communication with a GPS module—this can be applied to other modules or devices.

/*********
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Complete instructions at https://RandomNerdTutorials.com/esp32-neo-6m-gps-module-arduino/
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*********/

 // Define the RX and TX pins for Serial 2
#define RXD2 16
#define TXD2 17

#define GPS_BAUD 9600

// Create an instance of the HardwareSerial class for Serial 2
HardwareSerial gpsSerial(2);

void setup(){
  // Serial Monitor
  Serial.begin(115200);
  
  // Start Serial 2 with the defined RX and TX pins and a baud rate of 9600
  gpsSerial.begin(GPS_BAUD, SERIAL_8N1, RXD2, TXD2);
  Serial.println("Serial 2 started at 9600 baud rate");
}

void loop(){
  while (gpsSerial.available() > 0){
    // get the byte data from the GPS
    char gpsData = gpsSerial.read();
    Serial.print(gpsData);
  }
  delay(1000);
  Serial.println("-------------------------------");
}

View raw code

This sketch assumes you are using GPIO 16 and GPIO 17 as RX and TX serial pins to establish serial communication with the GPS module. If you’re using other pins you should edit that on the following lines:

// Define the RX and TX pins for Serial 2
#define RXD2 16
#define TXD2 17

Then, we define the module baud rate on the following line.

#define GPS_BAUD 9600

We create an instance of the HardwareSerial to use UART 2 called gpsSerial.

// Create an instance of the HardwareSerial class for Serial 2
HardwareSerial gpsSerial(2);

In the setup(), we initiate the Serial Monitor.

// Serial Monitor
Serial.begin(115200);

Next, we initialize a serial communication with the GPS module using the begin() method on the gpsSerial() instance.

// Start Serial 2 with the defined RX and TX pins and a baud rate of 9600
gpsSerial.begin(GPS_BAUD, SERIAL_8N1, RXD2, TXD2);
Serial.println("Serial 2 started at 9600 baud rate");

The begin() method accepts as arguments the baud rate, communication frame format (data, parity and stop bits, SERIAL_8N1 is the default), and RX and TX pins.

SERIAL_8N1 means 8 data bits, No parity, 1 stop bit, which is the most commonly used. You can check all the options here.

In the loop(), the code checks if there is GPS data on the serial port with the available() method.

void loop(){
  while (gpsSerial.available() > 0){

When data is available, we read it using the read() method and then print it in the Serial Monitor.

void loop(){
while (gpsSerial.available() > 0){
// get the byte data from the GPS
char gpsData = gpsSerial.read();
Serial.print(gpsData);
}
delay(1000);
Serial.println("-------------------------------");
}

For the complete instructions to test this code, make sure to take a look at our GPS Module tutorial: ESP32 with NEO-6M GPS Module (Arduino IDE).


ESP32 Serial Communication Between Boards (Sender and Receiver)

If you want to communicate with another ESP32, it is not much different. You basically initialize a serial communication on the desired GPIOs and then use the functions to read and send data via serial.

To show you how this works, we’ll send data via Serial from one ESP32 board to the other. The ESP32 sender will continuously send a message with a counter over UART. The ESP32 receiver board receiver will receive the number from the other board.

To test the example:

  • you need two ESP32 boards;
  • one board will be the sender and the other will be the receiver
  • we’ll use UART1 and we’ll assign TX to GPIO 19 and RX to GPIO 21 (you can use any other pins)—we’re not using the default pins to show you how it’s done;
  • you need to connect the RX from one board to the TX of the other and connect the GNDs together
ESP32 #1 (Sender)ESP32 #2 (Receiver)
TXD1 (GPIO 19)RXD1 (GPIO 21)
RXD1 (GPIO 21)TXD1 (GPIO 19)
GNDGND
ESP32 UART communication between boards

ESP32 Sender Code

Here’s the code for the ESP32 sender. Upload it to your board.

/*********
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Complete instructions at https://RandomNerdTutorials.com/esp32-uart-communication-serial-arduino/
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*********/

// Define TX and RX pins for UART (change if needed)
#define TXD1 19
#define RXD1 21

// Use Serial1 for UART communication
HardwareSerial mySerial(1);

int counter = 0;

void setup() {
  Serial.begin(115200);
  mySerial.begin(9600, SERIAL_8N1, RXD1, TXD1);  // UART setup
  
  Serial.println("ESP32 UART Transmitter");
}

void loop() {
  
  // Send message over UART
  mySerial.println(String(counter));
  
  Serial.println("Sent: " + String(counter));
  
  // increment the counter
  counter++;
  
  delay(1000); 
}

View raw code

How Does the Code Work?

Let’s take a look at how the code works.

Start by defining the TX and RX pins you want to use. We’re using GPIO19 and GPIO21, but you can use any other pins.

#define TXD1 19
#define RXD1 21

We’re using UART1, but for this example we could also have chosen UART2. To use UART1, we start by creating an HardwareSerial instance called mySerial.

// UART1
HardwareSerial mySerial(1);

Then, we create a variable to hold the number we want to send to the other board called counter.

int counter = 0;

In the setup(), we initialize the serial communication on UART1 by calling the begin() method on the mySerial object.

mySerial.begin(9600, SERIAL_8N1, RXD1, TXD1);  // UART setup

In the loop(), we send the counter via serial by using the println() method on our mySerial object. This is what will send the number to the other board.

mySerial.println(String(counter));

Then, we increment the counter on each loop.

// increment the counter
counter++;

A new message is sent every second, but you can change the delay time if needed.

delay(1000); 

Uploading the Code

Upload the code to the sender board. After uploading open the serial monitor at a baud rate of 115200. You’ll see that it will start sending data via UART.

ESP32 UART Sender Demonstration

Now, let’s prepare the receiver to receive the data.

ESP32 Receiver Code

Here’s the code for the ESP32 receiver. Upload it to your board.

/*********
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Complete instructions at https://RandomNerdTutorials.com/esp32-uart-communication-serial-arduino/
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*********/

// Define TX and RX pins for UART (change if needed)
#define TXD1 19
#define RXD1 21

// Use Serial1 for UART communication
HardwareSerial mySerial(2);

void setup() {
  Serial.begin(115200);
  mySerial.begin(9600, SERIAL_8N1, RXD1, TXD1);  // UART setup
  
  Serial.println("ESP32 UART Receiver");
}

void loop() {
  // Check if data is available to read
  if (mySerial.available()) {
    // Read data and display it
    String message = mySerial.readStringUntil('\n');
    Serial.println("Received: " + message);
  }
}

View raw code

How Does the Code Work?

Setting up the serial connection is the same as we’ve seen in the previous example. The loop() is different. In this case, we’ll listen for incoming data.

Then, to receive data from the other board, we start by checking if there are any available bytes to read.

// Check if data is available to read
if (mySerial.available()) {

Then, we read the incoming data and saved it in the message variable using the readStringUntil() method.

String message = mySerial.readStringUntil('\n');

This method reads data from the UART serial buffer as a String, continuing to read characters until it encounters the newline character ‘\n‘ .

The ‘\n‘ is typically used to mark the end of a message or line. When it encounters this character in the incoming data stream, it stops reading and returns the string up to that point.

Upload the Code

Upload the previous code to the receiver board. Open a Serial Monitor connection with this new board.

ESP32 communication via UART

The ESP32 sender will continuously send a message with a counter over UART. The ESP32 board receiver will receive the number from the other board.

ESP32 UART receiver demonstration

Now you have one ESP32 board sending data to the other.

Wrapping Up

This tutorial was a getting started guide to UART communication with the ESP32. We’ve seen how UART works, how to use the ESP32 UART ports on the desired pins, and how to send data from one ESP32 to the other.

We hope you found this guide useful.

We have guides for other communication protocols with the ESP32 that you may find useful.

Learn more about the ESP32 with our resources:

Thanks for reading.



Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »
Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »

Enjoyed this project? Stay updated by subscribing our newsletter!

4 thoughts on “ESP32 UART Communication (Serial): Set Pins, Interfaces, Send and Receive Data (Arduino IDE)”

  1. Thanks a lot: this is very useful to many of us.
    Anyway compiling sketches for the ESP32 using Arduino IDE is almost unpossible because a very long time. Normally it takes about 3 or more minutes to compile and this is not acceptable for a practical use. Any solution to this big problem ?
    Thanks

    Reply
  2. I know lot of people that are expeiencing a very long compiling time as I told. Question: are you experiencing the same problem , please ? If Not, could you please inform about your configuration ?
    Thanks

    Reply

Leave a Comment

Download Our Free eBooks and Resources

Get instant access to our FREE eBooks, Resources, and Exclusive Electronics Projects by entering your email address below.