Hello everyone! I’m having an issue with a project of mine, and I’d be really thankful if any of you would take some time to help me!
In a nutshell: I’m trying to read the MODBUS registers of a DDS238-4 W energy meter using my Arduino Mega. In order to adapt TTL to RS485, I’m using a MAX485. The wiring is as it follows:
In case it’s hard to see (sorry I made it on Paint):
Arduino Mega Pin 8 -> MAX485 DE & RE
Arduino Mega Pin 16 (TX2) -> MAX485 DI
Arduino Mega Pin 17 (RX2) -> MAX485 R0
Arduino Mega GND -> MAX485 GND
Arduino Mega 5V -> MAX485 VCC
MAX485 A -> DDS238-4 W Pin 2
MAX485 B -> DDS238-4 W Pin 1
DDS238-4 W registers are mapped like this:
And my code (which is inspired by this one that I found at GitHub: DDS238/DDS238.ino at master · carlosmsx/DDS238 · GitHub), is as it follows:
#include <ModbusMaster.h>
#define MAX485_DE 8
typedef struct {
uint32_t ID;
float total;
float export_energy;
float import_energy;
float V;
float I;
float P;
float Kvar;
float CosPhi;
float F;
uint16_t settings;
uint32_t bauds;
} READING;
// instantiate ModbusMaster object
ModbusMaster node;
void preTransmission()
{
digitalWrite(MAX485_DE, 1);
}
void postTransmission()
{
digitalWrite(MAX485_DE, 0);
}
void setup()
{
Serial.begin(115200);
pinMode(MAX485_DE, OUTPUT);
digitalWrite(MAX485_DE, 0);
Serial2.begin(9600);
// Modbus slave ID 1 (default)
node.begin(0x01, Serial2);
// These callbacks allow us to configure the RS485 transceiver correctly
node.preTransmission(preTransmission);
node.postTransmission(postTransmission);
}
void loop()
{
READING r;
uint8_t result = node.readHoldingRegisters(0x00, 32); //read 32 registers starting at 0
if (result == node.ku8MBSuccess)
{
r.total = (float)(node.getResponseBuffer(0x00)*0x10000 + node.getResponseBuffer(0x01))/100.0;
r.export_energy = (float)(node.getResponseBuffer(0x08)*0x10000 + node.getResponseBuffer(0x09))/100.0;
r.import_energy = (float)(node.getResponseBuffer(0x0A)*0x10000 + node.getResponseBuffer(0x0B))/100.0;
r.V = (float)node.getResponseBuffer(0x0C)/10.0;
r.I = (float)node.getResponseBuffer(0x0D)/100.0;
r.P = (float)node.getResponseBuffer(0x0E)/1000.0;
r.Kvar = (float)node.getResponseBuffer(0x0F)/1000.0;
r.CosPhi = (float)node.getResponseBuffer(0x10)/1000.0;
r.F = (float)node.getResponseBuffer(0x11)/100.0;
r.settings= node.getResponseBuffer(0x15);
r.ID = r.settings>>8;
uint32_t baudTable[] = {0, 9600, 4800, 2400, 1200};
r.bauds = baudTable[r.settings & 0xff];
Serial.print("{'id':"); Serial.print(r.ID); Serial.print(",");
Serial.print("'total':"); Serial.print(r.total); Serial.print(",");
Serial.print("'export':"); Serial.print(r.export_energy); Serial.print(",");
Serial.print("'import':"); Serial.print(r.import_energy); Serial.print(",");
Serial.print("'V':"); Serial.print(r.V); Serial.print(",");
Serial.print("'I':"); Serial.print(r.I); Serial.print(",");
Serial.print("'P':"); Serial.print(r.P); Serial.print(",");
Serial.print("'R':"); Serial.print(r.Kvar); Serial.print(",");
Serial.print("'CosPhi':"); Serial.print(r.CosPhi); Serial.print(",");
Serial.print("'F':"); Serial.print(r.F); Serial.print("}\n");
}
getResultMsg(result);
delay(2000);
}
bool getResultMsg(uint8_t result)
{
String tmpstr2;
switch (result) {
case node.ku8MBSuccess:
return true;
break;
case node.ku8MBIllegalFunction:
tmpstr2 = "Illegal Function";
break;
case node.ku8MBIllegalDataAddress:
tmpstr2 = "Illegal Data Address";
break;
case node.ku8MBIllegalDataValue:
tmpstr2 = "Illegal Data Value";
break;
case node.ku8MBSlaveDeviceFailure:
tmpstr2 = "Slave Device Failure";
break;
case node.ku8MBInvalidSlaveID:
tmpstr2 = "Invalid Slave ID";
break;
case node.ku8MBInvalidFunction:
tmpstr2 = "Invalid Function";
break;
case node.ku8MBResponseTimedOut:
tmpstr2 = "Response Timed Out";
break;
case node.ku8MBInvalidCRC:
tmpstr2 = "Invalid CRC";
break;
default:
tmpstr2 = "Unknown error: " + String(result);
break;
}
Serial.println(tmpstr2);
return false;
}
So, the issues I'm facing:
The result in the Serial Monitor is "Invalid Slave ID", which is awkward because the energy meter states that it is 1. I tried every other possibility, and it still states "Invalid Slave ID".
I tried, instead of using pin 8 for DE and RE, using 2 separate pins (so it would be MAX485_DE and MAX485_DE_NEG) . But then the error message that I get in the Serial Monitor is "Response Timed Out".
I wonder if by using just pin 8 the comm is too fast and I can't get the proper answer, but using two pins is too slow and the response times out?
Do you guys have any ideas of what's the problem? I wonder if just simple wires are enough to communicate with the meter, but I think they are because it's such a short distance.