กลับหน้าหลัก
views
Using ESP8266 to Control Modbus RTU Relay via RS485 - Step by Step
Last updated on

Using ESP8266 to Control Modbus RTU Relay via RS485 - Step by Step


Using ESP8266 to Control Modbus RTU Relay via RS485 - Step by Step

This guide walks you through using ESP8266 to control a Modbus RTU 1-Way Relay Module RS485/TTL 12V. We’ll cover wiring, Modbus command structure with Hex codes, and working Arduino code with CRC validation.

System architecture diagram showing ESP8266 + MAX485 + Modbus Relay with 12V power supply and load connection

Why Use Modbus RTU over RS485

Modbus RTU via RS485 is a widely used industrial protocol because it requires only 2 signal wires (A+ and B-) to control hundreds of relay units on a single bus, each with its own unique address.

Key advantages of this approach:

  • Saves I/O pins - Uses just 2 UART pins (TX/RX) to control dozens of relays
  • Long transmission distance - RS485 can carry data hundreds of meters without a repeater
  • High noise immunity - Differential signaling resists interference from motors, pumps, and high-voltage equipment
  • Suitable for Smart Farm / Home Automation - Easy to wire across large buildings or farms

Required Components

ComponentQty
NodeMCU ESP8266 V2 (CP2102)1
MAX485 RS485 to TTL Module1
Modbus RTU 1-Way Relay Module RS485/TTL 12V1
Power Adapter 12V 5A + DC Jack 5.5x2.5mm1 set
Power Adapter Micro USB 5V 2A1
Breadboard MB-102 830 Point1
Jumper wires M-M / M-F / F-F 20cm40 each
Micro USB cable1

Wiring Guide

1. Connect ESP8266 to MAX485 Module

Pin mapping table showing ESP8266 pins connected to MAX485 - Vin→VCC, GND→GND, D7→RO, D4→DI, D1→DE+RE
ESP8266MAX485 Module
Vin (5V)VCC
GNDGND
D7 (GPIO13)RO (RX Output)
D4 (GPIO2)DI (TX Input)
D1 (GPIO5)DE + RE (jumpered together)

Note: DE and RE must be jumpered together and connected to ESP8266 D1. MAX485 needs this pin to switch between Receive mode (LOW) and Transmit mode (HIGH).

2. Connect MAX485 to Modbus Relay

MAX485Modbus Relay
A+A+
B-B-

3. Connect Power and Load

Complete circuit diagram - 12V 5A adapter connected to Modbus Relay, NO terminal wired to load supply N, COM terminal wired to load N, load L connected directly
  • 12V DC from Adapter 5A to Modbus Relay’s + / - terminals
  • NO (Normally Open) terminal to N terminal of load power supply
  • COM terminal to N terminal of the load
  • L terminal of load power supply connected directly to load’s L terminal

Modbus RTU Command Structure

Modbus RTU uses Hex codes for communication. Every command frame includes a 16-bit CRC at the end for data integrity checking.

Turn Relay ON (Function Code 0x05 - Force Single Coil)

[ID] [0x05] [0x00] [0x00] [0xFF] [0x00] [CRC Low] [CRC High]
FieldValueMeaning
ID0x01Module address
Function Code0x05Force Single Coil
Coil Address High0x00Relay #1
Coil Address Low0x00
Force Data High0xFFCommand ON
Force Data Low0x00
CRC-Calculated from first 6 bytes

Turn Relay OFF

[ID] [0x05] [0x00] [0x00] [0x00] [0x00] [CRC Low] [CRC High]

Change Force Data from 0xFF 0x00 to 0x00 0x00 to turn OFF.

Read Relay Status (Function Code 0x01 - Read Coils)

[ID] [0x01] [0x00] [0x00] [0x00] [0x01] [CRC Low] [CRC High]
FieldValueMeaning
ID0x01Module address
Function Code0x01Read Coils
Starting Address High0x00Start from Coil 0
Starting Address Low0x00
Quantity High0x00Number of coils
Quantity Low0x01Read 1 coil

Arduino Code for ESP8266

#include <SoftwareSerial.h>

// RS485 pin definitions
#define RS485_TX_PIN    D4   // GPIO2 - Data Output (DI of MAX485)
#define RS485_RX_PIN    D7   // GPIO13 - Data Input (RO of MAX485)
#define RS485_CONTROL_PIN D1 // GPIO5 - TX/RX mode switch (DE/RE of MAX485)


// Modbus parameters
#define MODBUS_ID       0x01  // Relay module address
#define BAUD_RATE       9600 // Standard baud rate

// SoftwareSerial for RS485 interface
SoftwareSerial rs485(RS485_RX_PIN, RS485_TX_PIN);

void setup() {
  Serial.begin(9600);
  rs485.begin(BAUD_RATE);
  pinMode(RS485_CONTROL_PIN, OUTPUT);
  digitalWrite(RS485_CONTROL_PIN, LOW); // Start in receive mode
  Serial.println("ESP8266 Modbus RTU Relay Ready");
}

// Switch MAX485 between Send and Receive mode
void setRs485Mode(bool send) {
  digitalWrite(RS485_CONTROL_PIN, send ? HIGH : LOW);
  if (send) {
    delay(1); // Allow signal to stabilize
  }
}

