smarmengol Modbus and SoftwareSerial not reliable

I followed the included sketches of smarmengol Modbus to setup SoftwareSerial advanced master and slave on a pair of MEGA2560s.

Master sketch:

/**
 *  Modbus master example 2:
 *  The purpose of this example is to query several sets of data
 *  from an external Modbus slave device. 
 *  The link media can be USB or RS232.
 *
 *  Recommended Modbus slave: 
 *  diagslave http://www.modbusdriver.com/diagslave.html
 *
 *  In a Linux box, run 
 *  "./diagslave /dev/ttyUSB0 -b 19200 -d 8 -s 1 -p none -m rtu -a 1"
 * This is:
 * serial port /dev/ttyUSB0 at 19200 baud 8N1
 * RTU mode and address @1
 */

#include <ModbusRtu.h>
#include <SoftwareSerial.h>

uint16_t au16data[16]; //!< data array for modbus network sharing
uint8_t u8state; //!< machine state
uint8_t u8query; //!< pointer to message query

/**
 *  Modbus object declaration
 *  u8id : node id = 0 for master, = 1..247 for slave
 *  u8serno : serial port (use 0 for Serial)
 *  u8txenpin : 0 for RS-232 and USB-FTDI 
 *               or any pin number > 1 for RS-485
 */
Modbus master(0); // this is master and RS-232 or USB-FTDI
SoftwareSerial altSerial(50, 48); // RX, TX
/**
 * This is an structe which contains a query to an slave device
 */
modbus_t telegram[2];

unsigned long u32wait;

void setup() {
  Serial.begin(115200);
  Serial.println("Hello");
  // telegram 0: read registers
  telegram[0].u8id = 1; // slave address
  telegram[0].u8fct = 3; // function code (this one is registers read)
  telegram[0].u16RegAdd = 0; // start address in slave
  telegram[0].u16CoilsNo = 4; // number of elements (coils or registers) to read
  telegram[0].au16reg = au16data; // pointer to a memory array in the Arduino

  // telegram 1: write a single register
  telegram[1].u8id = 1; // slave address
  telegram[1].u8fct = 6; // function code (this one is write a single register)
  telegram[1].u16RegAdd = 4; // start address in slave
  telegram[1].u16CoilsNo = 1; // number of elements (coils or registers) to read
  telegram[1].au16reg = au16data+4; // pointer to a memory array in the Arduino
 
//  master.begin( 9600 ); 
  master.begin( &altSerial, 9600 ); // begin the ModBus object. The first parameter is the address of your SoftwareSerial address. Do not forget the "&". 9600 means baud-rate at 9600
  master.setTimeOut( 5000 ); // if there is no answer in 5000 ms, roll over
  u32wait = millis();
  u8state = u8query = 0; 
}

void loop() {
  switch( u8state ) {
  case 0: 
    if (millis() - u32wait > 1000)
     {
      u8state++; // wait state
      Serial.println("State 1");
     }
    break;
  case 1:
    master.query( telegram[u8query] ); // send query (only once)
     Serial.println("State 2");
    u8state++;
 u8query++;
 if (u8query > 2) u8query = 0;
    break;
  case 2:
    master.poll(); // check incoming messages
    if (master.getState() == COM_IDLE) {
     Serial.print(au16data[0]);
     Serial.print(",");
     Serial.print(au16data[6]);
     Serial.print(",");
     Serial.print(au16data[7]);
     Serial.print(",");
     Serial.println(au16data[8]);
     Serial.println("State 0");
      u8state = 0;
      u32wait = millis(); 
    }
    break;
  }

  au16data[4] = analogRead( 0 );
  
}

Slave Sketch:

/**
 *  Modbus slave example 2:
 *  The purpose of this example is to link the Arduino digital and analog
 * pins to an external device.
 *
 *  Recommended Modbus Master: QModbus
 *  http://qmodbus.sourceforge.net/
 */
#include <SoftwareSerial.h>
SoftwareSerial altSerial(50, 48); // RX, TX
#include <ModbusRtu.h>
#define ID   1

