ESP32 POE ISO Modbus TCP library and example

Started by Unimate, April 30, 2021, 09:42:39 AM

Previous topic - Next topic

Unimate

Hello,

I am looking for a Modbus TCP server library, because I would like to connect the
ESP32 POE board as a Modbus server to a Siemens PLC.
I was able to find examples for Arduino MKR WiFi 1010 via Ethernet shield (W5500)
and for Arduino NanoV3 via Ethernet shield (ENC28J60). Both work fine. But I was
not able to find an example/tutorial for the ESP32 working as a Modbus TCP server
via the hardwired Ethernet interface (LAN8710A chip).
I got the "ESP32_PoE_Ethernet_SD_Card_Arduino" example running. Even with a fixed
IP adress. But I am stuck on this Modbus TCP topic. Any help is appreciated.

Thanks

kevin

Hello,
Were you successful in finding a solution? I am looking for the same.

bart429

Hi! I'm trying exactly the same. I was able to actually connect to the Modbus server on the ESP32 POE using this:


#include <Arduino.h>
#include "ModbusServerWiFi.h"

char ssid[] = "YOUR_SSID";
char pass[] = "YOUR_PW";
// Set up a Modbus server
ModbusServerWiFi MBserver;
IPAddress lIP;                      // assigned local IP

const uint8_t MY_SERVER(1);
uint16_t memo[128];                 // Test server memory

// Worker function for serverID=1, function code 0x03 or 0x04
ModbusMessage FC03(ModbusMessage request) {
  uint16_t addr = 0;        // Start address to read
  uint16_t wrds = 0;        // Number of words to read
  ModbusMessage response;

  // Get addr and words from data array. Values are MSB-first, get() will convert to binary
  request.get(2, addr);
  request.get(4, wrds);
 
  // address valid?
  if (!addr || addr > 128) {
    // No. Return error response
    response.setError(request.getServerID(), request.getFunctionCode(), ILLEGAL_DATA_ADDRESS);
    return response;
  }

  // Modbus address is 1..n, memory address 0..n-1
  addr--;

  // Number of words valid?
  if (!wrds || (addr + wrds) > 127) {
    // No. Return error response
    response.setError(request.getServerID(), request.getFunctionCode(), ILLEGAL_DATA_ADDRESS);
    return response;
  }

  // Prepare response
  response.add(request.getServerID(), request.getFunctionCode(), (uint8_t)(wrds * 2));

  // Loop over all words to be sent
  for (uint16_t i = 0; i < wrds; i++) {
    // Add word MSB-first to response buffer
    response.add(memo[addr + i]);
  }

  // Return the data response
  return response;
}

void setup() {
// Init Serial
  Serial.begin(115200);
  while (!Serial) {}
  Serial.println("__ OK __");

  // Register the worker function with the Modbus server
  MBserver.registerWorker(MY_SERVER, READ_HOLD_REGISTER, &FC03);
 
  // Register the worker function again for another FC
  MBserver.registerWorker(MY_SERVER, READ_INPUT_REGISTER, &FC03);
 
  // Connect to WiFi
  WiFi.begin(ssid, pass);
  delay(200);
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(1000);
  }

  // print local IP address:
  lIP = WiFi.localIP();
  Serial.printf("My IP address: %u.%u.%u.%u\n", lIP[0], lIP[1], lIP[2], lIP[3]);

  // Initialize server memory with consecutive values
  for (uint16_t i = 0; i < 128; ++i) {
    memo[i] = (i * 2) << 8 | ((i * 2) + 1);
  }

  // Start the Modbus TCP server:
  // Port number 502, maximum of 4 clients in parallel, 10 seconds timeout
  MBserver.start(502, 4, 10000);
}

void loop() {
  static uint32_t statusTime = millis();
  const uint32_t statusInterval(10000);

  // We will be idling around here - all is done in subtasks :D
  if (millis() - statusTime > statusInterval) {
    Serial.printf("%d clients running.\n", MBserver.activeClients());
    statusTime = millis();
  }
  delay(100);
}

I can connect to it from my laptop (via Python pyModbusTCP.client). However, I'm not sure how to proceed as from here. Ultimately I want the ESP32 POE to react on something on the GPIO pins and send a modbus signal to another modbus Server based on that.

