eModbus / eModbus

Modbus library for RTU, ASCII and TCP protocols. Primarily developed on and for ESP32 MCUs.

Home Page:https://emodbus.github.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

FC0x02 Read Discrete Inputs

orlin369 opened this issue · comments

I am trying to create a Arduino application that read from remote modbus IO device a discrete inputs, bt using FC0x02 Read Discrete Inputs.

I am attaching callback to the onResponse() method of the modbus master bus the only thing that I receive is the request.

The application is not printing response information in the call back method.

Here is the experimental code:

/*

MIT License

Copyright (c) [2023] [MADE4HOME]

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

*/

// Note: this is an example for the "EASTRON SDM630 Modbus-V2" power meter!

#pragma region Definitions

#define UPDATE_INTERVAL 1000

#define MB_BAUDRATE 9600

#define MB_SLAVE_ID 2

#define MB_REG_START 0

#define MB_REG_COUNT 8

#pragma endregion

#pragma region Headers

#include "made4home.h"

// Include the header for the ModbusClient RTU style
#include "ModbusClientRTU.h"
#include "Logging.h"

#include "FxTimer.h"

#pragma endregion

#pragma region Variables

/**
 * @brief Data ready flag.
 * 
 */
bool DataReadyFlag_g = false;

/**
 * @brief Response values.
 * 
 */
vector<uint8_t> Values_g;

/**
 * @brief Request time.
 * 
 */
uint32_t RequestTime_g;

/**
 * @brief The RS485 module has no halfduplex, so the parameter with the DE/RE pin is required!
 * 
 */
ModbusClientRTU *MB;

/** 
 * @brief Update timer instance.
 */
FxTimer *UpdateTimer_g;

#pragma endregion

#pragma region Prototypes

/**
 * @brief Define an onData handler function to receive the regular responses
 * 
 * @param response Received response message.
 * @param token Request's token.
 */
void handleData(ModbusMessage response, uint32_t token);

/**
 * @brief Define an onError handler function to receive error responses
 * 
 * @param error Error code.
 * @param token User-supplied token to identify the causing request.
 */
void handleError(Error error, uint32_t token);

#pragma endregion

void setup()
{
      for (int i = 1; i <= MB_REG_COUNT*2; i++)
      {
        Values_g.push_back(i);
      }
 
    // Init Serial monitor
    Serial.begin(115200);
    while (!Serial) {}

  	// Setup the blink timer.
	  UpdateTimer_g = new FxTimer();
	  UpdateTimer_g->setExpirationTime(UPDATE_INTERVAL);
	  UpdateTimer_g->updateLastTime();

    Made4Home.setup();
    
    Serial.println("__ OK __");
   
    // Set up Serial2 connected to Modbus RTU
    Serial2.begin(MB_BAUDRATE, SERIAL_8N1, PIN_RS485_RX, PIN_RS485_TX);
    RTUutils::prepareHardwareSerial(Serial2);

    MB = new ModbusClientRTU(PIN_RS485_EN);

    // Set up ModbusRTU client.
    // - provide onData handler function
    MB->onResponseHandler(&handleResponse);
    // - provide onData handler function
    MB->onDataHandler(&handleData);
    // - provide onError handler function
    MB->onErrorHandler(&handleError);
    // Set message timeout to 2000ms
    MB->setTimeout(2000);
    // Start ModbusRTU background task
    MB->begin(Serial2);
}

void loop()
{
    UpdateTimer_g->update();
    if(UpdateTimer_g->expired())
    {
        UpdateTimer_g->updateLastTime();
        UpdateTimer_g->clear();

        // Yes.
        DataReadyFlag_g = false;

        // Issue the request
        Error err = MB->addRequest((uint32_t)millis(), MB_SLAVE_ID, READ_COIL, MB_REG_START, MB_REG_COUNT);
        if (err!=SUCCESS)
        {
          ModbusError e(err);
          LOG_E("Error creating request: %02X - %s\n", (int)e, (const char *)e);
        }

        // Issue the request
        err = MB->addRequest((uint32_t)millis(), MB_SLAVE_ID, READ_DISCR_INPUT, MB_REG_START, MB_REG_COUNT);
        if (err!=SUCCESS)
        {
          ModbusError e(err);
          LOG_E("Error creating request: %02X - %s\n", (int)e, (const char *)e);
        }


        // Issue the request
        err = MB->addRequest((uint32_t)millis(), MB_SLAVE_ID, READ_INPUT_REGISTER, MB_REG_START, MB_REG_COUNT);
        if (err!=SUCCESS)
        {
          ModbusError e(err);
          LOG_E("Error creating request: %02X - %s\n", (int)e, (const char *)e);
        }

        // Issue the request
        err = MB->addRequest((uint32_t)millis(), MB_SLAVE_ID, READ_HOLD_REGISTER, MB_REG_START, MB_REG_COUNT);
        if (err!=SUCCESS)
        {
          ModbusError e(err);
          LOG_E("Error creating request: %02X - %s\n", (int)e, (const char *)e);
        }
    }
    else
    {
        // No, but we may have another response
        if (DataReadyFlag_g)
        {
            DataReadyFlag_g = false;

            // We do. Print out the data
            Serial.printf("Requested at %8.3fs:\n", RequestTime_g / 1000.0);
            for (uint8_t i = 0; i < MB_REG_COUNT * 2; ++i)
            {
              Serial.printf("   %04X: %i\n", i + MB_REG_START, Values_g[i]);
            }
            Serial.printf("\r\n\r\n");
        }
    }
}

#pragma region Functions

/**
 * @brief Define an onData handler function to receive the regular responses
 * 
 * @param response Received response message.
 * @param token Request's token.
 */
void handleData(ModbusMessage response, uint32_t token) 
{
  // // First value is on pos 3, after server ID, function code and length byte
  // uint16_t offs = 0;

  // // The device has values all as IEEE754 float32 in two consecutive registers
  // // Read the requested in a loop
  for (uint8_t i = 0; i < MB_REG_COUNT; ++i)
  {
    response.get(i, Values_g[i]);
  }
  
  // uint16_t addr, words;
  // response.get(2, addr);
  // response.get(4, words);
  // Serial.print("Addr: ");
  // Serial.print(addr);
  // Serial.print(" Word: ");
  // Serial.println(words);
  Serial.println("handleData");

  // Signal "data is complete"
  RequestTime_g = token;
  DataReadyFlag_g = true;
}

void handleResponse(ModbusMessage response, uint32_t token) 
{
  // // First value is on pos 3, after server ID, function code and length byte
  // uint16_t offs = 0;

  // // The device has values all as IEEE754 float32 in two consecutive registers
  // // Read the requested in a loop
  for (uint8_t i = 0; i < MB_REG_COUNT; ++i)
  {
    response.get(i, Values_g[i]);
  }
  
  // uint16_t addr, words;
  // response.get(2, addr);
  // response.get(4, words);
  // Serial.print("Addr: ");
  // Serial.print(addr);
  // Serial.print(" Word: ");
  // Serial.println(words);
  Serial.println("handleResponse");

  // Signal "data is complete"
  RequestTime_g = token;
  DataReadyFlag_g = true;
}

/**
 * @brief Define an onError handler function to receive error responses
 * 
 * @param error Error code.
 * @param token User-supplied token to identify the causing request.
 */
void handleError(Error error, uint32_t token) 
{
    // ModbusError wraps the error code and provides a readable error message for it
    ModbusError ModbusErrorL(error);
    LOG_E("Error response: %02X - %s\n", (int)ModbusErrorL, (const char *)ModbusErrorL);
}

