CMB27 / ModbusRTUMaster

A library to implement the master/client portion of the Modbus RTU protocol on Arduino
MIT License
48 stars 7 forks source link

add _clearRxBuffer on every function #16

Closed ArnoldSchrader closed 1 month ago

ArnoldSchrader commented 3 months ago

I tried the library with the esp8266 to communicate with the Epever charge controller and with a few adjustments I even managed to establish a connection. However, the connection was rarely stable. As I found out, at some point something always remains in the “pipeline” (due to errors or similar). From then on, communication was no longer possible because the CRC was never correct. The reason, as I found out, is that the RxBuffer is only emptied once at the beginning. But never in between.

Inserting _clearRxBuffer() in every read and write function has stabilized this significantly...

CMB27 commented 3 months ago

How is your RS-485 driver connected to your ESP8266? It sounds like you are having an echo problem, where you are receiving everything you are sending. Connecting the RE and DE pins of the driver together and to the DE control pin on the ESP8266 may fix the problem.

ArnoldSchrader commented 3 months ago

I have a MAX3485 connected to the swapped serial. Control pin is not necessary. I don't think it's an echo problem: otherwise no communication would have been possible at all. But it worked for minutes or even an hour. I rather think that the EPever is not the most reliable terminal device with regard to RS485. I would therefore recommend to work arround such devices by simply clearing the buffer before I will get new data. Now it runs for days. Another change I made to the code concerns error handling: I didn't notice the communication errors at first because they were skipped. I have now adapted them to the error codes of another project (which makes it easier for me to evaluate them):

uint16_t ModbusRTUMaster::_readResponse(uint8_t id, uint8_t functionCode) {
  unsigned long startTime = millis();
  uint16_t numBytes = 0;
  while (!_serial->available()) {
    if (millis() - startTime >= _responseTimeout) {
      _exceptionResponse = 226;
      return 0;
    }
  }
  do {
    if (_serial->available()) {
      startTime = micros();
      _buf[numBytes] = _serial->read();
      numBytes++;
    }
  } while (micros() - startTime <= _charTimeout && numBytes < MODBUS_RTU_MASTER_BUF_SIZE);
  while (micros() - startTime < _frameTimeout);
  if(_buf[0] != id) {
    _exceptionResponse = 224;
    return 0;
  } else if(_buf[1] != functionCode && _buf[1] != (functionCode + 128)) {
    _exceptionResponse = 225;
    return 0;
  } else if(_crc(numBytes - 2) != _bytesToWord(_buf[numBytes - 1], _buf[numBytes - 2])) {
    _exceptionResponse = 227;
    return 0;
  } else if (_buf[1] == (functionCode + 128)) {
    _exceptionResponse = 228; //_buf[2];
    return 0;
  }
  return (numBytes - 2);
}
CMB27 commented 3 months ago

The MAX3485 definitely requires a control pin. Screenshot_24-8-2024_111315_www analog com Image source: MAX3483-MAX3491 datasheet

My understanding is that additional circuitry can be used to automatically manage the DE and RE pins of the driver, but I haven't ever used such schemes.

I recommend wiring up the driver like this. Schematic

To my knowledge, 224 (0xE0), 225 (0xE1), 226 (0xE2), 227 (0xE3), and 228 (0xE4) are not standard Modbus exception codes. While error checking like this is nice for debugging, it is not necessary for normal operations, nor is it required by the Modbus specification, therefore it lies outside of the scope of what this library aims to do.

There are also other ways of debugging that can actually show more. I use a logic analyzer (Raspberry Pi Pico with PulseView).

ArnoldSchrader commented 3 months ago

To my knowledge, 224 (0xE0), 225 (0xE1), 226 (0xE2), 227 (0xE3), and 228 (0xE4) are not standard Modbus exception codes.

I know but it helps me for watch my battery- and solar-control via telnet again ;)

I use this max3485: https://www.amazon.de/dp/B08HQMDKGR/ref=pe_27091401_487024491_TE_item

CMB27 commented 3 months ago

You are free to make any tweaks you want. I don't plan on incorporating these changes into the library.

That module seems a bit sketchy to me. I couldn't find any schematics for it. The schematics I do see to automatically handle the DE and RE pins have a transistor in them. I don't see a transistor on the board.

I really don't know how this board is handling those pins, and I suspect they are fudging something.