Modbus RTU using Schneider Power Meter and Arduino Uno

Hello guys, does anyone know a working library for the implementation of Arduino Uno and Schneider Power Meter or something similar in nature? Because I have used the SimpleModbus library and it does not give me results. When I loaded it up, the value is always 0. I am using the PM1200 and below is my code.

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

#define TxEnablePin 2 // RS485 modbus direction control pin:
#define baud 9600 // modbus port speed:
#define timeout 1000 // modbus timeout in mSec:
#define polling 200 // modbus scan rate in mSec:
#define retry_count 20

#define TOTAL_NO_OF_REGISTERS 20// number of registers to poll for:

#define LED 13

enum
{
PACKET1,
TOTAL_NO_OF_PACKETS // leave this last entry
};

Packet packets[TOTAL_NO_OF_PACKETS]; // array of Packets to be configured

//packetPointer packet1 = &packets[PACKET1];
unsigned int regs[TOTAL_NO_OF_REGISTERS]; // master register array
long previousMillis = 0;
long interval = 1200;
unsigned long currentMillis;
//SoftwareSerial Serial1 (10, 11);

void setup() {
Serial.begin(9600);
modbus_construct(&packets[PACKET1], 1, READ_HOLDING_REGISTERS, 3926, 2, regs); //initialize packet 1
modbus_configure(&Serial, baud, SERIAL_8N2, timeout, polling, retry_count, TxEnablePin, packets, TOTAL_NO_OF_PACKETS, regs);

pinMode(LED,OUTPUT);
}

void loop() {
digitalWrite(13,HIGH);
delay(500);
digitalWrite(13,LOW);
delay(500);

modbus_update();

float Power;
unsigned long temp = (unsigned long)regs[0] << 16 | regs[1];
Power = (float)&temp;

currentMillis = millis();
if (currentMillis - previousMillis >= interval)
{

Serial.print("Exception errors: ");
Serial.println(packets[PACKET1].exception_errors);

Serial.print("Failed requests: ");
Serial.println(packets[PACKET1].failed_requests);

Serial.print("Successful requests: ");
Serial.println(packets[PACKET1].successful_requests);
Serial.print("Low byte: ");
Serial.println(regs[0]);
Serial.print("High byte: ");
Serial.println(regs[1]);
Serial.print(“Power “);
Serial.println(Power);
Serial.println(”----------”);
previousMillis = currentMillis;
}

}

Also, I am new to Modbus. I cannot fully understand it. :frowning: Please help.

What RS-485 hardware (driver chip) are you using?

Do you have a link to your power meter? The manual I found on the Internet says that the RM1200 uses 8N1 and not the 8N2 you are configuring.

You cannot use the Serial interface for debugging and for the RS-485 communication. What Arduino are you using? Does it have a second hardware serial interface? I strongly discourage you to use SoftwareSerial for the RS-485 interface. If you have to use a software emulation, use it for the debugging channel and use AltSoftSerial instead of SoftwareSerial.

I am using MAX485 chip. I have commented out the softwareserial. I am using Arduino Uno but later on will use Trinket Pro.

http://panelmeters.weschler.com/Asset/Schneider-PM1200-Manual.pdf

Can you suggest some changes with the code?

In this case you're using the serial interface for two different things at the same time. You're printing debugging information on it and you try to communicate with your power meter. Chances are high that your power meter doesn't understand the debugging information you send it and it won't be able to distinguish itself what in the stream it gets belongs to the debugging information and what's ModBus traffic.

If you don't want to use a Leonardo (which has a hardware serial interface independent of the USB PC connection) or Mega2560 (which has 4 hardware serial interfaces and only one is used for the PC connection) you should probably use AltSoftSerial and connect your PC to pins 8 and 9 using a USB2TTLSerial adapter (p.e. Arduino USB 2 Serial Micro). Then change all Serial.print* calls with the appropriate other method.

Or a '1284P with two hardware serial ports.

I entered the altsoftwareserial but I get these error message:

Arduino: 1.6.4 (Windows 8.1), Board: “Arduino Uno”

sketch_dec05b.ino: In function ‘void setup()’:
sketch_dec05b:33: error: cannot convert ‘AltSoftSerial*’ to ‘HardwareSerial*’ for argument ‘1’ to ‘void modbus_configure(HardwareSerial*, long int, unsigned char, long int, long int, unsigned char, unsigned char, Packet*, unsigned int, unsigned int*)’
cannot convert ‘AltSoftSerial*’ to ‘HardwareSerial*’ for argument ‘1’ to ‘void modbus_configure(HardwareSerial*, long int, unsigned char, long int, long int, unsigned char, unsigned char, Packet*, unsigned int, unsigned int*)’