#pragma endregion

Several things came to my mind reading the code:

  • You are providing onData/onError handlers as well as an onResponse handler. The latter will have precedence, so the former two never will be called.
  • You defined Values_g as a vector of uint8_t, so the calls to get() in the response handler will read the responses byte by byte. A Modbus register is uint16_t, so you may not get what you are expecting
  • You are firing several different requests in short succession, but the response handler does not take care of the different responses at all.

If you will provide a logging output I can try to explain what may be happening from it.

Anything new? Else I will close this issue within a week.

Well, no further help required obviously.

Hello, thanks for the fast answer, BUT unfortunately I can not response that fast, so shame on me!

So back to the topic. I did create a small man in the middle device and have the packages between the master and slave.

This is the communication in raw:

Req: {2}{2}{0}{0}{0}{8}{79}{FF}
Res: {2}{2}{1}{0}{A1}{CC}

Req: {2}{2}{0}{0}{0}{8}{79}{FF}
Res: {2}{2}{1}{0}{A1}{CC}

Req: {2}{2}{0}{0}{0}{8}{79}{FF}
Res: {2}{2}{1}{0}{A1}{CC}

AAAAND, this is the boot of the device and examples that you provide. I am worried that the response bytes are actually the request. That's why I will provide a boot time debug console messages:

ets Jul 29 2019 12:21:46

rst:0x1 (POWERON_RESET),boot:0x12 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1344
load:0x40078000,len:13964
load:0x40080400,len:3600
entry 0x400805f0
__ OK __
handleData
Requested at 1.011s: 0000: 2 0001: 2 0002: 0 0003: 0 0004: 0 0005: 8 0006: 7 0007: 8 0008: 9 0009: 10 000A: 11 000B: 12 000C: 13 000D: 14 000E: 15 000F: 16

handleData
Requested at 2.011s: 0000: 2 0001: 2 0002: 0 0003: 0 0004: 0 0005: 8 0006: 7 0007: 8 0008: 9 0009: 10 000A: 11 000B: 12 000C: 13 000D: 14 000E: 15 000F: 16

handleData
Requested at 3.011s: 0000: 2 0001: 2 0002: 0 0003: 0 0004: 0 0005: 8 0006: 7 0007: 8 0008: 9 0009: 10 000A: 11 000B: 12 000C: 13 000D: 14 000E: 15 000F: 16

AND of course the code that I use.
/*

MIT License

Copyright (c) [2023] [MADE4HOME]

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

*/

#pragma region Definitions

#define UPDATE_INTERVAL 1000

#define MB_BAUDRATE 9600

#define MB_SLAVE_ID 2

#define MB_REG_START 0

#define MB_REG_COUNT 8

#pragma endregion

#pragma region Headers

#include "made4home.h"

// Include the header for the ModbusClient RTU style
#include "ModbusClientRTU.h"
#include "Logging.h"

#include "FxTimer.h"

#pragma endregion

#pragma region Variables

/**

*/
bool DataReadyFlag_g = false;

/**

*/
vector<uint8_t> Values_g;

/**

*/
uint32_t RequestTime_g;

/**

  • @brief The RS485 module has no halfduplex, so the parameter with the DE/RE pin is required!

*/
ModbusClientRTU *ModbusClientRTU_g;

/**

  • @brief Update timer instance.
    */
    FxTimer *UpdateTimer_g;

#pragma endregion

#pragma region Prototypes

/**

  • @brief Define an onData handler function to receive the regular responses
  • @param response Received response message.
  • @param token Request's token.
    */
    void handleData(ModbusMessage response, uint32_t token);

/**

  • @brief Define an onError handler function to receive error responses
  • @param error Error code.
  • @param token User-supplied token to identify the causing request.
    */
    void handleError(Error error, uint32_t token);

#pragma endregion

void setup()
{
for (int i = 1; i <= MB_REG_COUNT*2; i++)
{
Values_g.push_back(i);
}

// Init Serial monitor
Serial.begin(115200);
while (!Serial) {}

// Setup the update timer.
  UpdateTimer_g = new FxTimer();
  UpdateTimer_g->setExpirationTime(UPDATE_INTERVAL);
  UpdateTimer_g->updateLastTime();

Made4Home.setup();

Serial.println("__ OK __");

// Set up Serial2 connected to Modbus RTU
RTUutils::prepareHardwareSerial(Serial2);
Serial2.begin(MB_BAUDRATE, SERIAL_8N1, PIN_RS485_RX, PIN_RS485_TX);

ModbusClientRTU_g = new ModbusClientRTU(PIN_RS485_EN);

// Set up ModbusRTU client.
// - provide onData handler function
// ModbusClientRTU_g->onResponseHandler(&handleResponse);
// - provide onData handler function
ModbusClientRTU_g->onDataHandler(&handleData);
// - provide onError handler function
ModbusClientRTU_g->onErrorHandler(&handleError);
// Set message timeout to 2000ms
ModbusClientRTU_g->setTimeout(2000);
// Start ModbusRTU background task
ModbusClientRTU_g->begin(Serial2);

}

void loop()
{
UpdateTimer_g->update();
if(UpdateTimer_g->expired())
{
UpdateTimer_g->updateLastTime();
UpdateTimer_g->clear();

    // Yes.
    DataReadyFlag_g = false;

    // Issue the request
    // Error ErrorL = ModbusClientRTU_g->addRequest((uint32_t)millis(), MB_SLAVE_ID, READ_COIL, MB_REG_START, MB_REG_COUNT);
    // if (ErrorL!=SUCCESS)
    // {
    //   ModbusError e(ErrorL);
    //   LOG_E("Error creating request: %02X - %s\n", (int)e, (const char *)e);
    // }

    // Issue the request
    Error ErrorL = ModbusClientRTU_g->addRequest((uint32_t)millis(), MB_SLAVE_ID, READ_DISCR_INPUT, MB_REG_START, MB_REG_COUNT);
    if (ErrorL!=SUCCESS)
    {
      ModbusError e(ErrorL);
      LOG_E("Error creating request: %02X - %s\n", (int)e, (const char *)e);
    }

    // // Issue the request
    // ErrorL = ModbusClientRTU_g->addRequest((uint32_t)millis(), MB_SLAVE_ID, READ_INPUT_REGISTER, MB_REG_START, MB_REG_COUNT);
    // if (ErrorL!=SUCCESS)
    // {
    //   ModbusError e(ErrorL);
    //   LOG_E("Error creating request: %02X - %s\n", (int)e, (const char *)e);
    // }

    // // Issue the request
    // ErrorL = ModbusClientRTU_g->addRequest((uint32_t)millis(), MB_SLAVE_ID, READ_HOLD_REGISTER, MB_REG_START, MB_REG_COUNT);
    // if (ErrorL!=SUCCESS)
    // {
    //   ModbusError e(ErrorL);
    //   LOG_E("Error creating request: %02X - %s\n", (int)e, (const char *)e);
    // }
}
else
{
    // No, but we may have another response
    if (DataReadyFlag_g)
    {
        DataReadyFlag_g = false;

        // We do. Print out the data
        Serial.printf("Requested at %8.3fs:\n", RequestTime_g / 1000.0);
        for (uint8_t i = 0; i < MB_REG_COUNT * 2; ++i)
        {
          Serial.printf("   %04X: %i\n", i + MB_REG_START, Values_g[i]);
        }
        Serial.printf("\r\n\r\n");
    }
}

}

#pragma region Functions