// Modbus CRC16 calculation (CRC-16/MODBUS polynomial)
unsigned int calculateCRC(byte *data, byte length) {
  unsigned int crc = 0xFFFF;
  for (byte i = 0; i < length; i++) {
    crc ^= data[i];
    for (byte j = 0; j < 8; j++) {
      if (crc & 0x0001) {
        crc = (crc >> 1) ^ 0xA001;
      } else {
        crc >>= 1;
      }
    }
  }
  return crc;
}

// Send Modbus command and read response
bool sendModbusCommand(byte *cmd, byte cmdLength, byte *response, byte respLength) {
  // Transmit command
  setRs485Mode(true);          // Switch to transmit mode
  rs485.write(cmd, cmdLength);
  rs485.flush();               // Wait for transmission to complete
  setRs485Mode(false);         // Switch back to receive mode

  // Wait for response
  unsigned long startTime = millis();
  byte receivedBytes = 0;
  while (millis() - startTime < 500) {
    if (rs485.available()) {
      response[receivedBytes++] = rs485.read();
      if (receivedBytes >= respLength) break;
    }
  }

  return receivedBytes == respLength;
}

// Turn relay ON
void relayOn() {
  byte cmd[] = { MODBUS_ID, 0x05, 0x00, 0x00, 0xFF, 0x00 };
  unsigned int crc = calculateCRC(cmd, 6);
  cmd[6] = crc & 0xFF;          // CRC Low
  cmd[7] = (crc >> 8) & 0xFF;   // CRC High

  byte response[8];
  if (sendModbusCommand(cmd, 8, response, 8)) {
    Serial.println("Relay ON - Response: OK");
    printHex(response, 8);
  } else {
    Serial.println("Relay ON - No Response");
  }
}

// Turn relay OFF
void relayOff() {
  byte cmd[] = { MODBUS_ID, 0x05, 0x00, 0x00, 0x00, 0x00 };
  unsigned int crc = calculateCRC(cmd, 6);
  cmd[6] = crc & 0xFF;
  cmd[7] = (crc >> 8) & 0xFF;


  byte response[8];
  if (sendModbusCommand(cmd, 8, response, 8)) {
    Serial.println("Relay OFF - Response: OK");
    printHex(response, 8);
  } else {
    Serial.println("Relay OFF - No Response");
  }
}

// Read relay status
bool readRelayStatus() {
  byte cmd[] = { MODBUS_ID, 0x01, 0x00, 0x00, 0x00, 0x01 };
  unsigned int crc = calculateCRC(cmd, 6);
  cmd[6] = crc & 0xFF;
  cmd[7] = (crc >> 8) & 0xFF;

  byte response[7];
  if (sendModbusCommand(cmd, 8, response, 7)) {
    Serial.println("Read Status - Response: OK");
    printHex(response, 7);
    // Check status from byte index 3
    bool isOn = (response[3] & 0x01) != 0;
    Serial.print("Relay Status: ");
    Serial.println(isOn ? "ON" : "OFF");
    return isOn;
  } else {
    Serial.println("Read Status - No Response");
    return false;
  }
}

// Debug helper - print hex values
void printHex(byte *data, byte length) {
  Serial.print("Hex: ");
  for (byte i = 0; i < length; i++) {
    if (data[i] < 0x10) Serial.print("0");
    Serial.print(data[i], HEX);
    Serial.print(" ");
  }
  Serial.println();
}

void loop() {
  relayOn();
  delay(2000);
  relayOff();
  delay(2000);
}

Points to Adjust for Your Specific Module

  • Address (ID): If your module has a different address, change MODBUS_ID to match
  • Baud Rate: Default is usually 9600. If your module uses 4800 or 19200, update BAUD_RATE
  • Pin assignments: Different ESP8266 boards may use different pin numbers - check your board’s pinout

How to Change Module Address and Baud Rate

To operate multiple relay modules on the same bus, each must have a unique address:

  1. Connect only the module you want to reconfigure to ESP8266 (disconnect others)
  2. Send the address change command per your module’s datasheet (usually Function Code 0x06 to write a Holding Register)
  3. Verify the change by reading back the status

Reference Video

Quick Setup Summary

  1. Wire ESP8266 → MAX485 → Modbus Relay according to the pin tables above
  2. Power Modbus Relay with 12V and MAX485 with 5V from ESP8266
  3. Upload the code to ESP8266
  4. Open Serial Monitor to check operation status
  5. The relay will toggle ON/OFF every 2 seconds - you can now connect a load device

อยากทำโปรเจคแบบนี้?

รับทำโปรเจค Arduino / IoT จบงานไว ส่งงานครบ พร้อมสอน

If you need Arduino project service or urgent IoT development, see full service details on the home page

จ้างทำโปรเจคเลย

Project estimate

Want something like this? Open the estimate page.

The long form is now on a separate estimate page, so this article stays clean.

ความคิดเห็น

รีวิวจากคนใช้งานจริง

รีวิวจากลูกค้าและคนที่เคยใช้งาน

ถ้าเคยสั่งงาน เคยอ่านหน้านี้แล้วได้ประโยชน์ หรือมีข้อเสนอแนะ ฝากรีวิวไว้ได้เลย

กำลังโหลดรีวิว...