Achieving Full-Duplex Serial Communication Between Two ESP32 Boards

 The ESP32 microcontroller, renowned for its robust features and wireless capabilities, enables seamless bidirectional communication through full-duplex communication. This article delves into implementing full-duplex communication between two ESP32 modules using the UART (Universal Asynchronous Receiver-Transmitter) interface. Which is also known as serial communication. We will explain the code for both the sender and receiver, exploring the intricacies of simultaneous data transmission and reception.

Component list

To establish a serial communication between esp32, we are going to need the following components:

  • ESP32 Modules: Two ESP32 microcontrollers for bidirectional communication.
  • USB Cable: For programming and power.
  • Jumper Wires: To connect TX and RX pins, and establish a common ground.
  • Power Source: Depending on your setup, you might need a power source for each ESP32.

Circuit Diagram from ESP32 to ESP32 UART Communication

Before we embark on the code explanation, it's essential to have a clear understanding of the hardware setup. Ensure you have two ESP32 modules available and connect them as follows:

  • Connect the TX pin of ESP32-A to the RX pin of ESP32-B.
  • Connect the TX pin of ESP32-B to the RX pin of ESP32-A.
  • Establish a common ground by connecting the GND pins of both ESP32 modules.
Achieving Full-Duplex Communication Between Two ESP32 Boards
Connection Diagram for ESP32 Serial Communication

Certainly! Let's delve into the code for both the sender and receiver ESP32 modules, providing a detailed explanation of each section.

Sender ESP32 Code

The following Arduino code is for the sender esp32 or esp32-A.

// Sender ESP32 Code
void setup() {
  Serial.begin(115200);       // Initialize serial communication for USB
  Serial2.begin(115200, SERIAL_8N1, 16, 17);  // Initialize Serial2 for external communication (TX: 16, RX: 17)
}
void loop() {
  if (Serial.available() > 0) {
    String message = Serial.readStringUntil('\n');  // Read message from USB serial
    Serial2.println("Sender says: " + message);   // Send message to Serial2
  }
  if (Serial2.available() > 0) {
    String message = Serial2.readStringUntil('\n'); // Read message from Serial2
    Serial.print("Received from Receiver: ");
    Serial.println(message);  // Print received message to USB serial
  }
}code-box

Explanation:

1. Serial Initialization:

   - Serial.begin(115200);: This line initializes the Serial object for USB communication with a baud rate of 115200.

2. Serial2 Initialization:

   - Serial2.begin(115200, SERIAL_8N1, 16, 17);: This line initializes Serial2 for external communication with a baud rate of 115200, 8 data bits, no parity, and 1 stop bit. The pins 16 and 17 are specified as the TX and RX pins, respectively.

3. Sender Input Handling:

   - if (Serial.available() > 0): This condition checks if there is any data available from the USB serial (connected to Serial). If true, it reads the message until a newline character is encountered using `Serial.readStringUntil('\n')`.

   - Serial2.println("Sender says: " + message);: This line sends the received message appended with "Sender says:" to Serial2, representing the outgoing message from the sender to the receiver.

4. Receiver Response Handling:

   - if (Serial2.available() > 0): This condition checks if there is any data available from Serial2 (external communication). If true, it reads the incoming message until a newline character is encountered.

   - Serial.print("Received from Receiver: "); Serial.println(message);: This line prints the received message from the receiver to the USB serial for monitoring and debugging.

Receiver ESP32 Code

The following Arduino code is for receiver esp32 or esp32-B.

//Receiver esp32 code
void setup() {
  Serial.begin(115200);       // Initialize serial communication for USB
  Serial2.begin(115200, SERIAL_8N1, 16, 17);  // Initialize Serial2 for external communication (TX: 16, RX: 17)
}
void loop() {
  if (Serial.available() > 0) {
    String message = Serial.readStringUntil('\n');  // Read message from USB serial
    Serial2.println("Receiver says: " + message); // Send message to Serial2
  }
  if (Serial2.available() > 0) {
    String message = Serial2.readStringUntil('\n'); // Read message from Serial2
    Serial.print("Received from Sender: ");
    Serial.println(message);  // Print received message to USB serial
  }
}code-box

Receiver esp32 code Explanation:

The receiver code follows a similar structure to the sender code.

1. Serial Initialization:

   - Serial.begin(115200);: Initializes the Serial object for USB communication with a baud rate of 115200.

2. Serial2 Initialization:

   - Serial2.begin(115200, SERIAL_8N1, 16, 17);: Initializes Serial2 for external communication with the same configuration as the sender.

3. Receiver Input Handling:

   - if (Serial.available() > 0): Checks if there is any data available from the USB serial. If true, it reads the message until a newline character is encountered.

   - Serial2.println("Receiver says: " + message);: Sends the received message appended with "Receiver says:" to Serial2, representing the outgoing message from the receiver to the sender.

4. Sender Response Handling:

   - if (Serial2.available() > 0): Checks if there is any data available from Serial2 (communication from the sender). If true, it reads the incoming message until a newline character is encountered.

   - Serial.print("Received from Sender: "); Serial.println(message);: Prints the received message from the sender to the USB serial for monitoring and debugging.

Testing Full-Duplex Communication Between ESP32

Upload Code:

   - Upload the sender code to ESP32-A and the receiver code to ESP32-B using the Arduino IDE.

Serial Monitor:

   - Open the Serial Monitor for both ESP32-A and ESP32-B to observe the bidirectional communication. Messages sent by the sender should be received by the receiver, and vice versa.

Key Points to Note

Simultaneous Communication:

   - The code in both the sender and receiver modules allows for simultaneous communication. The sender can send messages to the receiver, and vice versa, without interrupting the flow of communication.

UART Configuration:

   - The `Serial2.begin(115200, SERIAL_8N1, 16, 17);` line initializes the second hardware serial (`Serial2`) with a baud rate of 115200, 8 data bits, no parity, and 1 stop bit. Adjust these parameters based on your specific requirements.

Message Handling:

   - Messages are sent and received using the `Serial.println` and `Serial2.println` functions. The newline character (`'\n'`) delimits messages, enabling the receiver to read complete messages.

Adaptability:

   - The provided code is a foundation that can be adapted for various projects. Whether you're working on IoT applications, sensor networks, or remote control systems, understanding full-duplex communication is crucial.

 Conclusion

Implementing full-duplex communication between ESP32 modules enhances the capabilities of your projects by enabling simultaneous data transmission and reception. By leveraging the UART interface and understanding the intricacies of the code, you have the flexibility to adapt the communication protocol to suit the specific requirements of your applications. As you explore the vast possibilities of bidirectional communication, you'll be well-equipped to build sophisticated and interconnected systems using ESP32 microcontrollers.