Modbus slave(ID); // this is slave ID and RS-232 or USB-FTDI
boolean led;
int8_t state = 0;
unsigned long tempus;

// data array for modbus network sharing
uint16_t au16data[9];

/**
 *  Setup procedure
 */
void setup() {
  Serial.begin(115200);
  Serial.println("Hello");
  io_setup(); // I/O settings

  // start communication
//  slave.begin( 9600 );
  slave.begin( &altSerial, 9600 );

  tempus = millis();
  digitalWrite(13, HIGH );
}

/**
 *  Loop procedure
 */
void loop() {
  // poll messages
  // blink led pin on each valid message
  state = slave.poll( au16data, 9 );

  if (state > 4) {
    tempus = millis();
     Serial.print(au16data[6]);
     Serial.print(",");
     Serial.print(au16data[7]);
     Serial.print(",");
     Serial.println(au16data[8]);
    digitalWrite(13, HIGH);
  }
  if (millis() - tempus > 50) digitalWrite(13, LOW );

  // link the Arduino pins to the Modbus array
  io_poll();
} 

/**
 * pin maping:
 * 2 - digital input
 * 3 - digital input
 * 4 - digital input
 * 5 - digital input
 * 6 - digital output
 * 7 - digital output
 * 8 - digital output
 * 9 - digital output
 * 10 - analog output
 * 11 - analog output
 * 14 - analog input
 * 15 - analog input
 *
 * pin 13 is reserved to show a successful query
 */
void io_setup() {
  // define i/o
  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  pinMode(4, INPUT_PULLUP);
  pinMode(5, INPUT_PULLUP);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(13, OUTPUT);

  digitalWrite(6, LOW );
  digitalWrite(7, LOW );
  digitalWrite(8, LOW );
  digitalWrite(9, LOW );
  digitalWrite(13, HIGH ); // this is for the UNO led pin
  analogWrite(10, 0 );
  analogWrite(11, 0 );
}

/**
 *  Link between the Arduino pins and the Modbus array
 */
void io_poll() {
  // get digital inputs -> au16data[0]
  bitWrite( au16data[0], 0, digitalRead( 2 ));
  bitWrite( au16data[0], 1, digitalRead( 3 ));
  bitWrite( au16data[0], 2, digitalRead( 4 ));
  bitWrite( au16data[0], 3, digitalRead( 5 ));

  // set digital outputs -> au16data[1]
  digitalWrite( 6, bitRead( au16data[1], 0 ));
  digitalWrite( 7, bitRead( au16data[1], 1 ));
  digitalWrite( 8, bitRead( au16data[1], 2 ));
  digitalWrite( 9, bitRead( au16data[1], 3 ));

  // set analog outputs
  analogWrite( 10, au16data[2] );
  analogWrite( 11, au16data[3] );

  // read analog inputs
  au16data[4] = analogRead( 0 );
  au16data[5] = analogRead( 1 );

  // diagnose communication
  au16data[6] = slave.getInCnt();
  au16data[7] = slave.getOutCnt();
  au16data[8] = slave.getErrCnt();
}

It almost completely works. The data is intermittent (ie., not very reliable). Is there something wrong with the skecthes or with the modbus library? Supposed this library works with SoftwareSerial and I’m not finding that to be the case.

Never use a software serial library on a Mega. It has 3 extra HardwareSerial ports for you to use: Serial1, Serial2 and Serial3, on pins 14-19.

With the proper configuration in the ModBus library, you should be able to call

   slave.begin( &Serial1, 9600 );

Are there some defines in an H file that let you select HardwareSerial instead of AltSoftSerial?

Standard engineering practice. Change one thing at a time. Take one step at a time. Eventually I will be changing the slave MEGA to nanos.

Using the pair of MEGAs, I started with a hardware serial echo test to verify the sketch and connections. Then I moved to software serial echo to make sure that works. I then changed to Modbus via hardware serial TTL (using Serial1). Since the nano has only one serial port, I'm on to making Modbus via SoftwareSerial.

Working with the MEGAs allows the serial port to be used for the serial monitor while debugging the software serial and modbus connections.