This report would have more information with
“Show verbose output during compilation”
enabled in File > Preferences.

Here is what I have done to the code:

#include <SimpleModbusMaster.h>
#include <AltSoftSerial.h>

#define TxEnablePin 2 // RS485 modbus direction control pin:
#define baud 9600 // modbus port speed:
#define timeout 1000 // modbus timeout in mSec:
#define polling 200 // modbus scan rate in mSec:
#define retry_count 15

#define TOTAL_NO_OF_REGISTERS 2// number of registers to poll for:

AltSoftSerial altSerial;

enum
{
PACKET1,
TOTAL_NO_OF_PACKETS // leave this last entry
};

Packet packets[TOTAL_NO_OF_PACKETS]; // array of Packets to be configured

//packetPointer packet1 = &packets[PACKET1];
unsigned int regs[TOTAL_NO_OF_REGISTERS]; // master register array
long previousMillis = 0;
long interval = 1200;
unsigned long currentMillis;

void setup() {
Serial.begin(9600);
altSerial.begin(9600);
modbus_construct(&packets[PACKET1], 1, READ_HOLDING_REGISTERS, 60, 2, 0); //initialize packet
//modbus_configure(&Serial1, baud, SERIAL_8N2, timeout, polling, retry_count, TxEnablePin, packets, TOTAL_NO_OF_PACKETS, regs);
** modbus_configure(&altSerial, baud, SERIAL_8N2, timeout, polling, retry_count, TxEnablePin, packets, TOTAL_NO_OF_PACKETS, regs);** //i get a problem with this line
}

void loop() {
modbus_update();

float Power;
unsigned long temp = (unsigned long)regs[0] << 16 | regs[1];
Power = (float)&temp;

currentMillis = millis();
if (currentMillis - previousMillis >= interval)
{

Serial.print("Exception errors: ");
Serial.println(packets[PACKET1].exception_errors);

altSerial.print("Exception errors: ");
altSerial.println(packets[PACKET1].exception_errors);

Serial.print("Failed requests: ");
Serial.println(packets[PACKET1].failed_requests);

altSerial.print("Failed requests: ");
altSerial.println(packets[PACKET1].failed_requests);

Serial.print("Successful requests: ");
Serial.println(packets[PACKET1].successful_requests);
Serial.print("Low byte: ");
Serial.println(regs[0]);
Serial.print("High byte: ");
Serial.println(regs[1]);
Serial.print(“Power “);
Serial.println(Power);
Serial.println(”----------”);

altSerial.print("Successful requests: ");
altSerial.println(packets[PACKET1].successful_requests);
altSerial.print("Low byte: ");
altSerial.println(regs[0]);
altSerial.print("High byte: ");
altSerial.println(regs[1]);
altSerial.print(“Power “);
altSerial.println(Power);
altSerial.println(”----------”);

previousMillis = currentMillis;
}

}

You cannot use the AltSoftSerial for the ModBus side. Use for the Debugging. And you need the USB2Serial adapter to read the debugging information with your PC. In your sketch delete all Serial.print* lines, leave the altSerial.print* lines. Reactive the ModBus line with the Serial object as the parameter and it probably works.

Maybe it's time to ask what you want to achieve with the Arduino in this setup. Do you want to use it as a translation device between the ModBus and the PC only?

Please update your IDE to a current version (as of this writing 1.6.13). I don't check my stuff with old versions.

So from this I want the arduino to read the data from the power meter since I am going to store it in an sd card. For the connections it is right that I connect the PC to the arduino pins 8 and 9 using the usb2ttl adapter? Then, on the side of the power meter I have connected the rxtx to the rs485 to ttl adapter then to the pin 0 and 1 of the arduino and pin 2 as the txenablepin? Are my connections right?

I cannot upload to the board using the usb to ttl adapter.

I cannot upload to the board using the usb to ttl adapter.

This is correct, unfortunately. If you want your project to be convenient, use another Arduino (Leonardo, Mega, etc.) to have an additional hardware serial interface. Otherwise you have to unplug the RS-485 connection each time you want to upload a new sketch to your Arduino and reconnect afterwards. Connect the PC USB to the Arduino USB during upload.

For the connections it is right that I connect the PC to the arduino pins 8 and 9 using the usb2ttl adapter? Then, on the side of the power meter I have connected the rxtx to the rs485 to ttl adapter then to the pin 0 and 1 of the arduino and pin 2 as the txenablepin? Are my connections right?

Yes, connect pin 8 of the Arduino to the TX pin of the USB2Serial adapter and pin 9 to the RX pin.