/**

  • @brief Define an onData handler function to receive the regular responses
  • @param response Received response message.
  • @param token Request's token.
    */
    void handleData(ModbusMessage response, uint32_t token)
    {
    // // First value is on pos 3, after server ID, function code and length byte
    // uint16_t offs = 0;

// // The device has values all as IEEE754 float32 in two consecutive registers
// // Read the requested in a loop
// for (uint8_t i = 0; i < MB_REG_COUNT; ++i)
// {
// response.get(i, Values_g[i]);
// }

for (uint8_t i = 0; i < response.size(); ++i)
{
// response.get(i, Values_g[i]);
Values_g[i] = response[i];
// Serial.printf("%02X: %02X, ", i, response[i]);
}

// Serial.println();

// uint16_t addr, words;
// response.get(2, addr);
// response.get(4, words);
// Serial.print("Addr: ");
// Serial.print(addr);
// Serial.print(" Word: ");
// Serial.println(words);
Serial.println("handleData");

// Signal "data is complete"
RequestTime_g = token;
DataReadyFlag_g = true;
}

void handleResponse(ModbusMessage response, uint32_t token)
{
// // First value is on pos 3, after server ID, function code and length byte
// uint16_t offs = 0;

// // The device has values all as IEEE754 float32 in two consecutive registers
// // Read the requested in a loop
for (uint8_t i = 0; i < response.size(); ++i)
{
// response.get(i, Values_g[i]);
Values_g[i] = response[i];
// Serial.printf("%02X: %02X, ", i, response[i]);
}

// Serial.println();

// uint16_t addr, words;
// response.get(2, addr);
// response.get(4, words);
// Serial.print("Addr: ");
// Serial.print(addr);
// Serial.print(" Word: ");
// Serial.println(words);
Serial.println("handleResponse");

// Signal "data is complete"
RequestTime_g = token;
DataReadyFlag_g = true;
}

/**

  • @brief Define an onError handler function to receive error responses
  • @param error Error code.
  • @param token User-supplied token to identify the causing request.
    */
    void handleError(Error error, uint32_t token)
    {
    // ModbusError wraps the error code and provides a readable error message for it
    ModbusError ModbusErrorL(error);
    LOG_E("Error response: %02X - %s\n", (int)ModbusErrorL, (const char *)ModbusErrorL);
    }

#pragma endregion

There still is something missing in your understanding of the whereabouts in the code, I am afraid. No offense meant of course.

The handleData output is the only thing printed from the data handler, the request logged stems from your output of it in loop(). You are in fact completely ignoring the response as is received in the handleData callback.
You are trying to read coils, BTW, which is the Modbus name for single bits. To decode these, you will need to analyze the responded bytes accordingly. Your "man in the middle" device clearly shows you are requesting 8 coils from address 0, that fit in a single response byte, so the response has a single 0 byte telling you all 8 coils requested are zero.

"I am afraid. No offense meant of course.", I am afraid you are right, but please provide me a example because I am new to this topic.

Here what I found after I gave an logic one to first input:

  • This i s raw message from man in the middle:

Req: {2}{2}{0}{0}{0}{8}{79}{FF}
Res: {2}{2}{1}{1}{60}{12}

Req: {2}{2}{0}{0}{0}{8}{79}{FF}
Res: {2}{2}{1}{1}{60}{12}

Req: {2}{2}{0}{0}{0}{8}{79}{FF}
Res: {2}{2}{1}{1}{60}{12}

  • This is the debug console messages.

ets Jul 29 2019 12:21:46

rst:0x1 (POWERON_RESET),boot:0x12 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1344
load:0x40078000,len:13964
load:0x40080400,len:3600
entry 0x400805f0
__ OK __
00: 02, 01: 02, 02: 00, 03: 00, 04: 00, 05: 08,
handleData
00: 02, 01: 02, 02: 00, 03: 00, 04: 00, 05: 08,
handleData
00: 02, 01: 02, 02: 00, 03: 00, 04: 00, 05: 08,
handleData

  • And of course the code, you were right I red in the handle function bytes:
/*

MIT License

Copyright (c) [2023] [MADE4HOME]

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

*/

#pragma region Definitions

#define UPDATE_INTERVAL 1000

#define MB_BAUDRATE 9600

#define MB_SLAVE_ID 2

#define MB_REG_START 0

#define MB_REG_COUNT 8

#pragma endregion

#pragma region Headers

#include "made4home.h"

// Include the header for the ModbusClient RTU style
#include "ModbusClientRTU.h"
#include "Logging.h"

#include "FxTimer.h"

#pragma endregion

#pragma region Variables

/**
 * @brief Data ready flag.
 * 
 */
bool DataReadyFlag_g = false;

/**
 * @brief Response values.
 * 
 */
vector<uint8_t> Values_g;

/**
 * @brief Request time.
 * 
 */
uint32_t RequestTime_g;

/**
 * @brief The RS485 module has no halfduplex, so the parameter with the DE/RE pin is required!
 * 
 */
ModbusClientRTU *ModbusClientRTU_g;

/** 
 * @brief Update timer instance.
 */
FxTimer *UpdateTimer_g;

#pragma endregion

#pragma region Prototypes

/**
 * @brief Define an onData handler function to receive the regular responses
 * 
 * @param response Received response message.
 * @param token Request's token.
 */
void handleData(ModbusMessage response, uint32_t token);

/**
 * @brief Define an onError handler function to receive error responses
 * 
 * @param error Error code.
 * @param token User-supplied token to identify the causing request.
 */
void handleError(Error error, uint32_t token);

#pragma endregion

void setup()
{
      for (int i = 1; i <= MB_REG_COUNT*2; i++)
      {
        Values_g.push_back(i);
      }
 
    // Init Serial monitor
    Serial.begin(115200);
    while (!Serial) {}

  	// Setup the update timer.
	  UpdateTimer_g = new FxTimer();
	  UpdateTimer_g->setExpirationTime(UPDATE_INTERVAL);
	  UpdateTimer_g->updateLastTime();

    Made4Home.setup();
    
    Serial.println("__ OK __");
   
    // Set up Serial2 connected to Modbus RTU
    RTUutils::prepareHardwareSerial(Serial2);
    Serial2.begin(MB_BAUDRATE, SERIAL_8N1, PIN_RS485_RX, PIN_RS485_TX);

    ModbusClientRTU_g = new ModbusClientRTU(PIN_RS485_EN);

    // Set up ModbusRTU client.
    // - provide onData handler function
    // ModbusClientRTU_g->onResponseHandler(&handleResponse);
    // - provide onData handler function
    ModbusClientRTU_g->onDataHandler(&handleData);
    // - provide onError handler function
    ModbusClientRTU_g->onErrorHandler(&handleError);
    // Set message timeout to 2000ms
    ModbusClientRTU_g->setTimeout(2000);
    // Start ModbusRTU background task
    ModbusClientRTU_g->begin(Serial2);
}