For now I need to get Modbus SoftwareSerial working, but only as a stepping stone or proof of concept. Supposedly the modbus library works with SoftwareSerial, but I'm not seeing it yet. Or I can make the leap to using AltSoftSerial, if any one knows how to make that work (see other thread). It is not as simple as substituting AltSoftSerial for SoftwareSerial or Serial1.

(see other thread)

Link to other thread?

-dev:
Link to other thread?

Eventually I will be changing the slave MEGA to nanos.

That doesn't help very much... I don't see any particular reason that AltSoftSerial did not work. Of course, we can't see the mods you made to the library.

You should still use Serial for the Nano ModBus. It will be much more reliable, and the CPU won't have to work so hard.

For testing, you could use AltSoftSerial on 8 & 9 for debug prints. Connect a TTL Serial-to-USB converter (aka FTDI) to those pins, and connect the USB to your PC. I assume the debug prints will be removed in the final system.

SoftwareSerial really isn't a choice for this application. It disables interrupts for long periods of time, and forces the Arduino to wait for each character to be sent or received. :stuck_out_tongue:

-dev:
Of course, we can't see the mods you made to the library.

Where do you see or what makes you think I made any modifications to the library or to any library?

Accroding to the smarmengol Modbus library website it is already compatible and ready to work with SoftwareSerial.

Though not the end game, I thought it would be best to use the library as is to see it working before I went out and tried to modify it. Now I know that I have an intermittent issue using the library with SoftwareSerial and that it has nothing to do with any chances I made (because I haven't made any).

You are correct in that SoftwareSerial isn't a good choice for this, or any other application. But it is what the library was built to work with. So this is the best path for development unless someone has a smarmengol Modbus library already modified to work with AltSoftSerial.

Comments like

-dev:
That doesn't help very much... I don't see any particular reason that AltSoftSerial did not work.

do not move the problem along.

All modified current code is posted in the threads (obviously no library posted because it is as yet unmodified thus no reason to post it)

Where do you see or what makes you think I made any modifications to the library or to any library?

You said this:

Since there is only an software serial master sketch and given it has the serial debug already in it, I added and changed it to include AltSoftSerial.

So...

And I don't understand your conclusion here:

But it [SoftwareSerial] is what the library was built to work with. So this is the best path for development

Good luck...

-dev:

adwsystems:
Where do you see or what makes you think I made any modifications to the library or to any library?

-dev:
You said this:

adwsystems:
Since there is only an software serial master sketch and given it has the serial debug already in it, I added and changed it to include AltSoftSerial. The sketch compiles but doesn't work.

That is two independent items that have been incorrectly linked and additionally misread.

It says

adwsystems:
Since there is only an software serial master sketch and given it has the serial debug already in it, I added and changed it to include AltSoftSerial. The sketch compiles but doesn't work.

I changed the software serial master sketch. Not the library. I have not changed any libraries.

Please do not connect the work from the post on working with AltSoftSerial with the work here on SoftwareSerial. It will only confuse everyone. For the most part the other thread is on hold until someone is available to assist. If you think the sketch in the post from where you linked that quote, should work, then let's jump over there and work on it. AltSoftSerial is the end game, if I have help to make it work then I'm all game to jump over the SoftwareSerial step.

At this time I'm looking to get the sketches and working as they were provided.

-dev:
And I don't understand your conclusion here:

adwsystems:
But it is what the library was built to work with. So this is the best path for development unless someone has a smarmengol Modbus library already modified to work with AltSoftSerial.

Good luck...

It is not a conclusion. It is a fact. The smarmengol Modbus library was modified, with help from Helium6072, to work with SoftwareSerial. Please see https://github.com/smarmengol/Modbus-Master-Slave-for-Arduino for more information. Supposedly they work together. Supposedly.

I am not in of need luck, I need assistance. I am experienced in programming many platforms, but I'm just learning this one. I'm all game to dump SoftwareSerial and jump to using AltSoftSerial, but I can only do that with assistance from experts on the Arduino platform and knowledge on this modbus library.