emelianov / modbus-esp8266

Most complete Modbus library for Arduino. A library that allows your Arduino board to communicate via Modbus protocol, acting as a master, slave or both. Supports network transport (Modbus TCP) and Serial line/RS-485 (Modbus RTU). Supports Modbus TCP Security for ESP8266/ESP32.
Other
534 stars 188 forks source link

Modbus TCP write multiple registers and read holding registers examples #204

Closed legaxus-mis closed 2 years ago

legaxus-mis commented 2 years ago

Hi Eemelianov, Appreciate if you could offer some examples for Modbus TCP write multiple registers and read holding registers using ModbusIP library, thanks. Hope to hear from you soon. Thanks.

emelianov commented 2 years ago

It's pretty much the same as ESP client example

uint16_t res[10];
uint8_t show = LOOP_COUNT;

void loop() {
  if (mb.isConnected(remote)) {   // Check if connection to Modbus Slave is established
    mb.readHreg(remote, REG, &res, 10);  // Initiate Read Hregs from Modbus Server
// or
    mb.writeHreg(remote, REG, &res, 10);  // Initiate Write to Modbus Server
  } else {
    mb.connect(remote);           // Try to connect if no connection
  }
  mb.task();                      // Common local Modbus task
  delay(100);                     // Pulling interval
  if (!show--) {                   // Display Slave register value one time per second (with default settings)
    Serial.println(res);
    show = LOOP_COUNT;
  }
}
legaxus-mis commented 2 years ago

It's pretty much the same as ESP client example

uint16_t res[10];
uint8_t show = LOOP_COUNT;

void loop() {
  if (mb.isConnected(remote)) {   // Check if connection to Modbus Slave is established
    mb.readHreg(remote, REG, &res, 10);  // Initiate Read Hregs from Modbus Server
// or
    mb.writeHreg(remote, REG, &res, 10);  // Initiate Write to Modbus Server
  } else {
    mb.connect(remote);           // Try to connect if no connection
  }
  mb.task();                      // Common local Modbus task
  delay(100);                     // Pulling interval
  if (!show--) {                   // Display Slave register value one time per second (with default settings)
    Serial.println(res);
    show = LOOP_COUNT;
  }
}

Hi Eemelianov, Thanks for replying. My current situation is client request to my side, and my side will be TCP server waiting for request and then response to the client. I've attached example 1 for Multiple registers and example 2 for Holding register. Appreciate if you could guide me with some examples. Thanks.

mbtcp-response2 mbtcp-query2 mbtcp-response1 mbtcp-query1

emelianov commented 2 years ago

If you need you device act as a server it's even simpler: Server -- you may add as many registers as needed. Analog read -- just replace Ireg with Hreg.

All requests (read/write/single/multiple) defined by Modbus specification are processed by the library internal code.

If you facing any issue please provide code snipped and detailed information on how to reproduce the issue.

legaxus-mis commented 2 years ago

If you need you device act as a server it's even simpler: Server -- you may add as many registers as needed. Analog read -- just replace Ireg with Hreg.

All requests (read/write/single/multiple) defined by Modbus specification are processed by the library internal code.

If you facing any issue please provide code snipped and detailed information on how to reproduce the issue.

Hi Eemelianov, Alright, I'll try it out first and update the result here, thanks.

williangomesa commented 2 years ago

Hi, first of all I'd like to thank you for this wonderfull library, i'm facing a strange issue, I do use a simple program to control an equipment, using this library as server AP mode in the ESP32, as soon as I connect the program to the server IP I receive a strange message "modbus says error: Connection is lost ! and doesn't work, Trying a more "complex " library this error doesn't happen, also, when I use a tester from the "easymodbustcpdotnet" the program works.

williangomesa commented 2 years ago

I'm using the server example with the exception that i'm using the esp32 as a acess point.

williangomesa commented 2 years ago