I did make an attempt to do it via ethernet, which connects, receives an IP address, but now I cannot reach the modbus server on the ESP32 POE.

#include <Arduino.h>
#include "ModbusServerEthernet.h"

#define ETH_CLK_MODE ETH_CLOCK_GPIO17_OUT
#define ETH_PHY_POWER 12

#include <ETH.h>

// Set up a Modbus server
ModbusServerEthernet MBserver;

// Create server
uint16_t memo[32]; // Test server memory: 32 words



// Server function to handle FC 0x03 and 0x04
ModbusMessage FC03(ModbusMessage request)
{
  Serial.println(request);
  ModbusMessage response; // The Modbus message we are going to give back
  uint16_t addr = 0;      // Start address
  uint16_t words = 0;     // # of words requested
  request.get(2, addr);   // read address from request
  request.get(4, words);  // read # of words from request

  // Address overflow?
  if ((addr + words) > 20)
  {
    // Yes - send respective error response
    response.setError(request.getServerID(), request.getFunctionCode(), ILLEGAL_DATA_ADDRESS);
  }
  // Set up response
  response.add(request.getServerID(), request.getFunctionCode(), (uint8_t)(words * 2));
  // Request for FC 0x03?
  if (request.getFunctionCode() == READ_HOLD_REGISTER)
  {
    // Yes. Complete response
    for (uint8_t i = 0; i < words; ++i)
    {
      // send increasing data values
      response.add((uint16_t)(memo[addr + i]));
    }
  }
  else
  {
    // No, this is for FC 0x04. Response is random
    for (uint8_t i = 0; i < words; ++i)
    {
      // send increasing data values
      response.add((uint16_t)random(1, 65535));
    }
  }
  // Send response back
  return response;
}


static bool eth_connected = false;

void WiFiEvent(WiFiEvent_t event)
{
  switch (event) {
    case SYSTEM_EVENT_ETH_START:
      Serial.println("ETH Started");
      //set eth hostname here
      ETH.setHostname("esp32-ethernet");
      break;
    case SYSTEM_EVENT_ETH_CONNECTED:
      Serial.println("ETH Connected");
      break;
    case SYSTEM_EVENT_ETH_GOT_IP:
      Serial.print("ETH MAC: ");
      Serial.print(ETH.macAddress());
      Serial.print(", IPv4: ");
      Serial.print(ETH.localIP());
      if (ETH.fullDuplex()) {
        Serial.print(", FULL_DUPLEX");
      }
      Serial.print(", ");
      Serial.print(ETH.linkSpeed());
      Serial.println("Mbps");
      eth_connected = true;
      break;
    case SYSTEM_EVENT_ETH_DISCONNECTED:
      Serial.println("ETH Disconnected");
      eth_connected = false;
      break;
    case SYSTEM_EVENT_ETH_STOP:
      Serial.println("ETH Stopped");
      eth_connected = false;
      break;
    default:
      break;
  }
}


void setup() {
// Init Serial
  Serial.begin(115200);
  while (!Serial) {}
  Serial.println("__ OK __");

  WiFi.onEvent(WiFiEvent);
  ETH.begin();

   // Set up test memory
  for (uint16_t i = 0; i < 32; ++i)
  {
    memo[i] = 100 + i;
  }
 
  // Now set up the server for some function codes
  MBserver.registerWorker(1, READ_HOLD_REGISTER, &FC03);      // FC=03 for serverID=1
  MBserver.registerWorker(1, READ_INPUT_REGISTER, &FC03);     // FC=04 for serverID=1
  MBserver.registerWorker(2, READ_HOLD_REGISTER, &FC03);      // FC=03 for serverID=2
 
  // Start the server
  MBserver.start(502, 2, 20000);
}

void loop() {
  static uint32_t statusTime = millis();
  const uint32_t statusInterval(10000);

  // We will be idling around here - all is done in subtasks :D
  if (millis() - statusTime > statusInterval) {
    Serial.printf("%d clients running.\n", MBserver.activeClients());
    statusTime = millis();
  }
  delay(100);
}

Maybe we can help each other here? ;)


marsmännchen

Hello together,

i wanted to ask if anybody got a sucessful working Modbus Server with the Olimex via ethernet?
I just want to send an receive some simple in- and outputs from my IoBroker Master.

Greetings
Patrick