Looking for guidance SimpleModbusMaster + SoftwareSerial

Hi All,

I'm trying to get data from a modus device using SimpleModbusMaster.

It uses the hardware serial pins.

I'm using an uno so I don't have other hardware serial pins, but I'd like to debug.

It there a way to have console messages over SoftwareSerial or move SimpleModbusMaster to use SoftwareSerial

Regards

Ian

Here's my code.

I read somewhere that modbus_configure would take SoftwareSerial instead of Serial but the only way was to cast it. <Think that's dumb>

Running Saleae Logic 1.2.18 I see activity on Pin 2 Pin 10 & Pin 11

Any ideas


#include <SimpleModbusMaster.h>
#include <SoftwareSerial.h>

SoftwareSerial mySerial(10, 11); // RX, TX

#define baud 9600 //Baud rate for MODBUS RTU
#define timeout 1000 //Maximum time for slave to respond (ms)
#define polling 2000 // Maximum scan rate of master to allow slave to return to idle (ms)
#define retry_count 10 //Maximum retries if slave returns response timeout or error
#define TxEnablePin 2 //Pin to set RS485 interface to transmit or receive (high to Transmit, sets DE and RE high. DE must be high to transmit and RE low to receive)
#define TOTAL_NO_OF_REGISTERS 2 //Used to size the array for returned data from slave to the total number of unsigned 16 bit registers to be read

#define ActiveImport 0x5000

#define ActiveImportAccum 0x5460

#define CurrentVoltage 0x5B00

//Create a packet for each distinct request for data (slave ID, function code, start address and number of registers to be returned) and the total number of packets
enum
{
PACKET1,
TOTAL_NO_OF_PACKETS // leave this last entry
};

unsigned int iCnt = 0;
//Create an array of packets
Packet packets[TOTAL_NO_OF_PACKETS];

//Create an array to hold returned data in its raw form of unsigned integers
unsigned int regs[TOTAL_NO_OF_REGISTERS]; //Array size seems to need to be 1 more than the total number of registers (i.e. 0 to n)

unsigned int OldRegs=0; //Used to store previous value to see if data returned by slave has changed - FOR INITIAL TESTING

//Variables used for time delay - FOR INITIAL TESTING
long previousmillis = 0;
long interval = 10000; ///time in ms to hold led on after value changes
unsigned long currentmillis = millis();

void setup() {
// Initialize packets (pointer to packet, slave device ID, function code constant, address to read (zero based),number of registers to read,subscript of first returned value in regs array
//This would be repeated if there wss more than one packet defined
//On the ABB B21 (set as ID 6) we use function code 3 Read Holding Registers, start address 20483 is the least significant word (16 bits) of the 4-word active import register, read one register and store in the first subscript of the regs array
//The returned value is in 1/100ths of a kWh. To read the whole value we would beed to read four registers starting at 20480 and shift and cast them into a single value. On this meter the most significant word is the first word.
// modbus_construct(&packets[PACKET1], 6, READ_HOLDING_REGISTERS, 20483, 1, 0);
modbus_construct(&packets[PACKET1], 6, READ_HOLDING_REGISTERS, ActiveImport+3, 1, 0);

mySerial.begin(9600);

// Initialize the Modbus comms using the default hardware serial port (Pins D0 and D1) and parameters at the top of the code, packet definitions and array to hold data locally
modbus_configure( (HardwareSerial*) &mySerial, baud, SERIAL_8E1, timeout, polling, retry_count, TxEnablePin, packets, TOTAL_NO_OF_PACKETS, regs);

Serial.begin(9600,SERIAL_8E1);
Serial.println("Lets start again...");
Serial.println("id");
Serial.println(packets[0].id);
Serial.println("function");
Serial.println(packets[0].function);
Serial.println("address");
Serial.println(packets[0].address);
Serial.println("data");
Serial.println(packets[0].data);
Serial.println("local_start_address");
Serial.println(packets[0].local_start_address);

}

void loop() {
modbus_update(); //Poll the slave

//Control LED to indicate value has just changed - FOR INITIAL TESTING
currentmillis=millis(); //Store current time
if(regs[0]!=OldRegs){
iCnt++;
}
else {
if(currentmillis - previousmillis >= interval){

char str[80];

sprintf(str , "%d Hello %d %d ", iCnt , regs[0] , OldRegs );
Serial.println(str);
iCnt = 0;

previousmillis=currentmillis;
}
}

//Store the latest value to use as old value on next iteration round loop
OldRegs=regs[0];
}

Is it working?

no

Please post a link (using the chain links icon on the forum toolbar to make it clickable) to where you downloaded the SimpleModbusMaster library from. Or if you installed it using Library Manger (Sketch > Include Library > Manage Libraries in the Arduino IDE or Libraries > Library Manager in the Arduino Web Editor) then say so and state the full name of the library.

Ian7Goodwin:
It there a way to have console messages over SoftwareSerial

Yes, but you'll need a USB to TTL serial adapter to connect the software serial pins to your computer. The USB to TTL serial adapters are widely available for a very low cost, and are a super useful tool to have on hand. Here's one of the ones I use on eBay:
https://www.ebay.com/itm/312519249465
but you can get them from most any other place you would go to get electronics components.

The CH340 ones are a good choice also. Although it's not important for this project, I do recommend that you get one which uses the standard FTDI pinout:

  • DTR or RTS
  • RX
  • TX
  • VCC
  • CTS
  • GND

That will allow you to plug the adapter right in to an Arduino Pro Mini, or many other boards that use this standard pinout. If you get an adapter with a non-standard pinout, you would need to use a mess of jumper wires to adapt it to the standard pinout, and some don't even break out all the signals you need for full functionality!

The ones that allow you to switch between 5 V and 3.3 V is also a nice feature.