ย
๐๐๐๐๐ - ๐๐ฎ๐ฅ๐ญ๐ข๐๐ซ๐จ๐ฉ

ย
01 Overview
The RS485 Multi-Drop Communication Network is a communication system that utilizes the Modbus RTU protocol to enable reliable data exchange between a master device and multiple ESP32 slave devices over a shared RS485 bus. The project is implemented in two configurations: (1) an ESP32 Master communicating with two ESP32 Slaves, and (2) a PC acting as the Master communicating with three ESP32 Slaves through an RS485-to-USB converter. In both configurations, the master sequentially polls each slave for data. Slave 1 collects temperature and humidity readings from a DHT11 sensor, Slave 2 detects touch input using a TTP223 capacitive touch sensor, and Slave 3 serves as an additional Modbus RTU slave for expansion or future sensor integration. The project demonstrates centralized monitoring, reliable serial communication, and scalable network architecture suitable for industrial and educational applications.
Project Use Case
The RS485 Multi-Drop Communication Network can be applied in industrial automation, environmental monitoring, smart building systems, laboratories, and educational environments where multiple sensor nodes need to communicate with a central controller or computer. Using the Modbus RTU protocol over RS485 allows long-distance communication, reduced wiring, and reliable data transmission in electrically noisy environments. The system can be expanded by adding more slave devices, making it suitable for monitoring multiple sensors and devices from a single master station.
02 Hardware and Software Components
Gather everything below before you start. This is your checklist - names, models, and versions only.
Hardware Components
| PHOTO | Component | Description |
|---|---|---|
![]() |
ย ESP32-WROOM-32 | The ESP32-WROOM-32 development board is a powerful, low-power IoT platform with Wi-Fi and Bluetooth, ideal for prototyping and embedded system projects. |
![]() |
MAX485 TTL To RS485 Serialย |
|
![]() |
RS485 to USB 2.0 TTL Serial Converter |
Supports various RS485 devices, including cameras, fingerprint machines, CNC machines, PBX systems, and microcontrollers. |
![]() |
Temperature and Humidity sensor module - DHT11 |
The DHT11 is an affordable and reliable sensor that measures temperature from 0ยฐC to 50ยฐC and relative humidity from 20% to 90% RH. |
![]() |
Digital Touch Sensor |
The TTP223B capacitive touch sensor module detects finger touches and outputs a high signal when activated, while consuming low power in standby mode. |
![]() |
Dupont Jumper Wires | Flexible wires used to connect electronic components and Arduino pins, providing reliable signal and power connections during prototyping without soldering. |
Software Tools
| Software | Version / Details |
|---|---|
| Arduino IDE | Version 2.3.8 |
| Pythonย | Version 3.14.6 |
| DHT sensor library | Version 1.4.7 |
Project Filesย
All required files are available in the project repository. Download the repository before proceeding to the Software Setup section.
| FILE | DESCRIPTION |
|---|---|
| DHT sensor library | The DHT Sensor Library developed by Adafruit. It simplifies communication with DHT series sensors (DHT11, DHT22, etc.) by providing easy-to-use functions for reading temperature and humidity values without manually implementing the sensor's communication protocol. |
03 Hardware Wiring andย Setup
Schematic Diagram "ESP32 acts as the Master"

Assembly Instructions
- Assemble the three ESP32 development boards and mount each board securely on separate breadboards or project bases.
- Connect one MAX485 RS485 transceiver module to each ESP32 using the designated UART pins (TX2 and RX2), and connect the RE and DE pins together to the assigned control pin.
- Connect the DHT11 temperature and humidity sensor to ESP32 Slave 1 by wiring the VCC, GND, and DATA pins to the appropriate ESP32 GPIO pin.
- Connect the TTP223 capacitive touch sensor to ESP32 Slave 2 by wiring the VCC, GND, and OUT pins to the appropriate ESP32 GPIO pin.
- Connect all MAX485 modules through the RS485 communication bus by wiring the A terminal to A, B terminal to B, and connecting a common GND between all devices.
- Power each ESP32 using a USB cable or an appropriate external power supply, ensuring that all modules receive the required operating voltage.
- Verify that all electrical connections are correct, secure, and properly connected before powering on the system.
- Upload the corresponding program to the ESP32 Master, ESP32 Slave 1, and ESP32 Slave 2, then open the Serial Monitor on the Master ESP32 to verify successful RS485 communication and sensor data exchange.
PC Master Wiring Diagram: Wire the components to the ESP32 slave boards using the tables below. The PC acts as the Master, while the three ESP32 boards act as Slave Nodes in the RS485 communication network.
Schematic Diagramย "PC acts as the Master"
ย

