ModbusRTU – auto assign addresses for slaves

  Kiến thức lập trình

I’m working on a home automation project, where I want to use rs485(modbus) for communication between modules and I was wondering, if there is a way to automate the process of adding new devices(slaves) to the bus and addressing them automatically and also writing the new address to it’s flash memory, so when the slave restart it remembers the new ID.

I found this document, and there are some ways to achieve this, but since I’m new to this I’m not really sure how to do it exactly.

I was thinking about something like this as mentioned in the document, but I don’t understand how can I use the unique id obtained from the slave to set it’s slave id.

Liang et. al. [4] present a concept that will enable
reconfiguration of slave IDs when there are ID conflicts.
The system employed slaves with unique identification
numbers in them. In case of devices with conflicting
Modbus IDs, the master requests the conflicting slaves to
send their unique identification number to the master
within a certain pre-set interval like in Ethernet [5]. The
slaves then will attempt to send their ID back after a
random waiting period so that the IDs are received at the
master reliably. In case the IDs are not received by the
master, the same process will be re-initiated several times
until the identification numbers of all the slaves are
received. Once the identification numbers of the slaves are
received successfully by the master, the master will then
send configuration messages to set Modbus ID of each
slave referring to it by its identification number.

Has anyone done something like this before?

Currently I have just a simple code to scan the bus for slave IDs.

MASTER code:

#include <ModbusRTUMaster.h>

const byte dePin = 32; // Driver Enable pin (set to LOW for auto flow control)
const uint16_t REGISTER_ADDRESS = 0; // Register address to read from
const uint16_t NUM_REGISTERS = 1; // Number of registers to read
const byte START_SLAVE_ID = 1; // Start of the slave ID range
const byte END_SLAVE_ID = 247; // End of the slave ID range

ModbusRTUMaster modbus(Serial2, dePin); // Create Modbus master object

byte foundDevices[END_SLAVE_ID];
byte foundCount = 0;

void setup() {
  Serial.begin(115200); // Serial monitor for debugging

  // Initialize Modbus communication
  modbus.begin(38400); // Baud rate for RS-485

  // Initialize the RS-485 driver enable pin
  pinMode(dePin, OUTPUT);
  digitalWrite(dePin, LOW); // Set DE pin low for auto flow control

  delay(5000);

  scanForDevices();

}

void loop() {

}

void scanForDevices() {
  for (byte slaveID = START_SLAVE_ID; slaveID <= END_SLAVE_ID; slaveID++) {

    if (slaveID > END_SLAVE_ID) {
      Serial.println("Reached maximum scan address. Stopping scan.");
      break; // Stop scanning if the max address is reached
    }

    uint16_t holdingRegisterValue = 0; // Variable to store the register value

    // Request the value of holding register from the current slave ID
    bool success = modbus.readHoldingRegisters(slaveID, REGISTER_ADDRESS, &holdingRegisterValue, NUM_REGISTERS);

    // Check if the request was successful
    if (success) {
      Serial.print("Device found at Slave ID ");
      Serial.println(slaveID);

      foundDevices[foundCount++] = slaveID;
    } else {
      // Optionally check for timeout or exception response
      if (modbus.getTimeoutFlag()) {
        Serial.print("No device at Slave ID ");
        Serial.println(slaveID);
        modbus.clearTimeoutFlag();
      } else if (modbus.getExceptionResponse() != 0) {
        Serial.print("Error at Slave ID ");
        Serial.print(slaveID);
        Serial.print(": Exception Response ");
        Serial.println(modbus.getExceptionResponse());
        modbus.clearExceptionResponse();
      }
    }

    delay(100); // Short delay to avoid flooding the bus
  }

  printFoundDevices();
}

void printFoundDevices() {
  Serial.println("Found Devices:");
  for (byte i = 0; i < foundCount; i++) {
    Serial.print("Slave ID ");
    Serial.println(foundDevices[i]);
  }
}

SLAVE code:

#include <SoftwareSerial.h>
#include <ModbusRTU.h>
#include <EEPROM.h> // Include EEPROM library

#define REGN 0 // Register for general data
#define ID_CONFIG_REGISTER 1 // Register for configuring the slave ID
#define DEFAULT_SLAVE_ID 247 // Default slave ID
#define EEPROM_SIZE 12 // Size of EEPROM, adjust as needed
#define SAVED_SLAVE_ADDRESS 0 // Address in EEPROM to store the slave ID

#define RS485_TX_PIN 5  // GPIO5
#define RS485_RX_PIN 4  // GPIO4

SoftwareSerial swSerial(RS485_RX_PIN, RS485_TX_PIN);  // RX, TX
ModbusRTU mb;

byte currentSlaveID;

void setup() {
  swSerial.begin(38400, SWSERIAL_8N1);
  mb.begin(&swSerial);

  EEPROM.begin(EEPROM_SIZE);
  
  //currentSlaveID = EEPROM.read(SAVED_SLAVE_ADDRESS);

  // Validate the currentSlaveID, set to default if invalid
  if (currentSlaveID < 1 || currentSlaveID > 247) {
    currentSlaveID = DEFAULT_SLAVE_ID;
  }

  mb.slave(currentSlaveID);
  mb.addHreg(REGN);
  mb.Hreg(REGN, 100);
  mb.addHreg(ID_CONFIG_REGISTER); // Add register for configuring the slave ID
}

void loop() {
  mb.task();
  yield();
}

Theme wordpress giá rẻ Theme wordpress giá rẻ Thiết kế website

LEAVE A COMMENT