Open karamdali opened 20 hours ago
Thank you for the clear explanation of the problem.
dePin
is supposed to be connected to both the DE
and RE
pins of the RS-485 transceiver.Serial.flush()
to know when to set the dePin
low. Serial.flush()
is supposed to act like a delay until the serial message is fully transmitted. On the aforementioned boards, it was returning 1 byte-length too early. The solution was to do exactly as you suggested: put a delay after Serial.flush()
in _writeResponse()
. The delay is calculated in _calculateTimeouts()
: _flushCompensationDelay = (bitsPerChar * 1000000) / baud;
. bitsPerChar
is the number of bits that need to be sent in order to send a single byte. This is 10 for a configuration of SERIAL_8N1
, which is the default.As for the code, it looks pretty good, the only issue I see is in loop()
. I think you meant ledPins[0]
instead of ledPins[1]
.
It would be helpful if you could get a logic analyzer on the pins so we can see exactly what the timings are. I don't have a STM32 board, so I can't do this myself at present.
Thank you for your reply. I can't get a logic analyzer anytime soon; it might take months to arrive.However, I've replaced the STM32 with an Arduino Nano 33 IoT, but the same issue remains: it works with direct UART, but I get a timeout error when using MAX485. Here’s the code I'm using with the Nano 33 IoT:
#include <ModbusRTUSlave.h>
const byte ledPins[1] = {13};
const int dePin =5;
ModbusRTUSlave modbus(Serial1, dePin);
bool coils[1]={1};
uint16_t inputRegisters[1];
void setup() {
pinMode(ledPins[0], OUTPUT);
modbus.configureCoils(coils, 1);
modbus.configureInputRegisters(inputRegisters, 1);
modbus.begin(1, 1200);
inputRegisters[0]=200;
}
void loop() {
modbus.poll();
digitalWrite(ledPins[0], coils[0]);
}
P.S. What I have is a DIY oscilloscope, which I use to check the signals coming out from both sides. but I can't confirm if the timing is correct.
I do have an Arduino Nano 33 IoT. I ran the following test.
Arduino Nano 33 IoT
↔ ModbusRTU-Test-Shield
↔ ModbusRTU-Test-Shield
↔ Arduino Nano ESP32
Nano 33 IoT | RS-485 XCVR | RS-485 XCVR | RS-485 XCVR | RS-485 XCVR | Nano ESP32 | |||
---|---|---|---|---|---|---|---|---|
TX (1) | → | DI | A (D+) | ↔ | A (D+) | RO | → | RX (D0) |
RX (0) | ← | RO | B (D-) | ↔ | B (D-) | DI | ← | TX (D1) |
13 | → | DE | GND | ↔ | GND | DE | ← | D13 |
13 | → | RE | RE | ← | D13 |
I also used Nano2UNO-Adapter-3V3s to connect the nano boards to the shields. But these shouldn't affect much.
#include "ModbusRTUSlave.h" // version 2.0.6
const int8_t ledPin = 5;
const int8_t dePin = 13;
ModbusRTUSlave modbus(Serial1, dePin);
bool coil;
uint16_t inputRegister = 200;
void setup() {
pinMode(ledPin, OUTPUT);
modbus.configureCoils(&coil, 1);
modbus.configureInputRegisters(&inputRegister, 1);
modbus.begin(1, 1200);
}
void loop() {
modbus.poll();
digitalWrite(ledPin, coil);
}
This is nearly equivalent to what you posted. I'm just not a fan of single value arrays.
#include <ModbusRTUMaster.h> // version 2.0.0
const int8_t buttonPin = D2;
const int8_t dePin = D13;
ModbusRTUMaster modbus(Serial0, dePin);
bool coil;
uint16_t inputRegister;
unsigned long transactionCounter = 0;
unsigned long errorCounter = 0;
const char* errorStrings[] = {
"success",
"invalid id",
"invalid buffer",
"invalid quantity",
"response timeout",
"frame error",
"crc error",
"unknown comm error",
"unexpected id",
"exception response",
"unexpected function code",
"unexpected response length",
"unexpected byte count",
"unexpected address",
"unexpected value",
"unexpected quantity"
};
void setup() {
pinMode(buttonPin, INPUT_PULLUP);
Serial.begin(115200);
Serial0.begin(1200);
modbus.begin(1200);
delay(1000);
}
void loop() {
coil = !digitalRead(buttonPin);
uint8_t error;
error = modbus.writeSingleCoil(1, 0, coil);
printLog(1, 5, 0, 1, error);
error = modbus.readInputRegisters(1, 0, &inputRegister, 1);
printLog(1, 4, 0, 1, error);
}
void printLog(uint8_t unitId, uint8_t functionCode, uint16_t startingAddress, uint16_t quantity, uint8_t error) {
transactionCounter++;
if (error) errorCounter++;
char string[128];
sprintf(string, "%ld %ld %02X %02X %04X %04X %s", transactionCounter, errorCounter, unitId, functionCode, startingAddress, quantity, errorStrings[error]);
Serial.print(string);
if (error == MODBUS_RTU_MASTER_EXCEPTION_RESPONSE) {
sprintf(string, ": %02X", modbus.getExceptionResponse());
Serial.print(string);
}
else if(functionCode == 4) {
Serial.print(" inputRegister = ");
Serial.print(inputRegister);
}
else if(functionCode == 5) {
Serial.print(" coil = ");
Serial.print(coil);
}
Serial.println();
}
I know this is a bit long. Most of this is for debugging.
I didn't encounter any issues. Everything worked as expected.
I am starting to think the issue may be with the software on the ESP32. As you can see In my example code for the Nano ESP32, I used ModbusRTUMaster, which is different than what you are using.
I did a little research MAX485 boards. They seem to be pretty standard RS-485 transceivers. The one concern I have is that are 5V devices, and I know the microcontrollers you are using are 3.3V. I'm not sure this is the issue though. Most 5V devices will accept 3.3V signals on their inputs, and it looks like the MAX485 has a resistor on its RO output, which should protect your microcontrollers.
I’m using this library with an ESP32 as the Modbus master and an STM32 Bluepill as the slave, connected via MAX485 transceivers. However, I consistently encounter a timeout error when using the MAX485 module.
Interestingly, if I connect the ESP32 directly to the STM32 using UART (bypassing the MAX485), everything works perfectly without any timeouts or issues. Setup
With MAX485 (Fails):
When connected in this configuration with MAX485 modules, I get a timeout error.
I’ve confirmed that:
There is a signal output from the MAX485 module on the master (ESP32) side.
The de_pin on the slave (STM32) goes high and then returns low, but no data is received.
Direct UART (Works):
This direct UART setup works perfectly without any issues.
I’ve also tested using an FTDI chip with the same outcome: UART works, but MAX485 times out.
Questions and Observations
DE/RE Pin Support: Does the library support the use of a de_pin for driving the DE/RE lines on the MAX485?
Possible Timing Issue: Would adding a delay after Serial.flush() in the _writeResponse() function help resolve timing issues with MAX485? I noticed this could potentially stabilize transmission, but I’m not certain if this is the recommended approach.
Any insights into ensuring compatibility with MAX485 or recommended changes to the code would be appreciated. this is the stm32 code using this library (esp32(master) use esp-idf with its modbus library):