Assembly Instructions
- Mount the three ESP32 boards on separate breadboards.
- Connect one MAX485 module to each ESP32 using the TX2, RX2, RE, and DE pins.
- Connect the DHT11 sensor to ESP32 Slave 1.
- Connect the TTP223 touch sensor to ESP32 Slave 2.
- Connect all MAX485 modules and the PCโs RS485-to-USB converter to the same RS485 bus (A-to-A, B-to-B, and common GND).
- Connect the RS485-to-USB converter to the PC using a USB cable.
- Power all ESP32 boards through USB or an external power supply.
- Check that all wiring is secure and correct.
- Upload the appropriate program to each ESP32 slave.
- Open the PC master application, select the correct COM port, and verify communication with all three ESP32 slave devices.
04ย Software Setup
ESP32 Master and Two ESP32 Slaves: Follow these steps in order to set up and test the RS485 communication network, with one ESP32 acting as the Master and two ESP32 boards acting as Slave nodes. Do not skip any step.
Download this first before proceeding.
Step 1: Install the Arduino IDE
- Download and install the Arduino IDE on your computer.
- Install the ESP32 Board Package in the Arduino IDE through the Boards Manager to enable programming of ESP32 development boards.
- Install the required libraries using the Library Manager: DHT Sensor Library by Adafruit Adafruit Unified Sensor
- Connect each ESP32 board to the computer using a USB cable and select the appropriate COM port and ESP32 board in the Arduino IDE.
- Open the corresponding source code for the Master, Slave 1 (DHT11), and Slave 2 (TTP223).
- Configure the communication parameters, including the UART pins, baud rate, slave addresses, and sensor pin assignments, according to the hardware connections.
- Compile and upload the appropriate program to each ESP32 board.
- Open the Serial Monitor for the Master ESP32 and verify that communication with the slave devices is successfully established and that sensor data is received correctly.
Step 2: Board Settings
Use exactly these settings in your IDE. Wrong settings will cause upload failures.
| Setting | Value |
|---|---|
| Board | ESP32 Dev module |
| Baud Rate | 115200 |
| Portย | Select the detectedย COM Port |
Step 3: Install Libraries
Install the following libraries via the Library Manager:
- DHT sensor library
ย
PC Master and Three ESP32 Slaves: Follow these steps in order to set up and test the RS485 communication network, with the PC acting as the Master and the three ESP32 boards acting as Slave nodes. Do not skip any step.
Download this first before proceeding.
Step 1: Install the Arduino IDE and Python
- Install the Required Software Download and install the Arduino IDE and Python on the PC.
- Install the ESP32 Board Package Open the Arduino IDE and install the ESP32 Board Package through the Boards Manager.
- Install the Required Libraries Install the required Arduino libraries (e.g., ModbusRTU and DHT Sensor Library by Adafruit, if using the DHT11 sensor) using the Library Manager.
- Connect the ESP32 Boards Connect each ESP32 slave board to the PC using a USB cable and select the correct ESP32 board and COM port in the Arduino IDE.
- Open the Source Codes Open the corresponding source code for ESP32 Slave 1 (DHT11), ESP32 Slave 2 (TTP223), ESP32 Slave 3, and the Python PC Master application.
- Open the Source Codes Open the corresponding source code for ESP32 Slave 1 (DHT11), ESP32 Slave 2 (TTP223), ESP32 Slave 3, and the Python PC Master application.
- Upload the ESP32 Programs Compile and upload the appropriate firmware to each ESP32 slave board.
- Run the PC Master Application Connect the RS485-to-USB converter to the PC, launch the Python master application, and select the correct COM port.
- Verify Communication Confirm that the PC master successfully communicates with all three ESP32 slave devices and correctly receives sensor data and responses over the RS485 network.
05 Code for ESP Master
Copy each file below into the correct location as described in the Software Setup section. This code is designed for a network consisting of one ESP32 Master and two ESP32 Slave nodes. Read the Code Breakdown section to understand the function of each part.
/*
RS485 MASTER
ESP32 + MAX485
*/
#define RXD2 16
#define TXD2 17
#define DE_RE 4
//------------------------------------------------------
// MODBUS CRC16
//------------------------------------------------------
uint16_t ModRTU_CRC(uint8_t buf[], int len)
{
uint16_t crc = 0xFFFF;
for (int pos = 0; pos < len; pos++)
{
crc ^= (uint16_t)buf[pos];
for (int i = 0; i < 8; i++)
{
if (crc & 1)
{
crc >>= 1;
crc ^= 0xA001;
}
else
{
crc >>= 1;
}
}
}
return crc;
}
//------------------------------------------------------
void printFrame(uint8_t frame[], int len)
{
for (int i = 0; i < len; i++)
{
if (frame[i] < 0x10)
Serial.print("0");
Serial.print(frame[i], HEX);
if (i < len - 1)
Serial.print(" ");
}
Serial.println();
}
//------------------------------------------------------
void rs485Transmit()
{
digitalWrite(DE_RE, HIGH);
}
void rs485Receive()
{
digitalWrite(DE_RE, LOW);
}
//------------------------------------------------------
// Request Slave
//------------------------------------------------------
void requestSlave(uint8_t slaveID, uint16_t regCount)
{
uint8_t request[8];
request[0] = slaveID; // Slave Address
request[1] = 0x03; // Function Code
request[2] = 0x00;
request[3] = 0x00;
request[4] = highByte(regCount);
request[5] = lowByte(regCount);
uint16_t crc = ModRTU_CRC(request, 6);
request[6] = lowByte(crc);
request[7] = highByte(crc);
Serial.println();
if (slaveID == 1)
Serial.println("----- Slave 1 -----");
else if (slaveID == 2)
Serial.println("----- Slave 2 -----");
Serial.print("TX > ");
printFrame(request, 8);
rs485Transmit();
Serial2.write(request, 8);
Serial2.flush();
rs485Receive();
}
//------------------------------------------------------
void setup()
{
Serial.begin(115200);
Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2);
pinMode(DE_RE, OUTPUT);
rs485Receive();
Serial.println();
Serial.println("=================================");
Serial.println(" RS485 MASTER STARTED");
Serial.println("=================================");
}
//------------------------------------------------------
void loop()
{
requestSlave(1, 2);
unsigned long start = millis();
uint8_t response[20];
int index = 0;
while (millis() - start < 1000)
{
while (Serial2.available())
{
response[index++] = Serial2.read();
}
if (index >= 9)
break;
}
if (index == 0)
{
Serial.println("No Response");
}
else
{
Serial.print("RX < ");
printFrame(response, index);
// Check CRC
uint16_t crcCalc = ModRTU_CRC(response, index - 2);
uint16_t crcRecv = response[index - 2] | (response[index - 1] << 8);
if (crcCalc == crcRecv)
{
Serial.println("CRC : PASS");
// Decode only if valid response
if (response[1] == 0x03 && response[2] == 0x04)
{
uint16_t temp = (response[3] << 8) | response[4];
uint16_t hum = (response[5] << 8) | response[6];
Serial.print("Temperature : ");
Serial.print(temp / 10.0, 1);
Serial.println(" ยฐC");
Serial.print("Humidity : ");
Serial.print(hum / 10.0, 1);
Serial.println(" %");
}
}
else
{
Serial.println("CRC : FAIL");
}
//--------------------------------------------------
// REQUEST SLAVE 2
//--------------------------------------------------
delay(100);
requestSlave(2, 1);
start = millis();
index = 0;
while (millis() - start < 1000)
{
while (Serial2.available())
{
response[index++] = Serial2.read();
}
if (index >= 7)
break;
}
if (index == 0)
{
Serial.println("No Response from Slave 2");
}
else
{
Serial.print("RX < ");
printFrame(response, index);
uint16_t crcCalc = ModRTU_CRC(response, index - 2);
uint16_t crcRecv = response[index - 2] | (response[index - 1] << 8);
if (crcCalc == crcRecv)
{
Serial.println("CRC : PASS");
if (response[1] == 0x03 && response[2] == 0x02)
{
uint16_t touch = (response[3] << 8) | response[4];
Serial.print("Touch Status : ");
if (touch == 1)
Serial.println("PRESSED");
else
Serial.println("RELEASED");
}
}
else
{
Serial.println("CRC : FAIL");
}
}
}delay(3000);
}
/*
RS485 DHT11 SLAVE
ESP32 + MAX485
*/
#include
#define RXD2 16
#define TXD2 17
#define DE_RE 4
#define DHTPIN 15
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
//------------------------------------------------------
// CRC16
//------------------------------------------------------
uint16_t ModRTU_CRC(uint8_t buf[], int len)
{
uint16_t crc = 0xFFFF;
for (int pos = 0; pos < len; pos++)
{
crc ^= buf[pos];
for (int i = 0; i < 8; i++)
{
if (crc & 1)
{
crc >>= 1;
crc ^= 0xA001;
}
else
{
crc >>= 1;
}
}
}
return crc;
}
//------------------------------------------------------
void printFrame(uint8_t frame[], int len)
{
for (int i = 0; i < len; i++)
{
if (frame[i] < 0x10)
Serial.print("0");
Serial.print(frame[i], HEX);
if (i < len - 1)
Serial.print(" ");
}
Serial.println();
}
//------------------------------------------------------
void rs485Transmit()
{
digitalWrite(DE_RE, HIGH);
}
void rs485Receive()
{
digitalWrite(DE_RE, LOW);
}
//------------------------------------------------------
void setup()
{
Serial.begin(115200);
Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2);
pinMode(DE_RE, OUTPUT);
rs485Receive();
dht.begin();
Serial.println();
Serial.println("=================================");
Serial.println(" RS485 DHT11 SLAVE");
Serial.println("=================================");
Serial.println("Waiting for Master...");
}
//------------------------------------------------------
void loop()
{
if (Serial2.available() >= 8)
{
uint8_t request[8];
int len = Serial2.readBytes(request, 8);
Serial.println();
Serial.print("RX < ");
printFrame(request, len);
// ---------------- CRC Check ----------------
uint16_t crcCalc = ModRTU_CRC(request, 6);
uint16_t crcRecv = request[6] | (request[7] << 8);
if (crcCalc != crcRecv)
{
Serial.println("CRC ERROR");
return;
}
// ---------------- Read Sensor ----------------
float temperature = dht.readTemperature();
float humidity = dht.readHumidity();
if (isnan(temperature) || isnan(humidity))
{
Serial.println("DHT11 Read Failed!");
return;
}
uint16_t temp = (uint16_t)(temperature * 10);
uint16_t hum = (uint16_t)(humidity * 10);
// ---------------- Build Response ----------------
uint8_t response[9];
response[0] = 0x01; // Slave ID
response[1] = 0x03; // Function
response[2] = 0x04; // 4 data bytes
response[3] = highByte(temp);
response[4] = lowByte(temp);
response[5] = highByte(hum);
response[6] = lowByte(hum);
uint16_t crc = ModRTU_CRC(response, 7);
response[7] = lowByte(crc);
response[8] = highByte(crc);
// ---------------- Send ----------------
delay(2);
rs485Transmit();
Serial2.write(response, 9);
Serial2.flush();
rs485Receive();
// ---------------- Display ----------------
Serial.println("CRC : PASS");
}
}
/*
RS485 TTP223 SLAVE
ESP32 + MAX485
*/
#define RXD2 16
#define TXD2 17
#define DE_RE 4
#define TOUCH_PIN 15
//------------------------------------------------------
// CRC16
//------------------------------------------------------
uint16_t ModRTU_CRC(uint8_t buf[], int len)
{
uint16_t crc = 0xFFFF;
for (int pos = 0; pos < len; pos++)
{
crc ^= buf[pos];
for (int i = 0; i < 8; i++)
{
if (crc & 1)
{
crc >>= 1;
crc ^= 0xA001;
}
else
{
crc >>= 1;
}
}
}
return crc;
}
//------------------------------------------------------
void printFrame(uint8_t frame[], int len)
{
for (int i = 0; i < len; i++)
{
if (frame[i] < 0x10)
Serial.print("0");
Serial.print(frame[i], HEX);
if (i < len - 1)
Serial.print(" ");
}
Serial.println();
}
//------------------------------------------------------
void rs485Transmit()
{
digitalWrite(DE_RE, HIGH);
}
void rs485Receive()
{
digitalWrite(DE_RE, LOW);
}
//------------------------------------------------------
void setup()
{
Serial.begin(115200);
Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2);
pinMode(DE_RE, OUTPUT);
pinMode(TOUCH_PIN, INPUT);
rs485Receive();
Serial.println();
Serial.println("=================================");
Serial.println(" RS485 TTP223 SLAVE");
Serial.println("=================================");
Serial.println("Waiting for Master...");
}
//------------------------------------------------------
void loop()
{
if (Serial2.available() >= 8)
{
uint8_t request[8];
int len = Serial2.readBytes(request, 8);
Serial.println();
Serial.print("RX < ");
printFrame(request, len);
// CRC Check
uint16_t crcCalc = ModRTU_CRC(request, 6);
uint16_t crcRecv = request[6] | (request[7] << 8);
if (crcCalc != crcRecv)
{
Serial.println("CRC ERROR");
return;
}
// Check Slave ID
if (request[0] != 0x02)
{
// Hindi para sa Slave 2
return;
}
// Read Touch Sensor
bool touch = digitalRead(TOUCH_PIN);
// Build Response
uint8_t response[7];
response[0] = 0x02; // Slave ID
response[1] = 0x03; // Function Code
response[2] = 0x02; // 2 bytes of data
response[3] = 0x00;
response[4] = touch ? 0x01 : 0x00;
uint16_t crc = ModRTU_CRC(response, 5);
response[5] = lowByte(crc);
response[6] = highByte(crc);
delay(2);
rs485Transmit();
Serial2.write(response, 7);
Serial2.flush();
rs485Receive();
Serial.print("TX > ");
printFrame(response, 7);
Serial.print("Touch Status : ");
if (touch)
Serial.println("PRESSED");
else
Serial.println("RELEASED");
Serial.println("CRC : PASS");
}
}
06ย Code for PC Master
import serial
import time
from config import *
from protocol import build_request
class SerialManager:
def __init__(self):
self.serial = None
self.connected = False
# ==============================
# CONNECT
# ==============================
def connect(self):
try:
self.serial = serial.Serial(
port=COM_PORT,
baudrate=BAUDRATE,
timeout=TIMEOUT
)
time.sleep(2)
self.connected = True
return True
except Exception as e:
print(e)
return False
# ==============================
# DISCONNECT
# ==============================
def disconnect(self):
if self.serial:
self.serial.close()
self.connected = False
# ==============================
# SEND REQUEST
# ==============================
def send_request(self, slave_id, register_count):
request = build_request(slave_id, register_count)
self.serial.reset_input_buffer()
self.serial.reset_output_buffer()
self.serial.write(request)
self.serial.flush()
return request
# ==============================
# RECEIVE RESPONSE
# ==============================
def receive_response(self, length):
timeout = time.time() + 0.30
response = b''
while len(response) < length and time.time() < timeout:
response += self.serial.read(length - len(response))
return response
# ==============================
# READ SLAVE 1
# ==============================
def read_slave1(self):
if not self.connected:
return None
request = self.send_request(SLAVE1_ID, 2)
response = self.receive_response(9)
if len(response) != 9:
return None
temperature = ((response[3] << 8) | response[4]) / 10.0
humidity = ((response[5] << 8) | response[6]) / 10.0
return {
"request": request,
"response": response,
"temperature": temperature,
"humidity": humidity
}
# ==============================
# READ SLAVE 2
# ==============================
def read_slave2(self):
if not self.connected:
return None
request = self.send_request(SLAVE2_ID, 2)
response = self.receive_response(7)
if len(response) != 7:
return None
touch = bool(response[4])
return {
"request": request,
"response": response,
"touch": touch
}
# ==============================
# READ SLAVE 3
# ==============================
def read_slave3(self):
if not self.connected:
return None
request = self.send_request(3, 1)
response = self.receive_response(7)
if len(response) != 7:
return None
return {
"request": request,
"response": response,
"message": chr(response[3]) + chr(response[4])
}
from serial_manager import SerialManager
from datetime import datetime
import time
import customtkinter as ctk
# ==========================================
# THEME
# ==========================================
ctk.set_appearance_mode("dark")
ctk.set_default_color_theme("green")
# ==========================================
# WINDOW
# ==========================================
app = ctk.CTk()
app.title("RS485 Multi-Drop Communication Network")
app.geometry("1000x600")
app.resizable(False, False)
# ==========================================
# COLORS
# ==========================================
BG = "#101010"
CARD = "#1B1B1B"
GREEN = "#00FF66"
WHITE = "#FFFFFF"
ORANGE = "#FFA500"
CYAN = "#00E5FF"
app.configure(fg_color=BG)
# ==========================================
# HEADER
# ==========================================
header = ctk.CTkFrame(
app,
fg_color="#181818",
corner_radius=10,
height=80
)
header.pack(fill="x", padx=20, pady=(15,10))
title = ctk.CTkLabel(
header,
text="RS485 MULTI-DROP COMMUNICATION NETWORK",
font=("Segoe UI",30,"bold"),
text_color=GREEN
)
title.pack(side="left", padx=25)
rightFrame = ctk.CTkFrame(
header,
fg_color="transparent"
)
rightFrame.pack(side="right", padx=25)
status = ctk.CTkLabel(
rightFrame,
text="๐ข Connected",
font=("Segoe UI",18,"bold"),
text_color=GREEN
)
status.pack(anchor="e")
port = ctk.CTkLabel(
rightFrame,
text="COM7",
font=("Segoe UI",16),
text_color=CYAN
)
port.pack(anchor="e")
# ==========================================
# SERIAL
# ==========================================
sm = SerialManager()
packets_sent = 0
packets_received = 0
error_count = 0
if sm.connect():
status.configure(
text="๐ข Connected",
text_color=GREEN
)
print("======================================")
print("RS485 SERIAL MONITOR")
print("======================================")
print(f"Port : {sm.serial.port}")
print(f"Baudrate : {sm.serial.baudrate}")
print("Status : Connected")
print("======================================")
else:
status.configure(
text="๐ด Disconnected",
text_color="red"
)
print("Failed to connect!")
# ==========================================
# CARD CONTAINER
# ==========================================
cards = ctk.CTkFrame(
app,
fg_color="transparent"
)
cards.pack(fill="x", padx=20, pady=10)
# ==========================================
# SLAVE 1 CARD
# ==========================================
def create_slave1(master):
frame = ctk.CTkFrame(
master,
width=280,
height=340,
fg_color=CARD,
border_width=2,
border_color=GREEN,
corner_radius=15
)
frame.pack(side="left", padx=18, pady=10)
frame.pack_propagate(False)
ctk.CTkLabel(
frame,
text="SLAVE 1",
font=("Segoe UI",24,"bold"),
text_color=WHITE
).pack(pady=(20,15))
ctk.CTkLabel(
frame,
text="๐ก Temperature",
font=("Segoe UI",18),
text_color=ORANGE
).pack()
temp = ctk.CTkLabel(
frame,
text="--.- ยฐC",
font=("Segoe UI",48,"bold"),
text_color=ORANGE
)
temp.pack(pady=(10,30))
ctk.CTkLabel(
frame,
text="๐ง Humidity",
font=("Segoe UI",18),
text_color=CYAN
).pack()
hum = ctk.CTkLabel(
frame,
text="--.- %",
font=("Segoe UI",48,"bold"),
text_color=CYAN
)
hum.pack(pady=(10,30))
last = ctk.CTkLabel(
frame,
text="Last Update\n--:--:--",
font=("Segoe UI",18),
text_color=GREEN
)
last.pack()
return temp, hum, last
# ==========================================
# SLAVE 2 CARD
# ==========================================
def create_slave2(master):
frame = ctk.CTkFrame(
master,
width=280,
height=340,
fg_color=CARD,
border_width=2,
border_color=GREEN,
corner_radius=15
)
frame.pack(side="left", padx=18, pady=10)
frame.pack_propagate(False)
ctk.CTkLabel(
frame,
text="SLAVE 2",
font=("Segoe UI",24,"bold"),
text_color=WHITE
).pack(pady=(20,15))
ctk.CTkLabel(
frame,
text="๐ Touch Sensor",
font=("Segoe UI",18),
text_color=CYAN
).pack()
status = ctk.CTkLabel(
frame,
text="RELEASED",
font=("Segoe UI",42,"bold"),
text_color="red"
)
status.pack(pady=(30,40))
last = ctk.CTkLabel(
frame,
text="Last Update\n--:--:--",
font=("Segoe UI",18),
text_color=GREEN
)
last.pack()
return status, last
# ==========================================
# SLAVE 3 CARD
# ==========================================
def create_slave3(master):
frame = ctk.CTkFrame(
master,
width=280,
height=340,
fg_color=CARD,
border_width=2,
border_color=GREEN,
corner_radius=15
)
frame.pack(side="left", padx=18, pady=10)
frame.pack_propagate(False)
ctk.CTkLabel(
frame,
text="SLAVE 3",
font=("Segoe UI",24,"bold"),
text_color=WHITE
).pack(pady=(20,15))
ctk.CTkLabel(
frame,
text="๐ฌ Communication",
font=("Segoe UI",18),
text_color=CYAN
).pack()
message = ctk.CTkLabel(
frame,
text="Waiting...",
font=("Segoe UI",24,"bold"),
text_color=WHITE
)
message.pack(pady=(30,40))
last = ctk.CTkLabel(
frame,
text="Last Update\n--:--:--",
font=("Segoe UI",18),
text_color=GREEN
)
last.pack()
return message, last
# ==========================================
# CREATE 3 SLAVE CARDS
# ==========================================
slave1_temp, slave1_hum, slave1_time = create_slave1(cards)
slave2_status, slave2_time = create_slave2(cards)
slave3_message, slave3_time = create_slave3(cards)
# ==========================================
# STATISTICS
# ==========================================
# ==========================================
# STATISTICS FRAME
# ==========================================
stats = ctk.CTkFrame(
app,
fg_color="#181818",
corner_radius=15,
height=120
)
stats.pack(fill="x", padx=20, pady=20)
sent = ctk.CTkLabel(
stats,
text="Packets Sent : 0",
font=("Segoe UI",18),
text_color=WHITE
)
sent.pack(anchor="w", padx=20, pady=5)
received = ctk.CTkLabel(
stats,
text="Packets Received : 0",
font=("Segoe UI",18),
text_color=WHITE
)
received.pack(anchor="w", padx=20)
errors = ctk.CTkLabel(
stats,
text="Errors : 0",
font=("Segoe UI",18),
text_color="red"
)
errors.pack(anchor="w", padx=20, pady=5)
def update_dashboard():
global packets_sent
global packets_received
global error_count
print("\n--------------------------------------")
if sm.connected:
# =============================
# READ SLAVE 1
# =============================
print("Polling Slave 1...")
data = sm.read_slave1()
packets_sent += 1
if data:
packets_received += 1
print("TX:", " ".join(f"{b:02X}" for b in data["request"]))
print("RX:", " ".join(f"{b:02X}" for b in data["response"]))
print(f"Temperature : {data['temperature']:.1f} ยฐC")
print(f"Humidity : {data['humidity']:.1f} %")
slave1_temp.configure(
text=f"{data['temperature']:.1f} ยฐC"
)
slave1_hum.configure(
text=f"{data['humidity']:.1f} %"
)
slave1_time.configure(
text="Last Update\n" +
datetime.now().strftime("%H:%M:%S")
)
else:
error_count += 1
print("ERROR : No response from Slave 1")
# =============================
# READ SLAVE 2
# =============================
print("\nPolling Slave 2...")
time.sleep(0.30)
data2 = sm.read_slave2()
packets_sent += 1
if data2:
packets_received += 1
if data2["touch"]:
slave2_status.configure(
text="PRESSED",
text_color=GREEN
)
else:
slave2_status.configure(
text="RELEASED",
text_color="red"
)
slave2_time.configure(
text="Last Update\n" +
datetime.now().strftime("%H:%M:%S")
)
print("TX:", " ".join(f"{b:02X}" for b in data2["request"]))
print("RX:", " ".join(f"{b:02X}" for b in data2["response"]))
print("Touch:", "PRESSED" if data2["touch"] else "RELEASED")
else:
error_count += 1
print("ERROR : No response from Slave 2")
# =============================
# READ SLAVE 3
# =============================
print("\nPolling Slave 3...")
time.sleep(0.30)
data3 = sm.read_slave3()
packets_sent += 1
if data3:
packets_received += 1
slave3_message.configure(
text=data3["message"],
text_color=GREEN
)
slave3_time.configure(
text="Last Update\n" +
datetime.now().strftime("%H:%M:%S")
)
print("TX:", " ".join(f"{b:02X}" for b in data3["request"]))
print("RX:", " ".join(f"{b:02X}" for b in data3["response"]))
print("Message:", data3["message"])
else:
error_count += 1
slave3_message.configure(
text="OFFLINE",
text_color="red"
)
print("ERROR : No response from Slave 3")
sent.configure(
text=f"Packets Sent : {packets_sent}"
)
received.configure(
text=f"Packets Received : {packets_received}"
)
errors.configure(
text=f"Errors : {error_count}"
)
app.after(2000, update_dashboard)
update_dashboard()
app.mainloop()
from crc16 import append_crc
def build_request(slave_id, register_count):
frame = [
slave_id, # Slave ID
0x03, # Function Code
0x00, # Start Address High
0x00, # Start Address Low
0x00, # Quantity High
register_count # Quantity Low
]
return bytes(append_crc(frame))
COM_PORT = "COM7"
BAUDRATE = 9600
TIMEOUT = 1
SLAVE1_ID = 1
SLAVE2_ID = 2
SLAVE3_ID = 3
def crc16(data):
crc = 0xFFFF
for byte in data:
crc ^= byte
for _ in range(8):
if crc & 0x0001:
crc >>= 1
crc ^= 0xA001
else:
crc >>= 1
return crc
def append_crc(frame):
crc = crc16(frame)
frame.append(crc & 0xFF) # CRC Low Byte
frame.append((crc >> 8) & 0xFF) # CRC High Byte
return frame
from serial_manager import SerialManager
from config import COM_PORT
import time
sm = SerialManager()
print("================================")
print(" RS485 PC MASTER STARTED")
print("================================")
if sm.connect():
print(f"\nConnected to {COM_PORT}")
while True:
data = sm.read_slave1()
if data:
print("\nSending to Slave 1...\n")
print(
"TX :",
" ".join(f"{b:02X}" for b in data["request"])
)
print(
"RX :",
" ".join(f"{b:02X}" for b in data["response"])
)
print()
print(f"Temperature : {data['temperature']} ยฐC")
print(f"Humidity : {data['humidity']} %")
print("--------------------------------")
else:
print("No response from Slave 1")
time.sleep(1)
else:
print("Connection Failed")
from serial_manager import SerialManager
import time
sm = SerialManager()
if sm.connect():
print("Connected to RS485")
while True:
data = sm.read_slave2()
if data:
print("\n========================")
print(
"TX:",
" ".join(f"{b:02X}" for b in data["request"])
)
print(
"RX:",
" ".join(f"{b:02X}" for b in data["response"])
)
if data["touch"]:
print("Touch : PRESSED")
else:
print("Touch : RELEASED")
else:
print("No Response")
time.sleep(1)
else:
print("Cannot connect.")
from serial_manager import SerialManager
import time
sm = SerialManager()
if sm.connect():
print("==========================")
print(" TEST SLAVE 3")
print("==========================")
while True:
data = sm.read_slave3()
if data:
print("Request :", data["request"].hex(" "))
print("Response:", data["response"].hex(" "))
print("Message :", data["message"])
print()
else:
print("No response from Slave 3\n")
time.sleep(1)
else:
print("Failed to connect.")
/*
RS485 DHT11 SLAVE
ESP32 + MAX485
Manual Protocol (No Modbus Library)
*/
#include
#define RXD2 16
#define TXD2 17
#define DE_RE 4
#define DHTPIN 15
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
//------------------------------------------------------
// CRC16
//------------------------------------------------------
uint16_t ModRTU_CRC(uint8_t buf[], int len)
{
uint16_t crc = 0xFFFF;
for (int pos = 0; pos < len; pos++)
{
crc ^= buf[pos];
for (int i = 0; i < 8; i++)
{
if (crc & 1)
{
crc >>= 1;
crc ^= 0xA001;
}
else
{
crc >>= 1;
}
}
}
return crc;
}
//------------------------------------------------------
void printFrame(uint8_t frame[], int len)
{
for (int i = 0; i < len; i++)
{
if (frame[i] < 0x10)
Serial.print("0");
Serial.print(frame[i], HEX);
if (i < len - 1)
Serial.print(" ");
}
Serial.println();
}
//------------------------------------------------------
void rs485Transmit()
{
digitalWrite(DE_RE, HIGH);
}
void rs485Receive()
{
digitalWrite(DE_RE, LOW);
}
//------------------------------------------------------
void setup()
{
Serial.begin(115200);
Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2);
pinMode(DE_RE, OUTPUT);
rs485Receive();
dht.begin();
Serial.println();
Serial.println("=================================");
Serial.println(" RS485 DHT11 SLAVE");
Serial.println("=================================");
Serial.println("Waiting for Master...");
}
//------------------------------------------------------
void loop()
{
if (Serial2.available() >= 8)
{
uint8_t request[8];
int len = Serial2.readBytes(request, 8);
Serial.println();
Serial.print("RX < ");
printFrame(request, len);
// ---------------- CRC Check ----------------
uint16_t crcCalc = ModRTU_CRC(request, 6);
uint16_t crcRecv = request[6] | (request[7] << 8);
if (crcCalc != crcRecv)
{
Serial.println("CRC ERROR");
return;
}
// ---------------- Read Sensor ----------------
float temperature = dht.readTemperature();
float humidity = dht.readHumidity();
if (isnan(temperature) || isnan(humidity))
{
Serial.println("DHT11 Read Failed!");
return;
}
uint16_t temp = (uint16_t)(temperature * 10);
uint16_t hum = (uint16_t)(humidity * 10);
// ---------------- Build Response ----------------
uint8_t response[9];
response[0] = 0x01; // Slave ID
response[1] = 0x03; // Function
response[2] = 0x04; // 4 data bytes
response[3] = highByte(temp);
response[4] = lowByte(temp);
response[5] = highByte(hum);
response[6] = lowByte(hum);
uint16_t crc = ModRTU_CRC(response, 7);
response[7] = lowByte(crc);
response[8] = highByte(crc);
// ---------------- Send ----------------
delay(2);
rs485Transmit();
Serial2.write(response, 9);
Serial2.flush();
rs485Receive();
// ---------------- Display ----------------
Serial.println("CRC : PASS");
}
}
/*
RS485 TTP223 SLAVE
ESP32 + MAX485
Manual Protocol (No Modbus Library)
*/
#define RXD2 16
#define TXD2 17
#define DE_RE 4
#define TOUCH_PIN 15
//------------------------------------------------------
// CRC16
//------------------------------------------------------
uint16_t ModRTU_CRC(uint8_t buf[], int len)
{
uint16_t crc = 0xFFFF;
for (int pos = 0; pos < len; pos++)
{
crc ^= buf[pos];
for (int i = 0; i < 8; i++)
{
if (crc & 1)
{
crc >>= 1;
crc ^= 0xA001;
}
else
{
crc >>= 1;
}
}
}
return crc;
}
//------------------------------------------------------
void printFrame(uint8_t frame[], int len)
{
for (int i = 0; i < len; i++)
{
if (frame[i] < 0x10)
Serial.print("0");
Serial.print(frame[i], HEX);
if (i < len - 1)
Serial.print(" ");
}
Serial.println();
}
//------------------------------------------------------
void rs485Transmit()
{
digitalWrite(DE_RE, HIGH);
}
void rs485Receive()
{
digitalWrite(DE_RE, LOW);
}
//------------------------------------------------------
void setup()
{
Serial.begin(115200);
Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2);
Serial2.setTimeout(50);
pinMode(DE_RE, OUTPUT);
pinMode(TOUCH_PIN, INPUT);
rs485Receive();
Serial.println();
Serial.println("=================================");
Serial.println(" RS485 TTP223 SLAVE");
Serial.println("=================================");
Serial.println("Waiting for Master...");
}
//------------------------------------------------------
void loop()
{
static uint8_t request[8];
if (Serial2.readBytes(request, 8) == 8)
{
Serial.println();
Serial.print("RX < ");
printFrame(request, 8);
// CRC Check
uint16_t crcCalc = ModRTU_CRC(request, 6);
uint16_t crcRecv = request[6] | (request[7] << 8);
if (crcCalc != crcRecv)
{
Serial.println("CRC ERROR");
return;
}
// Check Slave ID
if (request[0] != 0x02)
{
// Hindi para sa Slave 2
return;
}
// Read Touch Sensor
bool touch = digitalRead(TOUCH_PIN);
// Build Response
uint8_t response[7];
response[0] = 0x02; // Slave ID
response[1] = 0x03; // Function Code
response[2] = 0x02; // 2 bytes of data
response[3] = 0x00;
response[4] = touch ? 0x01 : 0x00;
uint16_t crc = ModRTU_CRC(response, 5);
response[5] = lowByte(crc);
response[6] = highByte(crc);
delay(2);
rs485Transmit();
Serial2.write(response, 7);
Serial2.flush(); // Hintaying matapos ang transmission
delayMicroseconds(500);
rs485Receive(); // Bumalik sa receive mode
Serial.print("TX > ");
printFrame(response, 7);
Serial.print("Touch Status : ");
if (touch)
Serial.println("PRESSED");
else
Serial.println("RELEASED");
Serial.println("CRC : PASS");
}
}
/*
RS485 SLAVE 3
ESP32 + MAX485
Random Message: HI / OK
*/
#define RXD2 16
#define TXD2 17
#define DE_RE 4
//------------------------------------------------------
// CRC16
//------------------------------------------------------
uint16_t ModRTU_CRC(uint8_t buf[], int len)
{
uint16_t crc = 0xFFFF;
for (int pos = 0; pos < len; pos++)
{
crc ^= buf[pos];
for (int i = 0; i < 8; i++)
{
if (crc & 1)
{
crc >>= 1;
crc ^= 0xA001;
}
else
{
crc >>= 1;
}
}
}
return crc;
}
//------------------------------------------------------
void printFrame(uint8_t frame[], int len)
{
for (int i = 0; i < len; i++)
{
if (frame[i] < 0x10)
Serial.print("0");
Serial.print(frame[i], HEX);
if (i < len - 1)
Serial.print(" ");
}
Serial.println();
}
//------------------------------------------------------
void rs485Transmit()
{
digitalWrite(DE_RE, HIGH);
}
void rs485Receive()
{
digitalWrite(DE_RE, LOW);
}
//------------------------------------------------------
void setup()
{
Serial.begin(115200);
Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2);
Serial2.setTimeout(50);
pinMode(DE_RE, OUTPUT);
// Force receive mode
digitalWrite(DE_RE, LOW);
delay(500);
// Clear garbage bytes
while (Serial2.available())
{
Serial2.read();
}
randomSeed(micros());
Serial.println();
Serial.println("===============================");
Serial.println(" RS485 SLAVE 3");
Serial.println("===============================");
Serial.println("Waiting for Master...");
Serial.println("SETUP COMPLETE");
}
//------------------------------------------------------
void loop()
{
static uint8_t request[8];
if (Serial2.readBytes(request, 8) == 8)
{
Serial.println();
Serial.print("RX < ");
printFrame(request, 8);
// CRC Check
uint16_t crcCalc = ModRTU_CRC(request, 6);
uint16_t crcRecv = request[6] | (request[7] << 8);
if (crcCalc != crcRecv)
{
Serial.println("CRC ERROR");
return;
}
// Check Slave ID
if (request[0] != 0x03)
{
return;
}
// Generate random message
char c1, c2;
if (random(0, 2) == 0)
{
c1 = 'H';
c2 = 'I';
}
else
{
c1 = 'O';
c2 = 'K';
}
// Build response
uint8_t response[7];
response[0] = 0x03;
response[1] = 0x03;
response[2] = 0x02;
response[3] = c1;
response[4] = c2;
uint16_t crc = ModRTU_CRC(response, 5);
response[5] = lowByte(crc);
response[6] = highByte(crc);
delay(2);
rs485Transmit();
Serial2.write(response, 7);
Serial2.flush();
delayMicroseconds(500);
rs485Receive();
Serial.print("TX > ");
printFrame(response, 7);
Serial.print("Message : ");
Serial.print(c1);
Serial.println(c2);
}
}
07ย Code Breakdown
ESP32 Master and Two ESP32 Slaves: Here is what each part of the code does for the RS485 network with one ESP32 acting as the Master and two ESP32 boards acting as Slave nodes. Read this section after uploading the code.
Libraries
| Library | Purpose |
|---|---|
|
ย DHT sensor library |
The DHT11 sensor measures ambient temperature and humidity. In this project, it is connected to Slave 1 to provide real-time environmental data to the ESP32.
|
Key Functions
setup()
Initializes the ESP32, configures the UART communication, MAX485 transceiver control pins, sensor pins, and starts the Serial and Serial2 interfaces for RS485 communication.
loop()
Continuously polls each slave device, receives sensor data, verifies the CRC16 checksum, and displays the received information on the Serial Monitor.
ย REQUESTSLAVE()ย
Constructs and transmits a request frame to a specified slave device through the RS485 bus.
MODRTU_CRC()ย
Calculates the CRC16 (Cyclic Redundancy Check) checksum for every transmitted and received frame to ensure data integrity during communication.
DHT.READTEMPERATURE() & DHT.READHUMIDITY()ย
Reads the temperature and humidity values from the DHT11 sensor connected to Slave 1 before transmitting the data to the Master.
ย DIGITALREAD()
Reads the current state of the TTP223 capacitive touch sensor connected to Slave 2 and returns its status when requested by the Master.
ย FRAME VALIDATION
Verifies the received slave address, function code, and CRC16 checksum before processing incoming RS485 messages.
ย SERIAL2 COMMUNICATION
Handles the transmission and reception of data frames between the Master and Slave nodes over the RS485 communication bus.
General Program Workflow
- Initialize the ESP32 boards, UART communication, MAX485 transceivers, and connected sensors.
- The Master sequentially sends request frames to each slave through the RS485 bus.
- The Master sequentially sends request frames to each slave through the RS485 bus. Each addressed slave validates the received request, acquires the requested sensor data, generates a response frame with a CRC16 checksum, and transmits the response back to the Master.
- The Master verifies the received data, displays the sensor readings on the Serial Monitor, and continuously repeats the polling process for real-time RS485 communication.
ย
PC Master and Three ESP32 Slaves: Here is what each part of the code does for the RS485 network with a PC acting as the Master and three ESP32 boards acting as Slave nodes. Read this section after uploading and running the code.
Python Source file
| python file | functions |
|---|---|
|
ย config.py |
Stores communication settings such as COM port, baud rate, timeout, and slave IDs.
|
|
crc16.py |
Calculates the CRC16 checksum for data integrity verification.
|
|
protocol.py |
Constructs the communication request frames sent by the master.
|
|
serial_manager.py |
Handles serial communication between the Python master and ESP32 slaves.
|
|
dashboard.py |
Displays the graphical user interface and monitors the RS485 network in real time.
|
|
slave1.py |
Measures temperature and humidity and sends the data to the master.
|
|
slave2.py |
Detects touch input and sends the touch status to the master.
|
|
slave3.py |
Sends "HI" or "OK" messages to verify RS485 communication.
|
Key Functions
PC Master (Python)
Main()
Initializes the Python application, opens the selected COM port through the RS485-to-USB converter, configures the serial communication parameters, and starts communication with the three ESP32 slave devices.
POLL_SLAVES()
Sequentially sends Modbus RTU request frames to Slave 1, Slave 2, and Slave 3 to collect data from each device.
SEND_REQUEST()ย
Constructs a Modbus RTU request frame containing the slave address, function code, register address, and CRC16 checksum, then transmits it through the RS485 bus.
READ_RESPONSE()ย
Receives the response frame from the addressed slave, extracts the returned data, and forwards it for validation.
ย MODRTU_CRC()ย
Calculates the CRC16 (Cyclic Redundancy Check) checksum for transmitted and received Modbus RTU frames to ensure data integrity.
ย FRAME_VALIDATION()
Verifies the received slave address, function code, data length, and CRC16 checksum before processing the received information.
DISPLAY_DATA()
Displays the received sensor values and communication status on the Python dashboard or terminal.
SERIAL_COMMUNICATION()
Handles the transmission and reception of Modbus RTU frames between the PC Master and the ESP32 slave devices through the RS485-to-USB converter.
ESP32 Slave 1 (DHT11)
SETUP()
Initializes the ESP32, UART communication, MAX485 control pins, and the DHT11 sensor.
LOOP()
Waits for Modbus RTU requests from the PC Master and responds when its slave address is requested.
DHT.READTEMPERATURE() & DHT.READHUMIDITY()ย
Reads the temperature and humidity values from the DHT11 sensor.
FRAME_VALIDATION()ย
Checks the received slave address, function code, and CRC16 checksum before processing the request.
ย MODRTU_CRC()ย
Calculates the CRC16 checksum for response frames.
SERIAL2_COMMUNICATION()
Handles RS485 communication between the slave and the PC Master.
ESP32 Slave 2 (TTP223)
SETUP()
Initializes the ESP32, UART communication, MAX485 control pins, and the TTP223 touch sensor.
LOOP()
Waits for requests from the PC Master and sends the touch sensor status when requested.
ย DIGITALREAD()ย
Reads the current state of the TTP223 capacitive touch sensor.
FRAME_VALIDATION()ย
Validates the received request frame before responding.
ย MODRTU_CRC()ย
Calculates the CRC16 checksum for transmitted response frames.
SERIAL2_COMMUNICATION()
Handles RS485 communication between the slave and the PC Master.
ESP32 Slave 3
SETUP()
Initializes the ESP32, UART communication, and MAX485 transceiver.
LOOP()
Waits for requests from the PC Master and returns the configured register values or device status.
ย FRAME_VALIDATION()ย
Verifies the received slave address, function code, and CRC16 checksum.
ย MODRTU_CRC()ย
Calculates the CRC16 checksum for transmitted response frames.
SERIAL2_COMMUNICATION()
Handles RS485 communication between the slave and the PC Master.
ย
ย
General Program Workflow
- Initialize the PC Master application, ESP32 slave devices, UART communication, MAX485 transceivers, and connected sensors.
- The PC Master sequentially sends Modbus RTU request frames to Slave 1, Slave 2, and Slave 3 through the RS485 bus.
- Each addressed slave validates the received request, acquires the requested sensor data or device status, generates a response frame with a CRC16 checksum, and transmits the response back to the PC Master.
- The PC Master verifies the received response using frame validation and CRC16 checking.
- The received data from all slave devices are displayed on the PC application.
-
The polling process continuously repeats to provide real-time monitoring and communication over the RS485 network.
08ย Testing and Calibration
After uploading the programs to the ESP32 Master, Slave 1, and Slave 2, verify each of the following tests to ensure that the RS485 communication network is functioning correctly.
RS485 Communication Test
Power on all ESP32 boards and verify that the Master successfully communicates with each slave over the RS485 bus. Confirm that requests and responses are exchanged without communication errors.
DHT11 Sensor Test
Monitor the Serial Monitor and verify that Slave 1 correctly measures and transmits real-time temperature and humidity readings when requested by the Master.
TTP223 Touch Sensor Test
Touch the TTP223 sensor connected to Slave 2 and verify that the Master correctly displays the corresponding touch status (Pressed or Released).
Multi-Drop Communication Test
Confirm that the Master polls each slave sequentially and that only the addressed slave responds, ensuring reliable communication on the shared RS485 bus.
Continuous Communication Test
Allow the system to run continuously and verify that sensor data is updated consistently without communication failures or data corruption.
ย
After setting up the PC as the Master and connecting the three ESP32 boards as Slave 1, Slave 2, and Slave 3, verify each of the following tests to ensure that the RS485 communication network is functioning correctly.
PC-to-Slave Communication Test
Power on all ESP32 slave devices and connect the PC to the RS485 network using the RS485-to-USB converter. Run the PC Master application and verify that it successfully communicates with each slave by sending requests and receiving valid responses without communication errors.
DHT11 Sensor Test (Slave 1)
Monitor the PC Master application and verify that ESP32 Slave 1 correctly measures and transmits real-time temperature and humidity readings whenever requested by the PC Master.
TTP223 Touch Sensor Test (Slave 2)
Touch the TTP223 sensor connected to ESP32 Slave 2 and verify that the PC Master correctly displays the sensor status as Pressed or Released.
Slave 3 Communication Test
Verify that the PC Master successfully communicates with ESP32 Slave 3 by polling its Modbus address and confirming that the expected data or status is received correctly.
Multi-Drop Communication Test
Confirm that the PC Master sequentially polls Slave 1, Slave 2, and Slave 3, and that only the addressed slave responds at any given time, ensuring reliable communication on the shared RS485 bus.
Continuous Communication Test
Allow the system to operate continuously and verify that the PC Master consistently receives updated data from all three ESP32 slave devices without communication failures, data corruption, or CRC errors.
09ย System Demonstration
Video Demonstration "PC Master and 3 ESP32 Slave"
This video demonstrates the complete setup of the RS485 Multi-Drop Communication Network using a PC Master, USB-to-RS485 converter, and three ESP32 Slave nodes. It shows the sequential polling of each slave and the real-time transmission of temperature, humidity, and touch sensor data over the RS485 communication bus.
Video Demonstration "ESP32 Master and two ESP32 Slave"
This video demonstrates the complete setup of an RS485 Multi-Drop Communication Network using one ESP32 Master and two ESP32 Slave nodes. It shows the master sequentially polling each slave and receiving real-time temperature, humidity, and touch sensor data through the RS485 communication bus.
10ย Conclusion
Possible Improvements and Future Enhancements
- Add more sensor nodes to expand the RS485 network and support larger monitoring systems.
- Integrate an IoT or cloud-based dashboard for remote monitoring and data logging.
- Improve the system with error detection and automated device control for more reliable and efficient operation.
11ย References
-
How to use Modbus RTU with ESP32 to read Sensor Data By Mamtaz Alamย
12ย Project Authors
- Mikyla P. Montana
-
Jonna Kayzher S. Apellido
ย






