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 anonResponse
handler. The latter will have precedence, so the former two never will be called. - You defined
Values_g
as a vector ofuint8_t
, so the calls toget()
in the response handler will read the responses byte by byte. A Modbus register isuint16_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
/**
- @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
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!
- 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
- 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!
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. 😉