` /* Modbus-Arduino Example - Test Holding Register (Modbus IP ESP8266) Configure Holding Register (offset 100) with initial value 0xABCD You can get or set this holding register Original library Copyright by André Sarmento Barbosa http://github.com/andresarmento/modbus-arduino

Current version (c)2017 Alexander Emelianov (a.m.emelianov@gmail.com) https://github.com/emelianov/modbus-esp8266 */

ifdef ESP8266

include

else //ESP32

include

endif

include

// Modbus Registers Offsets const int TEST_HREG = 100;

//ModbusIP object ModbusIP mb;

void setup() { Serial.begin(115200);

WiFi.mode(WIFI_AP); WiFi.softAP("esp32", "12345678"); delay(100);

Serial.println("Set softAPConfig"); IPAddress Ip(192, 168, 1, 1); IPAddress NMask(255, 255, 255, 0); WiFi.softAPConfig(Ip, Ip, NMask);

IPAddress myIP = WiFi.softAPIP(); Serial.print("AP IP address: "); Serial.println(myIP);

mb.server(); mb.addHreg(TEST_HREG, 0xABCD); }

void loop() { //Call once inside loop() - all magic here mb.task(); delay(10); } `

legaxus-mis commented 2 years ago

If you need you device act as a server it's even simpler: Server -- you may add as many registers as needed. Analog read -- just replace Ireg with Hreg.

All requests (read/write/single/multiple) defined by Modbus specification are processed by the library internal code.

If you facing any issue please provide code snipped and detailed information on how to reproduce the issue.

Hi Eemelianov, I still confuse on some logic of communication between server and client. The example code below, how can I perform like, if receive client query message string "$01M" from Multiple registers 16 in hex as below. (0x01, 0x10, 0x27, 0x0F, 0x00, 0x03, 0x06, 0x24, 0x30, 0x31, 0x4D, 0x0D) then only server response with the SENSOR_HREG1 to client? If another message string query from client like "$02M" then server response SENSOR_HREG2 to client?

Appreciate if you could guide me on some examples, thanks.

Examples code: mb.server(); //Start Modbus IP // Add SENSOR_IREG register - Use addHreg() for analog Inputs mb.addHreg(SENSOR_HREG1); mb.addHreg(SENSOR_HREG2); mb.addHreg(SENSOR_HREG2);

ts = millis();

}

void loop() { //Call once inside loop() - all magic here mb.task();

//Read each two seconds if (millis() > ts + 2000) { ts = millis(); //Setting raw value (0-1024) mb.Hreg(SENSOR_HREG1, analogRead(A0)); } delay(10); }

emelianov commented 2 years ago

I'm not sure that understand you idea correctly. In general Modbus protocol can only read and write registers. For sure you can use multiple registers to store some text across them and use the text value on server side. As the library is focused on standard Modbus data processing for this particular task code will be slightly more complex. Something like (it's just an idea):

union {
  uint16_t reg[MESSAGE_REGS_COUNT];
  char symbol[MESSAGE_REGS_COUNT * 2 + 1];
} message;

// Callback is called for each register individually
uint16_t cbMessageReg(TRegister* reg, uint16_t val) {
  if (reg->address.address == MESSAGE_REG) // Clear message on first register write
    for (uint8_t i = 0; i < MESSAGE_REGS_COUNT + 1; i++)
      message.symbol[i] = '/0';
    message.reg[reg->address.address - MESSAGE_REG] = val; // or __swap_16(val);
  return val;
}

void setup() {
//...
  mb.addHreg(MESSAGE_REG, 0, MESSAGE_REGS_COUNT);
  mb.onSetHreg(MESSAGE_REG, cbMessageReg, MESSAGE_REGS_COUNT);
//...
}

uint32_t ts = 0;