void loop()
{
    UpdateTimer_g->update();
    if(UpdateTimer_g->expired())
    {
        UpdateTimer_g->updateLastTime();
        UpdateTimer_g->clear();

        // Yes.
        DataReadyFlag_g = false;

        // Issue the request
        // Error ErrorL = ModbusClientRTU_g->addRequest((uint32_t)millis(), MB_SLAVE_ID, READ_COIL, MB_REG_START, MB_REG_COUNT);
        // if (ErrorL!=SUCCESS)
        // {
        //   ModbusError e(ErrorL);
        //   LOG_E("Error creating request: %02X - %s\n", (int)e, (const char *)e);
        // }

        // Issue the request
        Error ErrorL = ModbusClientRTU_g->addRequest((uint32_t)millis(), MB_SLAVE_ID, READ_DISCR_INPUT, MB_REG_START, MB_REG_COUNT);
        if (ErrorL!=SUCCESS)
        {
          ModbusError e(ErrorL);
          LOG_E("Error creating request: %02X - %s\n", (int)e, (const char *)e);
        }

        // // Issue the request
        // ErrorL = ModbusClientRTU_g->addRequest((uint32_t)millis(), MB_SLAVE_ID, READ_INPUT_REGISTER, MB_REG_START, MB_REG_COUNT);
        // if (ErrorL!=SUCCESS)
        // {
        //   ModbusError e(ErrorL);
        //   LOG_E("Error creating request: %02X - %s\n", (int)e, (const char *)e);
        // }

        // // Issue the request
        // ErrorL = ModbusClientRTU_g->addRequest((uint32_t)millis(), MB_SLAVE_ID, READ_HOLD_REGISTER, MB_REG_START, MB_REG_COUNT);
        // if (ErrorL!=SUCCESS)
        // {
        //   ModbusError e(ErrorL);
        //   LOG_E("Error creating request: %02X - %s\n", (int)e, (const char *)e);
        // }
    }
    else
    {
        // No, but we may have another response
        if (DataReadyFlag_g)
        {
            DataReadyFlag_g = false;

            // // We do. Print out the data
            // Serial.printf("Requested at %8.3fs:\n", RequestTime_g / 1000.0);
            // for (uint8_t i = 0; i < MB_REG_COUNT * 2; ++i)
            // {
            //   Serial.printf("   %04X: %i\n", i + MB_REG_START, Values_g[i]);
            // }
            // Serial.printf("\r\n\r\n");
        }
    }
}

#pragma region Functions

/**
 * @brief Define an onData handler function to receive the regular responses
 * 
 * @param response Received response message.
 * @param token Request's token.
 */
void handleData(ModbusMessage response, uint32_t token) 
{
  // // First value is on pos 3, after server ID, function code and length byte
  // uint16_t offs = 0;

  // // The device has values all as IEEE754 float32 in two consecutive registers
  // // Read the requested in a loop
  // for (uint8_t i = 0; i < MB_REG_COUNT; ++i)
  // {
  //   response.get(i, Values_g[i]);
  // }

  for (uint8_t i = 0; i < response.size(); ++i)
  {
    // response.get(i, Values_g[i]);
    // Values_g[i] = response[i];
    Serial.printf("%02X: %02X, ", i, response[i]);
  }

  Serial.println();


  // uint16_t addr, words;
  // response.get(2, addr);
  // response.get(4, words);
  // Serial.print("Addr: ");
  // Serial.print(addr);
  // Serial.print(" Word: ");
  // Serial.println(words);
  Serial.println("handleData");

  // Signal "data is complete"
  RequestTime_g = token;
  DataReadyFlag_g = true;
}

void handleResponse(ModbusMessage response, uint32_t token) 
{
  // // First value is on pos 3, after server ID, function code and length byte
  // uint16_t offs = 0;

  // // The device has values all as IEEE754 float32 in two consecutive registers
  // // Read the requested in a loop
  for (uint8_t i = 0; i < response.size(); ++i)
  {
    // response.get(i, Values_g[i]);
    // Values_g[i] = response[i];
    Serial.printf("%02X: %02X, ", i, response[i]);
  }

  Serial.println();

  
  // uint16_t addr, words;
  // response.get(2, addr);
  // response.get(4, words);
  // Serial.print("Addr: ");
  // Serial.print(addr);
  // Serial.print(" Word: ");
  // Serial.println(words);
  Serial.println("handleResponse");

  // Signal "data is complete"
  RequestTime_g = token;
  DataReadyFlag_g = true;
}

/**
 * @brief Define an onError handler function to receive error responses
 * 
 * @param error Error code.
 * @param token User-supplied token to identify the causing request.
 */
void handleError(Error error, uint32_t token) 
{
    // ModbusError wraps the error code and provides a readable error message for it
    ModbusError ModbusErrorL(error);
    LOG_E("Error response: %02X - %s\n", (int)ModbusErrorL, (const char *)ModbusErrorL);
}

#pragma endregion
  • Conclusion
    i am again saying that I am giving the first input logic one.
    What I am afraid that the response debug messages are the same as previous time.

Kindly Regards

Awg, man, your code is hard to read... 😉

Do me a favor and modify Logging.h at the very start to have LOG_LEVEL_VERBOSE as default logging level, compile again, run it and post the logging output here.

I did change the log as you mentioned LOG_LEVEL_VERBOSE and this is the result:

ets Jul 29 2019 12:21:46