I can't seem to get a value. It is always 0.00. :(

Please post your current code and the complete output you get.

Here is my recent code:

#include <SimpleModbusMaster.h>
#include <AltSoftSerial.h>

#define TxEnablePin 2 // RS485 modbus direction control pin:
#define baud 9600 // modbus port speed:
#define timeout 1000 // modbus timeout in mSec:
#define polling 200 // modbus scan rate in mSec:
#define retry_count 15

#define TOTAL_NO_OF_REGISTERS 2// number of registers to poll for:

AltSoftSerial altSerial;

enum
{
PACKET1,
TOTAL_NO_OF_PACKETS // leave this last entry
};

Packet packets[TOTAL_NO_OF_PACKETS]; // array of Packets to be configured

packetPointer packet1 = &packets[PACKET1];
unsigned int regs[TOTAL_NO_OF_REGISTERS]; // master register array
long previousMillis = 0;
long interval = 1200;
unsigned long currentMillis;

void setup() {
Serial.begin(9600);
altSerial.begin(9600);
altSerial.println(“Hello World”);
modbus_construct(&packets[PACKET1], 1, READ_HOLDING_REGISTERS, 3927, 2, 0); //initialize packet
modbus_configure(&Serial, baud, SERIAL_8N2, timeout, polling, retry_count, TxEnablePin, packets, TOTAL_NO_OF_PACKETS, regs);
}

void loop() {
modbus_update();

float Power;
unsigned long temp = (unsigned long)regs[1] << 16 | regs[0];
Power = (float)&temp;

currentMillis = millis();
if (currentMillis - previousMillis >= interval)
{
altSerial.print("Exception errors: ");
altSerial.println(packets[PACKET1].exception_errors);

altSerial.print("Failed requests: ");
altSerial.println(packets[PACKET1].failed_requests);

altSerial.print("Successful requests: ");
altSerial.println(packets[PACKET1].successful_requests);
altSerial.print("Low byte: ");
altSerial.println(regs[0]);
altSerial.print("High byte: ");
altSerial.println(regs[1]);
altSerial.print(“Power “);
altSerial.println(Power);
altSerial.println(”----------”);

previousMillis = currentMillis;
}

}

And the output I get,

Exception errors: 0
Failed requests: 1
Successfull requests: 0
Low byte: 0
High byte: 0
Power: 0.00

I wrote in my first post:

pylon: Do you have a link to your power meter? The manual I found on the Internet says that the RM1200 uses 8N1 and not the 8N2 you are configuring.

You still configure 8N2. Why? I was wrong too, the manual says on page 47 it should be 9600 baud with 8E1, although according to page 49 the baudrate can be changed, the even parity and a single stop bit seems to be fixed. Do you know anything about the RM1200 that I cannot find in the manual?

According to page 53 of the manual you're not reading the power value but the voltage of phase 1 to neutral. Is that the intended action?

My power meter is not RM1200 it is PM1200. Here is the link: PM1200 power meter.

But, yes I would like to read the voltage of phase 1 to neutral. How can I do that? :confused:

Please excuse, that was my typo. I read the manual of the PM1200 power meter and the page references in my last post point to that manual. So I guess you have to change the serial configuration to match that of your power meter.

Okay I will try that. But is there another way that I should get or access the register to get the data?

Can you suggest another code that may work? Or as an alternative?

I just need to get this done this week and it is really frustrating. :(

Another one, how can I get the data by block?

Thank you for being so helpful by the way.

But is there another way that I should get or access the register to get the data?

Other way of what kind? There are other ModBus functions you could use but according to the manual the power meter supports only function 3. I see no other way of communicating with the device than using ModBus RTU.

Can you suggest another code that may work? Or as an alternative?

I guess you've chosen a quite easy to use library. I know alternatives but they are more complex and harder to use and offer no advantage for your purpose.

Another one, how can I get the data by block?

Part of the address space is organized as blocks that have to be read in complete blocks (I haven't found an explanation why this must be by block). The values you're interested in can be read individually. If you must be a complete block you use the same funcation (3) but specify the starting address of the block and the complete number of registers in the block as the read size.

I still cannot get a value. I have changed the parity to 8E1. What do you think is wrong?

What should be the setting of the power meter? Should it be in RMS mode? I have a load btw. I plugged it in the socket.

Do I have to change anything else from the code?

My guess is a hardware problem. Did you wire your setup according to figure 6-1 of the manual? Do you have terminating resistors in place? What value did you choose? Is it possible to post a picture of your setup?

hy @kat121

did u solve this problem with pm1200, i have same problem........