void loop() {
  mb.task();
  if (millis() > ts + 2000) {
    ts = millis();
    if (String(reinterpret_cast<char*>(message.symbol)) == "$01M") {
      mb.Hreg(SENSOR_HREG1, analogRead(A0));
    }
  }
  delay(10);
} 
legaxus-mis commented 2 years ago

I'm not sure that understand you idea correctly. In general Modbus protocol can only read and write registers. For sure you can use multiple registers to store some text across them and use the text value on server side. As the library is focused on standard Modbus data processing for this particular task code will be slightly more complex. Something like (it's just an idea):

union {
  uint16_t reg[MESSAGE_REGS_COUNT];
  char symbol[MESSAGE_REGS_COUNT * 2 + 1];
} message;

// Callback is called for each register individually
uint16_t cbMessageReg(TRegister* reg, uint16_t val) {
  if (reg->address.address == MESSAGE_REG) // Clear message on first register write
    for (uint8_t i = 0; i < MESSAGE_REGS_COUNT + 1; i++)
      message.symbol[i] = '/0';
    message.reg[reg->address.address - MESSAGE_REG] = val; // or __swap_16(val);
  return val;
}

void setup() {
//...
  mb.addHreg(MESSAGE_REG, 0, MESSAGE_REGS_COUNT);
  mb.onSetHreg(MESSAGE_REG, cbMessageReg, MESSAGE_REGS_COUNT);
//...
}

uint32_t ts = 0;

void loop() {
  mb.task();
  if (millis() > ts + 2000) {
    ts = millis();
    if (String(reinterpret_cast<char*>(message.symbol)) == "$01M") {
      mb.Hreg(SENSOR_HREG1, analogRead(A0));
    }
  }
  delay(10);
} 

Hi Eemelianov, Thanks for the explanation. What means by (reinterpret_cast<char*>(message.symbol), what will this line perform? Thanks.

emelianov commented 2 years ago

What means by (reinterpret_cast<char*>(message.symbol), what will this line perform? Thanks.

It's close to (char): instructs compiler to interpret pinter as char not char[].

legaxus-mis commented 2 years ago

What means by (reinterpret_cast<char*>(message.symbol), what will this line perform? Thanks.

It's close to (char): instructs compiler to interpret pinter as char not char[].

Hi Eemelianov, Thanks for the explanation. From the condition as below if (String(reinterpret_cast<char*>(message.symbol)) == "$01M") { ----> mb.Hreg(SENSOR_HREG1, analogRead(A0)); <----

if after receive and compare correctly the message is "$01M" , I would like to send an "$02ACK" before sending the analogRead data. Appreciate if you could guide me on some examples, thanks.

emelianov commented 2 years ago

It's some kind of overengineering in my opinion. If you really need to implement protocol on top of Modbus it's better to use Ciols/Ists for ACK flagging in my opinion. Anyway this out of the library usage scope questions.

manikyalara0 commented 1 year ago

Sir.... my slave device communication is Communication : RS232 Transmation Mode : ASCII Baud rate : 57600 Word lenth : 7 Parity : EVEN Stop Bits : 1

Not communicating the ModbusRTU program . Please help for communication.

emelianov commented 1 year ago

The library doesn't support ASCII mode.

manikyalara0 commented 1 year ago

Dear sir,

Is there a library that supports it?

Please give me a library...

Thanks & regards

Manikyalarao k Mob:9885898897

On Sat, Oct 14, 2023, 9:29 AM Alexander Emelianov @.***> wrote:

The library doesn't support ASCII mode.

— Reply to this email directly, view it on GitHub https://github.com/emelianov/modbus-esp8266/issues/204#issuecomment-1762551060, or unsubscribe https://github.com/notifications/unsubscribe-auth/AZPIRDJKLSLHWGQ2FIFBSPLX7IE2NAVCNFSM5UEK5KE2U5DIOJSWCZC7NNSXTN2JONZXKZKDN5WW2ZLOOQ5TCNZWGI2TKMJQGYYA . You are receiving this because you commented.Message ID: @.***>