rst:0x1 (POWERON_RESET),boot:0x12 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1344
load:0x40078000,len:13964
load:0x40080400,len:3600
entry 0x400805f0
__ OK __
[D] 21| ModbusClientRTU.cpp [ 111] setTimeout: Timeout set to 2000
[V] 21| RTUutils.cpp [ 112] calculateInterval: Calc interval(9600)=3645
[D] 32| ModbusClientRTU.cpp [ 86] doBegin: Client task 1073428052 started. Interval=3645
[V] 1011| ModbusMessage.cpp [ 477] checkData: Check data #3
[D] 1011| ModbusClientRTU.cpp [ 147] addRequestM: request for 02/02
[D] 1011| ModbusClientRTU.cpp [ 230] addToQueue: RC=01
[D] 1011| ModbusClientRTU.cpp [ 248] handleConnection: Pulled request from queue
[D] 1021| ModbusClientRTU.cpp [ 158] addRequestM: RC=00
[D] Sent packet: @3FFB37EC/6:
| 0000: 02 02 00 00 00 08 |...... |
[D] 1040| ModbusClientRTU.cpp [ 253] handleConnection: Request sent.
[V] 1055| RTUutils.cpp [ 262] receive: C/3656us without data after 8
[V] 1055| RTUutils.cpp [ 272] receive: C/[V] Raw buffer received: @3FFB3834/8:
| 0000: 02 02 00 00 00 08 79 FF |......y. |
[D] 1075| RTUutils.cpp [ 437] receive: C/[D] Received packet: @3FFB37BC/6:
| 0000: 02 02 00 00 00 08 |...... |
[D] 1086| ModbusClientRTU.cpp [ 268] handleConnection: Data response (6 bytes) received.
[V] Data: @3FFB37BC/6:
| 0000: 02 02 00 00 00 08 |...... |
[D] 1096| ModbusClientRTU.cpp [ 289] handleConnection: Response generated.
[V] Response packet: @3FFB37BC/6:
| 0000: 02 02 00 00 00 08 |...... |
00: 02, 01: 02, 02: 00, 03: 00, 04: 00, 05: 08,
handleData
[V] 2011| ModbusMessage.cpp [ 477] checkData: Check data #3
[D] 2011| ModbusClientRTU.cpp [ 147] addRequestM: request for 02/02
[D] 2021| ModbusClientRTU.cpp [ 230] addToQueue: RC=01
[D] 2021| ModbusClientRTU.cpp [ 158] addRequestM: RC=00
[D] 2021| ModbusClientRTU.cpp [ 248] handleConnection: Pulled request from queue
[D] Sent packet: @3FFB37D4/6:
| 0000: 02 02 00 00 00 08 |...... |
[D] 2041| ModbusClientRTU.cpp [ 253] handleConnection: Request sent.
[V] 2064| RTUutils.cpp [ 262] receive: C/3663us without data after 14
[V] 2064| RTUutils.cpp [ 272] receive: C/[V] Raw buffer received: @3FFB381C/14:
| 0000: 02 02 00 00 00 08 79 FF 02 02 01 01 60 0C |......y.....`. |
[D] 2074| RTUutils.cpp [ 437] receive: C/[D] Received packet: @3FFB8308/1:
| 0000: E2 |. |
[D] 2095| ModbusClientRTU.cpp [ 268] handleConnection: Error response (1 bytes) received.
[V] Data: @3FFB8308/1:
| 0000: E2 |. |
[D] 2106| ModbusClientRTU.cpp [ 289] handleConnection: Response generated.
[V] Response packet: @3FFB8308/3:
| 0000: 02 82 E2 |... |
[1;33m[E] 2126| modbus_master.ino [ 291] handleError: Error response: E2 - CRC check error
[0m

The first response received is in fact the request you sent. The next response looks like a collision of the next request with a response on the bus.

Can you check the wiring and have a close look at the response times and configuration of the servers on the bus? The collision would be explainable by a slow server not maintaining the RTU protocol. A picture of your connections could be helpful as well.

I did try to remove all other devices from the bus (RS485). This is the new messages:

ets Jul 29 2019 12:21:46

rst:0x1 (POWERON_RESET),boot:0x12 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1344
load:0x40078000,len:13964
load:0x40080400,len:3600
entry 0x400805f0
__ OK __
[D] 21| ModbusClientRTU.cpp [ 111] setTimeout: Timeout set to 2000
[V] 21| RTUutils.cpp [ 112] calculateInterval: Calc interval(9600)=3645
[D] 32| ModbusClientRTU.cpp [ 86] doBegin: Client task 1073428052 started. Interval=3645
[V] 1011| ModbusMessage.cpp [ 477] checkData: Check data #3
[D] 1011| ModbusClientRTU.cpp [ 147] addRequestM: request for 02/02
[D] 1011| ModbusClientRTU.cpp [ 230] addToQueue: RC=01
[D] 1011| ModbusClientRTU.cpp [ 248] handleConnection: Pulled request from queue
[D] 1021| ModbusClientRTU.cpp [ 158] addRequestM: RC=00
[D] Sent packet: @3FFB37EC/6:
| 0000: 02 02 00 00 00 08 |...... |
[D] 1040| ModbusClientRTU.cpp [ 253] handleConnection: Request sent.
[V] 1059| RTUutils.cpp [ 262] receive: C/3647us without data after 14
[V] 1059| RTUutils.cpp [ 272] receive: C/[V] Raw buffer received: @3FFB3834/14:
| 0000: 02 02 00 00 00 08 79 FF 02 02 01 01 60 0C |......y...... | [D] 1069| RTUutils.cpp [ 437] receive: C/[D] Received packet: @3FFB8308/1: | 0000: E2 |. | [D] 1090| ModbusClientRTU.cpp [ 268] handleConnection: Error response (1 bytes) received. [V] Data: @3FFB8308/1: | 0000: E2 |. | [D] 1101| ModbusClientRTU.cpp [ 289] handleConnection: Response generated. [V] Response packet: @3FFB8308/3: | 0000: 02 82 E2 |... | [1;33m[E] 1121| modbus_master.ino [ 291] handleError: Error response: E2 - CRC check error [0m[V] 2011| ModbusMessage.cpp [ 477] checkData: Check data #3 [D] 2011| ModbusClientRTU.cpp [ 147] addRequestM: request for 02/02 [D] 2021| ModbusClientRTU.cpp [ 230] addToQueue: RC=01 [D] 2021| ModbusClientRTU.cpp [ 158] addRequestM: RC=00 [D] 2021| ModbusClientRTU.cpp [ 248] handleConnection: Pulled request from queue [D] Sent packet: @3FFB37D4/6: | 0000: 02 02 00 00 00 08 |...... | [D] 2040| ModbusClientRTU.cpp [ 253] handleConnection: Request sent. [V] 2059| RTUutils.cpp [ 262] receive: C/3648us without data after 14 [V] 2059| RTUutils.cpp [ 272] receive: C/[V] Raw buffer received: @3FFB381C/14: | 0000: 02 02 00 00 00 08 79 FF 02 02 01 01 60 0C |......y...... |
[D] 2070| RTUutils.cpp [ 437] receive: C/[D] Received packet: @3FFB8308/1:
| 0000: E2 |. |
[D] 2090| ModbusClientRTU.cpp [ 268] handleConnection: Error response (1 bytes) received.
[V] Data: @3FFB8308/1:
| 0000: E2 |. |
[D] 2101| ModbusClientRTU.cpp [ 289] handleConnection: Response generated.
[V] Response packet: @3FFB8308/3:
| 0000: 02 82 E2 |... |
[1;33m[E] 2121| modbus_master.ino [ 291] handleError: Error response: E2 - CRC check error
[0m[V] 3011| ModbusMessage.cpp [ 477] checkData: Check data #3
[D] 3011| ModbusClientRTU.cpp [ 147] addRequestM: request for 02/02
[D] 3021| ModbusClientRTU.cpp [ 230] addToQueue: RC=01
[D] 3021| ModbusClientRTU.cpp [ 158] addRequestM: RC=00
[D] 3021| ModbusClientRTU.cpp [ 248] handleConnection: Pulled request from queue
[D] Sent packet: @3FFB37D4/6:
| 0000: 02 02 00 00 00 08 ets Jul 29 2019 12:21:46

rst:0x1 (POWERON_RESET),boot:0x12 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1344
load:0x40078000,len:13964
load:0x40080400,len:3600
entry 0x400805f0
__ OK __
[D] 21| ModbusClientRTU.cpp [ 111] setTimeout: Timeout set to 2000
[V] 21| RTUutils.cpp [ 112] calculateInterval: Calc interval(9600)=3645
[D] 32| ModbusClientRTU.cpp [ 86] doBegin: Client task 1073428052 started. Interval=3645

Same again. The server seems to first echo the request, then responds without maintaining the required quiet time of 3500 microseconds. Another explanation would be a misplaced connection between the ESP's RX and TX lines...

This is again the log, I did suceed the message transport.

This is the log:

The oldest data was removed. Continue...
11| ModbusMessage.cpp [ 477] checkData: Check data #3
[D] 2011| ModbusClientRTU.cpp [ 147] addRequestM: request for 02/02
[D] 2021| ModbusClientRTU.cpp [ 230] addToQueue: RC=01
[D] 2021| ModbusClientRTU.cpp [ 158] addRequestM: RC=00
[D] 2021| ModbusClientRTU.cpp [ 248] handleConnection: Pulled request from queue
[D] Sent packet: @3FFB37D4/6:
| 0000: 02 02 00 00 00 08 |...... |
[D] 2040| ModbusClientRTU.cpp [ 253] handleConnection: Request sent.
[V] 2060| RTUutils.cpp [ 262] receive: C/3670us without data after 14
[V] 2060| RTUutils.cpp [ 272] receive: C/[V] Raw buffer received: @3FFB381C/14:
| 0000: 02 02 00 00 00 08 79 FF 02 02 01 01 60 0C |......y...... | [D] 2071| RTUutils.cpp [ 437] receive: C/[D] Received packet: @3FFB8308/1: | 0000: E2 |. | [D] 2091| ModbusClientRTU.cpp [ 268] handleConnection: Error response (1 bytes) received. [V] Data: @3FFB8308/1: | 0000: E2 |. | [D] 2102| ModbusClientRTU.cpp [ 289] handleConnection: Response generated. [V] Response packet: @3FFB8308/3: | 0000: 02 82 E2 |... | [1;33m[E] 2123| modbus_master.ino [ 291] handleError: Error response: E2 - CRC check error [0m[V] 3011| ModbusMessage.cpp [ 477] checkData: Check data #3 [D] 3011| ModbusClientRTU.cpp [ 147] addRequestM: request for 02/02 [D] 3021| ModbusClientRTU.cpp [ 230] addToQueue: RC=01 [D] 3021| ModbusClientRTU.cpp [ 158] addRequestM: RC=00 [D] 3021| ModbusClientRTU.cpp [ 248] handleConnection: Pulled request from queue [D] Sent packet: @3FFB37D4/6: | 0000: 02 02 00 00 00 08 |...... | [D] 3040| ModbusClientRTU.cpp [ 253] handleConnection: Request sent. [V] 3060| RTUutils.cpp [ 262] receive: C/3647us without data after 14 [V] 3060| RTUutils.cpp [ 272] receive: C/[V] Raw buffer received: @3FFB381C/14: | 0000: 02 02 00 00 00 08 79 FF 02 02 01 01 60 0C |......y...... |
[D] 3071| RTUutils.cpp [ 437] receive: C/[D] Received packet: @3FFB8308/1:
| 0000: E2 |. |
[D] 3091| ModbusClientRTU.cpp [ 268] handleConnection: Error response (1 bytes) received.
[V] Data: @3FFB8308/1:
| 0000: E2 |. |
[D] 3102| ModbusClientRTU.cpp [ 289] handleConnection: Response generated.
[V] Response packet: @3FFB8308/3:
| 0000: 02 82 E2 |... |
[1;33m[E] 3123| modbus_master.ino [ 291] handleError: Error response: E2 - CRC check error
[0m[V] 4011| ModbusMessage.cpp [ 477] checkData: Check data #3
[D] 4011| ModbusClientRTU.cpp [ 147] addRequestM: request for 02/02
[D] 4021| ModbusClientRTU.cpp [ 230] addToQueue: RC=01
[D] 4021| ModbusClientRTU.cpp [ 158] addRequestM: RC=00
[D] 4021| ModbusClientRTU.cpp [ 248] handleConnection: Pulled request from queue
[D] Sent packet: @3FFB37D4/6:
| 0000: 02 02 00 00 00 08 |...... |
[D] 4040| ModbusClientRTU.cpp [ 253] handleConnection: Request sent.
[V] 4060| RTUutils.cpp [ 262] receive: C/3687us without data after 14
[V] 4061| RTUutils.cpp [ 272] receive: C/[V] Raw buffer received: @3FFB381C/14:
| 0000: 02 02 00 00 00 08 79 FF 02 02 01 01 60 0C |......y.....`. |
[D] 4071| RTUutils.cpp [ 437] receive: C/[D] Received packet: @3FFB8308/1:
| 0000: E2 |. |
[D] 4092| ModbusClientRTU.cpp [ 268] handleConnection: Error response (1 bytes) received.
[V] Data: @3FFB8308/1:
| 0000: E2 |. |
[D] 4102| ModbusClientRTU.cpp [ 289] handleConnection: Response generated.
[V] Response packet: @3FFB8308/3:
| 0000: 02 82 E2 |... |
[1;33m[E] 4123| modbus_master.ino [ 291] handleError: Error response: E2 - CRC check error
[0m
Serial port COM11 closed

And this is the communication:

Req: {2}{2}{0}{0}{0}{8}{79}{FF}
Res: {2}{2}{1}{1}{60}{12}

Req: {2}{2}{0}{0}{0}{8}{79}{FF}
Res: {2}{2}{1}{1}{60}{12}

Req: {2}{2}{0}{0}{0}{8}{79}{FF}
Res: {2}{2}{1}{1}{60}{12}

Req: {2}{2}{0}{0}{0}{8}{79}{FF}
Res: {2}{2}{1}{1}{60}{12}

Again: did you check if there is an unwanted connection between the ESP's RX and TX pins? That would explain what we see - the request immediately read back again.

I did check all the wearing. The length is so short that the wires can not play role as a antenna or internal interference.

To verify that disconnect the RS485 wires and let run your sketch. If we see the requests echoed back, there is something wrong on the ESP side. If all you will get are E0 timeout errors, the problem must lie on the RS485 or server's side.

The oldest data was removed. Continue...
|. |
[D] 4102| ModbusClientRTU.cpp [ 289] handleConnection: Response generated.
[V] Response packet: @3FFB8308/3:
| 0000: 02 82 E2 |... |
[1;33m[E] 4123| modbus_master.ino [ 291] handleError: Error response: E2 - CRC check error
[0mets Jul 29 2019 12:21:46

rst:0x1 (POWERON_RESET),boot:0x12 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1344
load:0x40078000,len:13964
load:0x40080400,len:3600
entry 0x400805f0
__ OK __
[D] 21| ModbusClientRTU.cpp [ 111] setTimeout: Timeout set to 2000
[V] 21| RTUutils.cpp [ 112] calculateInterval: Calc interval(9600)=3645
[D] 32| ModbusClientRTU.cpp [ 86] doBegin: Client task 1073428052 started. Interval=3645
[V] 1011| ModbusMessage.cpp [ 477] checkData: Check data #3
[D] 1011| ModbusClientRTU.cpp [ 147] addRequestM: request for 02/02
[D] 1011| ModbusClientRTU.cpp [ 230] addToQueue: RC=01
[D] 1011| ModbusClientRTU.cpp [ 248] handleConnection: Pulled request from queue
[D] 1021| ModbusClientRTU.cpp [ 158] addRequestM: RC=00
[D] Sent packet: @3FFB37EC/6:
| 0000: 02 02 00 00 00 08 |...... |
[D] 1040| ModbusClientRTU.cpp [ 253] handleConnection: Request sent.
[V] 1058| RTUutils.cpp [ 262] receive: C/3649us without data after 14
[V] 1058| RTUutils.cpp [ 272] receive: C/[V] Raw buffer received: @3FFB3834/14:
| 0000: 02 02 00 00 00 08 79 FF 02 02 01 01 60 0C |......y...... | [D] 1069| RTUutils.cpp [ 437] receive: C/[D] Received packet: @3FFB8308/1: | 0000: E2 |. | [D] 1089| ModbusClientRTU.cpp [ 268] handleConnection: Error response (1 bytes) received. [V] Data: @3FFB8308/1: | 0000: E2 |. | [D] 1100| ModbusClientRTU.cpp [ 289] handleConnection: Response generated. [V] Response packet: @3FFB8308/3: | 0000: 02 82 E2 |... | [1;33m[E] 1120| modbus_master.ino [ 291] handleError: Error response: E2 - CRC check error [0m[V] 2011| ModbusMessage.cpp [ 477] checkData: Check data #3 [D] 2011| ModbusClientRTU.cpp [ 147] addRequestM: request for 02/02 [D] 2021| ModbusClientRTU.cpp [ 230] addToQueue: RC=01 [D] 2021| ModbusClientRTU.cpp [ 158] addRequestM: RC=00 [D] 2021| ModbusClientRTU.cpp [ 248] handleConnection: Pulled request from queue [D] Sent packet: @3FFB37D4/6: | 0000: 02 02 00 00 00 08 |...... | [D] 2040| ModbusClientRTU.cpp [ 253] handleConnection: Request sent. [V] 2058| RTUutils.cpp [ 262] receive: C/3654us without data after 14 [V] 2058| RTUutils.cpp [ 272] receive: C/[V] Raw buffer received: @3FFB381C/14: | 0000: 02 02 00 00 00 08 79 FF 02 02 01 01 60 0C |......y...... |
[D] 2069| RTUutils.cpp [ 437] receive: C/[D] Received packet: @3FFB8308/1:
| 0000: E2 |. |
[D] 2089| ModbusClientRTU.cpp [ 268] handleConnection: Error response (1 bytes) received.
[V] Data: @3FFB8308/1:
| 0000: E2 |. |
[D] 2100| ModbusClientRTU.cpp [ 289] handleConnection: Response generated.
[V] Response packet: @3FFB8308/3:
| 0000: 02 82 E2 |... |
[1;33m[E] 2121| modbus_master.ino [ 291] handleError: Error response: E2 - CRC check error
[0m

I think you are right. There is problem with the slave device. Will try another. May I keep the chance to communicate with you for further support?

Of course we will continue trying to kill the bug 😉

The log you posted some minutes ago still has the E2 CRC errors, so you did not cut the RS485 connection yet. To sort things out please do as advised yesterday, disconnect the A+/B- wires and do another run. I really would like to see the resulting log...

No, I did try with another MODBUS library for arduino, bu still the same thing popped up. So will just try with another modbus slave device. Beside with python library on windows 10 are working just fine, with all OPCodes that I want to try. We cant't just kill the bug because it is not part of my or your firmware. It is inside the slave firmware.

No, I did try with another MODBUS library for arduino, bu still the same thing popped up. So will just try with another modbus slave device. Beside with python library on windows 10 are working just fine, with all OPCodes that I want to try. We cant't just kill the bug because it is not part of my or your firmware. It is inside the slave firmware.

Hey I have break trough. I did try with modbus RTU bu for python pymodbus:

#!/usr/bin/env python3
# -*- coding: utf8 -*-

import time
import logging

# --------------------------------------------------------------------------- #
# import the modbus client and the framers
# --------------------------------------------------------------------------- #
# from pymodbus.client.sync import ModbusTcpClient as ModbusClient
# from pymodbus.transaction import ModbusSocketFramer as ModbusFramer
from pymodbus.client.serial import ModbusSerialClient


from pymodbus.transaction import ModbusRtuFramer
# from pymodbus.transaction import ModbusBinaryFramer as ModbusFramer
# from pymodbus.transaction import ModbusAsciiFramer as ModbusFramer

# --------------------------------------------------------------------------- #
# configure the client logging
# --------------------------------------------------------------------------- #
log = logging.getLogger()
log.setLevel(logging.DEBUG)

def handle_discrete_input(client, slave):
    """Read discrete inputs."""
    log.info("### Reading discrete input, Read address:0-7")
    rr = client.read_discrete_inputs(0, 8, slave=slave)
    if not rr.isError():
        print(rr.bits)

    else:
        print(rr)

def main():

    unit = 2
    port = "COM13"
    # ----------------------------------------------------------------------- #
    # Initialize the client
    # ----------------------------------------------------------------------- #

    with ModbusSerialClient(
            port,
            method="rtu",
            framer=ModbusRtuFramer,
            timeout=1,
            # retries=3,
            # retry_on_empty=False,
            # close_comm_on_error=False,.
            # strict=True,
            baudrate=9600,
            bytesize=8,
            parity="N",
            stopbits=1,
            # handle_local_echo=False,
        ) as client:

        # ----------------------------------------------------------------------- #
        # perform your requests
        # ----------------------------------------------------------------------- #
        handle_discrete_input(client, unit)

        # ----------------------------------------------------------------------- #
        # close the client
        # ---------------------------------------------------------------------- #
        client.close()

if __name__ == "__main__":
    main()

The result from the code:

[True, False, False, False, False, False, False, False]

Like I said before I give high level to first input.

This is on your PC, right? So it does show the server is working in principle, but does not help much in regards to finding the problem on the ESP32.

I still would suggest you to do the simple disconnected test as described above to find if it is in the wiring or the software...

There is no man in the middle device, only p2p as you said, just change the master.

But COM13 in the Python code clearly says "PC", so no ESP32 involved?

Yes ESP is not involved, the data is received and parsed with no problems. This is what puzzling me. Why ESP32 does not accept it, and PC accept it.

For the fourth time: please do as advised, so we will know if it is the wiring or the software!

  1. with RS485
ets Jul 29 2019 12:21:46

rst:0x1 (POWERON_RESET),boot:0x12 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1344
load:0x40078000,len:13964
load:0x40080400,len:3600
entry 0x400805f0
__ OK __
[D] 25| ModbusClientRTU.cpp  [ 111] setTimeout: Timeout set to 2000
[V] 25| RTUutils.cpp         [ 112] calculateInterval: Calc interval(9600)=3645
[D] 36| ModbusClientRTU.cpp  [  86] doBegin: Client task 1073428052 started. Interval=3645
[V] 1015| ModbusMessage.cpp    [ 477] checkData: Check data #3
[D] 1015| ModbusClientRTU.cpp  [ 147] addRequestM: request for 02/02
[D] 1015| ModbusClientRTU.cpp  [ 230] addToQueue: RC=01
[D] 1015| ModbusClientRTU.cpp  [ 248] handleConnection: Pulled request from queue
[D] 1025| ModbusClientRTU.cpp  [ 158] addRequestM: RC=00
[D] Sent packet: @3FFB37EC/6:
  | 0000: 02 02 00 00 00 08                                 |......          |
[D] 1044| ModbusClientRTU.cpp  [ 253] handleConnection: Request sent.
[V] 1059| RTUutils.cpp         [ 262] receive: C/3664us without data after 14
[V] 1059| RTUutils.cpp         [ 272] receive: C/[V] Raw buffer received: @3FFB3834/14:
  | 0000: 02 02 00 00 00 08 79 FF  02 02 01 01 60 0C        |......y.....`.  |
[D] 1070| RTUutils.cpp         [ 437] receive: C/[D] Received packet: @3FFB8308/1:
  | 0000: E2                                                |.               |
[D] 1090| ModbusClientRTU.cpp  [ 268] handleConnection: Error response (1 bytes) received.
[V] Data: @3FFB8308/1:
  | 0000: E2                                                |.               |
[D] 1101| ModbusClientRTU.cpp  [ 289] handleConnection: Response generated.
[V] Response packet: @3FFB8308/3:
  | 0000: 02 82 E2                                          |...             |
[E] 1121| modbus_master.ino    [ 291] handleError: Error response: E2 - CRC check error
[V] 2015| ModbusMessage.cpp    [ 477] checkData: Check data #3
[D] 2015| ModbusClientRTU.cpp  [ 147] addRequestM: request for 02/02
[D] 2025| ModbusClientRTU.cpp  [ 230] addToQueue: RC=01
[D] 2025| ModbusClientRTU.cpp  [ 158] addRequestM: RC=00
[D] 2025| ModbusClientRTU.cpp  [ 248] handleConnection: Pulled request from queue
[D] Sent packet: @3FFB37D4/6:
  | 0000: 02 02 00 00 00 08                                 |......          |
[D] 2044| ModbusClientRTU.cpp  [ 253] handleConnection: Request sent.
[V] 2059| RTUutils.cpp         [ 262] receive: C/3669us without data after 14
[V] 2059| RTUutils.cpp         [ 272] receive: C/[V] Raw buffer received: @3FFB381C/14:
  | 0000: 02 02 00 00 00 08 79 FF  02 02 01 01 60 0C        |......y.....`.  |
[D] 2080| RTUutils.cpp         [ 437] receive: C/[D] Received packet: @3FFB8308/1:
  | 0000: E2                                                |.               |
[D] 2090| ModbusClientRTU.cpp  [ 268] handleConnection: Error response (1 bytes) received.
[V] Data: @3FFB8308/1:
  | 0000: E2                                                |.               |
[D] 2101| ModbusClientRTU.cpp  [ 289] handleConnection: Response generated.
[V] Response packet: @3FFB8308/3:
  | 0000: 02 82 E2                                          |...             |
[E] 2122| modbus_master.ino    [ 291] handleError: Error response: E2 - CRC check error
  1. no RS485
ets Jul 29 2019 12:21:46

rst:0x1 (POWERON_RESET),boot:0x12 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1344
load:0x40078000,len:13964
load:0x40080400,len:3600
entry 0x400805f0
__ OK __
[D] 25| ModbusClientRTU.cpp  [ 111] setTimeout: Timeout set to 2000
[V] 25| RTUutils.cpp         [ 112] calculateInterval: Calc interval(9600)=3645
[D] 36| ModbusClientRTU.cpp  [  86] doBegin: Client task 1073428052 started. Interval=3645
[V] 1015| ModbusMessage.cpp    [ 477] checkData: Check data #3
[D] 1015| ModbusClientRTU.cpp  [ 147] addRequestM: request for 02/02
[D] 1015| ModbusClientRTU.cpp  [ 230] addToQueue: RC=01
[D] 1015| ModbusClientRTU.cpp  [ 248] handleConnection: Pulled request from queue
[D] 1025| ModbusClientRTU.cpp  [ 158] addRequestM: RC=00
[D] Sent packet: @3FFB37EC/6:
  | 0000: 02 02 00 00 00 08                                 |......          |
[D] 1044| ModbusClientRTU.cpp  [ 253] handleConnection: Request sent.
[V] 1059| RTUutils.cpp         [ 262] receive: C/3650us without data after 8
[V] 1059| RTUutils.cpp         [ 272] receive: C/[V] Raw buffer received: @3FFB3834/8:
  | 0000: 02 02 00 00 00 08 79 FF                           |......y.        |
[D] 1079| RTUutils.cpp         [ 437] receive: C/[D] Received packet: @3FFB37BC/6:
  | 0000: 02 02 00 00 00 08                                 |......          |
[D] 1090| ModbusClientRTU.cpp  [ 268] handleConnection: Data response (6 bytes) received.
[V] Data: @3FFB37BC/6:
  | 0000: 02 02 00 00 00 08                                 |......          |
[D] 1100| ModbusClientRTU.cpp  [ 289] handleConnection: Response generated.
[V] Response packet: @3FFB37BC/6:
  | 0000: 02 02 00 00 00 08                                 |......          |
00: 02, 01: 02, 02: 00, 03: 00, 04: 00, 05: 08, 
handleData
[V] 2015| ModbusMessage.cpp    [ 477] checkData: Check data #3
[D] 2015| ModbusClientRTU.cpp  [ 147] addRequestM: request for 02/02
[D] 2025| ModbusClientRTU.cpp  [ 230] addToQueue: RC=01
[D] 2025| ModbusClientRTU.cpp  [ 158] addRequestM: RC=00
[D] 2025| ModbusClientRTU.cpp  [ 248] handleConnection: Pulled request from queue
[D] Sent packet: @3FFB37D4/6:
  | 0000: 02 02 00 00 00 08                                 |......          |
[D] 2044| ModbusClientRTU.cpp  [ 253] handleConnection: Request sent.
[V] 2059| RTUutils.cpp         [ 262] receive: C/3646us without data after 8
[V] 2059| RTUutils.cpp         [ 272] receive: C/[V] Raw buffer received: @3FFB381C/8:
  | 0000: 02 02 00 00 00 08 79 FF                           |......y.        |
[D] 2080| RTUutils.cpp         [ 437] receive: C/[D] Received packet: @3FFB37D4/6:
  | 0000: 02 02 00 00 00 08                                 |......          |
[D] 2090| ModbusClientRTU.cpp  [ 268] handleConnection: Data response (6 bytes) received.
[V] Data: @3FFB37D4/6:
  | 0000: 02 02 00 00 00 08                                 |......          |
[D] 2101| ModbusClientRTU.cpp  [ 289] handleConnection: Response generated.
[V] Response packet: @3FFB37D4/6:
  | 0000: 02 02 00 00 00 08                                 |......          |
00: 02, 01: 02, 02: 00, 03: 00, 04: 00, 05: 08, 
handleData

Thanks! now we get somewhere.

The request still is echoed back, so the problem is located on the ESP32 side. The software is acting as if there is a loopback between TX and RX of the Serial interface. This can be some unintended wire or false contact on the breadboard, or a wrong GPIO assignment somewhere. Can it be some other library you are using is doing Serial configuration as well?

OK, I am digging.

Will keep doing the same test and see what will comes out.

Thanks in advance!

Screenshot 2023-12-15 233126

Can you see it?

I am afraid: no? I personally would not recommend pulling RE to a constant GND, but what else should I see?

I personally would not recommend pulling RE to a constant GND

I will call my colleague tomorrow and we should redesign this thing!

I would like to apologies for wasting your time!

No worries. I would have told you if you had been wasting my time. One always will learn something.

The usual connection is to wire both RE and DE to the same GPIO, so that toggling that between HIGH and LOW levels will switch between listen and send modes.

Hello, and Merry Christmas! I wish you guys all best!

Well after revising our electrical schematic and fix the F.. issue all things are great and work.

I face the following problem by creating message and here the problem.

I am not able to create a single coil message and send it FC=0x05.

The code:

        // Issue the request
        Error ErrorL = ModbusClientRTU_g->addRequest((uint32_t)millis(), MB_SLAVE_ID, WRITE_COIL, 1, 1);
        if (ErrorL!=SUCCESS)
        {
          ModbusError e(ErrorL);
          LOG_E("Error creating request: %02X - %s\n", (int)e, (const char *)e);
        }
[V] 109042| ModbusMessage.cpp    [ 477] checkData: Check data #3
[E] 109042| modbus_master.ino    [ 174] loop: Error creating request: E7 - Parameter out of bounds

Thanks in advance.
I decide not open a new issue because it is easy to track what we achieve due to our device development

Regards

Good to read you got your schematics fixed and the initial problem is gone.

The Modbus standard is stating for the 0x05 Set Coil function code the second parameter (your second '1') has to be 0 to clear the coil/bit and 0xff00 to set it, so you want to use 0xff00 here.

Great, you are providing the best support!

Can you please show me example for multiple coils. The idea is to reduce the number of messages through the network.

Regards

You should have a look at the TCPcoilExample sketch, that makes use of the eModbus CoilData type and has an example for writing multiple coils as well.

I would like to thank you for your help.

Great library, great team!

Regards

May I ask if your code is prepared for the following situation in hardware development?

Specifically, in the case of an ESP32 equipped with an LAN8720 Ethernet controller, can your code handle MODBUS TCP and send MODBUS packages to slave server devices?

I do not know that specific Ethernet controller, but I myself am using exactly the setup you described. Base is a ModbusBridgeEthernet with a ModbusClientRTU attached to it. This way I can request from the bridge over TCP data it will in turn request from RTU servers on the bus. There is an example sketch for that as well. 😉