Introduction

Hello everyone, today I’m excited to share the process of setting up RS-485 communication using ESP32-S3. This is a key part of my project to create a wireless node sensor for measuring tunnel structure displacements. However, in this article, I’ll guide you through the process of establishing RS-485 communication between two ESP32-S3 devices: one as the master and the other as the slave. This configuration enables seamless data exchange between the devices, making it valuable for various applications.

The Hardware

The hardware for this project comprises two ESP32-S3 devices (Get them here), with both equipped with RS-485 communication capabilities using a straightforward TTL-RS485 module (Available here). One of these devices serves as the master, while the other assumes the role of the slave. In this setup, the master initiates requests to the slave, and the slave promptly responds with the requested data.

Wiring

Below is a simple schematic for the wiring:

Codes

The testing codes are available on my Github here

Code for the Slave:

#include <ModbusRTU.h>
#define RXD1 17
#define TXD1 18
#define SLAVE_ID 1 // Modbus Slave ID
#define REGN 1

const int analogPin = A0;

ModbusRTU mb;

void setup() {
  Serial.begin(9600, SERIAL_8N1);
  Serial1.begin(9600, SERIAL_8N1, RXD1, TXD1);  // Start the Serial1 communication
  mb.begin(&Serial1);
  
  mb.slave(SLAVE_ID); // Initialize the modbus slave device with ID 1
  mb.addHreg(REGN); // Add a register with address 1
  mb.Hreg(REGN, 100); // Assign a value of 100 to the local Holding Register #REGN (for testing)
}

void loop() {
  mb.task(); // Process incoming Modbus requests

  // Read the analog value from the analog pin
  uint16_t sensorValue = analogRead(analogPin);

  // Update the holding register with the sensor value
  mb.Hreg(REGN, sensorValue); // Store the value in holding register 0
  delay(100); // Add a small delay for stability

  yield();
}

Code for the Master:

#include <ModbusRTU.h>

#define SLAVE_ID 1
#define RXD1 17
#define TXD1 18
#define REGN 1
#define REG_COUNT 1

ModbusRTU mb;

bool cb(Modbus::ResultCode event, uint16_t transactionId, void* data) { // Callback to monitor errors
  Serial.printf_P("Request result: 0x%02X, Mem: %d\n", event, ESP.getFreeHeap());
  return true;
}

void setup() {
  Serial.begin(9600);
  Serial1.begin(9600, SERIAL_8N1, RXD1, TXD1);
  mb.begin(&Serial1);
  mb.master();
}

void loop() {
  uint16_t res[REG_COUNT];
  if (!mb.slave()) {    // Check if no transaction is in progress
    mb.readHreg(SLAVE_ID, REGN, res, REG_COUNT, cb); // Send Read Hreg to the Modbus Server
    while (mb.slave()) { // Check if a transaction is active
      mb.task();
      delay(10);
    }
    Serial.println(res[0]);
  }
  delay(1000);
}

Serial Monitor Output

Upon successful setup and execution of your RS-485 communication, you can monitor the communication through the serial monitor. Here’s a sample output to expect:

Conclusion

This project demonstrates how to establish RS-485 communication between ESP32-S3 devices. The master can initiate requests to the slave, and the slave responds with the requested data. This setup provides a foundation for various applications, from data logging to remote control. As with any embedded system, thorough testing and, if necessary, calibration are essential for precise measurements and reliable data exchange