update SDM power meter library to version 2.2.3
in particular, this brings improved timing (settings). the values are now read out much quicker in succession.
This commit is contained in:
parent
a5ba24fdd8
commit
8202bb23cd
@ -1,6 +1,6 @@
|
|||||||
/* Library for reading SDM 72/120/220/230/630 Modbus Energy meters.
|
/* Library for reading SDM 72/120/220/230/630 Modbus Energy meters.
|
||||||
* Reading via Hardware or Software Serial library & rs232<->rs485 converter
|
* Reading via Hardware or Software Serial library & rs232<->rs485 converter
|
||||||
* 2016-2022 Reaper7 (tested on wemos d1 mini->ESP8266 with Arduino 1.8.10 & 2.5.2 esp8266 core)
|
* 2016-2023 Reaper7 (tested on wemos d1 mini->ESP8266 with Arduino 1.8.10 & 2.5.2 esp8266 core)
|
||||||
* crc calculation by Jaime García (https://github.com/peninquen/Modbus-Energy-Monitor-Arduino/)
|
* crc calculation by Jaime García (https://github.com/peninquen/Modbus-Energy-Monitor-Arduino/)
|
||||||
*/
|
*/
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@ -60,7 +60,7 @@ void SDM::begin(void) {
|
|||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
#if defined ( ESP8266 ) || defined ( ESP32 )
|
#if defined ( ESP8266 ) || defined ( ESP32 )
|
||||||
sdmSer.begin(_baud, (SoftwareSerialConfig)_config, _rx_pin, _tx_pin);
|
sdmSer.begin(_baud, (EspSoftwareSerial::Config)_config, _rx_pin, _tx_pin);
|
||||||
#else
|
#else
|
||||||
sdmSer.begin(_baud);
|
sdmSer.begin(_baud);
|
||||||
#endif
|
#endif
|
||||||
@ -77,44 +77,67 @@ void SDM::begin(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
float SDM::readVal(uint16_t reg, uint8_t node) {
|
float SDM::readVal(uint16_t reg, uint8_t node) {
|
||||||
uint16_t temp;
|
startReadVal(reg, node);
|
||||||
unsigned long resptime;
|
|
||||||
uint8_t sdmarr[FRAMESIZE] = {node, SDM_B_02, 0, 0, SDM_B_05, SDM_B_06, 0, 0, 0};
|
uint16_t readErr = SDM_ERR_STILL_WAITING;
|
||||||
float res = NAN;
|
|
||||||
|
while (readErr == SDM_ERR_STILL_WAITING) {
|
||||||
|
readErr = readValReady(node);
|
||||||
|
delay(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (readErr != SDM_ERR_NO_ERROR) { //if error then copy temp error value to global val and increment global error counter
|
||||||
|
readingerrcode = readErr;
|
||||||
|
readingerrcount++;
|
||||||
|
} else {
|
||||||
|
++readingsuccesscount;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (readErr == SDM_ERR_NO_ERROR) {
|
||||||
|
return decodeFloatValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr float res = NAN;
|
||||||
|
return (res);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDM::startReadVal(uint16_t reg, uint8_t node, uint8_t functionCode) {
|
||||||
|
uint8_t data[] = {
|
||||||
|
node, // Address
|
||||||
|
functionCode, // Modbus function
|
||||||
|
highByte(reg), // Start address high byte
|
||||||
|
lowByte(reg), // Start address low byte
|
||||||
|
SDM_B_05, // Number of points high byte
|
||||||
|
SDM_B_06, // Number of points low byte
|
||||||
|
0, // Checksum low byte
|
||||||
|
0}; // Checksum high byte
|
||||||
|
|
||||||
|
constexpr size_t messageLength = sizeof(data) / sizeof(data[0]);
|
||||||
|
modbusWrite(data, messageLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t SDM::readValReady(uint8_t node, uint8_t functionCode) {
|
||||||
uint16_t readErr = SDM_ERR_NO_ERROR;
|
uint16_t readErr = SDM_ERR_NO_ERROR;
|
||||||
|
if (sdmSer.available() < FRAMESIZE && ((millis() - resptime) < msturnaround))
|
||||||
sdmarr[2] = highByte(reg);
|
{
|
||||||
sdmarr[3] = lowByte(reg);
|
return SDM_ERR_STILL_WAITING;
|
||||||
|
}
|
||||||
temp = calculateCRC(sdmarr, FRAMESIZE - 3); //calculate out crc only from first 6 bytes
|
|
||||||
|
|
||||||
sdmarr[6] = lowByte(temp);
|
|
||||||
sdmarr[7] = highByte(temp);
|
|
||||||
|
|
||||||
#if !defined ( USE_HARDWARESERIAL )
|
|
||||||
sdmSer.listen(); //enable softserial rx interrupt
|
|
||||||
#endif
|
|
||||||
|
|
||||||
flush(); //read serial if any old data is available
|
|
||||||
|
|
||||||
dereSet(HIGH); //transmit to SDM -> DE Enable, /RE Disable (for control MAX485)
|
|
||||||
|
|
||||||
delay(2); //fix for issue (nan reading) by sjfaustino: https://github.com/reaper7/SDM_Energy_Meter/issues/7#issuecomment-272111524
|
|
||||||
|
|
||||||
sdmSer.write(sdmarr, FRAMESIZE - 1); //send 8 bytes
|
|
||||||
|
|
||||||
sdmSer.flush(); //clear out tx buffer
|
|
||||||
|
|
||||||
dereSet(LOW); //receive from SDM -> DE Disable, /RE Enable (for control MAX485)
|
|
||||||
|
|
||||||
resptime = millis();
|
|
||||||
|
|
||||||
while (sdmSer.available() < FRAMESIZE) {
|
while (sdmSer.available() < FRAMESIZE) {
|
||||||
if (millis() - resptime > msturnaround) {
|
if ((millis() - resptime) > msturnaround) {
|
||||||
readErr = SDM_ERR_TIMEOUT; //err debug (4)
|
readErr = SDM_ERR_TIMEOUT; //err debug (4)
|
||||||
|
|
||||||
|
if (sdmSer.available() == 5) {
|
||||||
|
for(int n=0; n<5; n++) {
|
||||||
|
sdmarr[n] = sdmSer.read();
|
||||||
|
}
|
||||||
|
if (validChecksum(sdmarr, 5)) {
|
||||||
|
readErr = sdmarr[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
yield();
|
delay(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (readErr == SDM_ERR_NO_ERROR) { //if no timeout...
|
if (readErr == SDM_ERR_NO_ERROR) { //if no timeout...
|
||||||
@ -125,14 +148,10 @@ float SDM::readVal(uint16_t reg, uint8_t node) {
|
|||||||
sdmarr[n] = sdmSer.read();
|
sdmarr[n] = sdmSer.read();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sdmarr[0] == node && sdmarr[1] == SDM_B_02 && sdmarr[2] == SDM_REPLY_BYTE_COUNT) {
|
if (sdmarr[0] == node &&
|
||||||
|
sdmarr[1] == functionCode &&
|
||||||
if ((calculateCRC(sdmarr, FRAMESIZE - 2)) == ((sdmarr[8] << 8) | sdmarr[7])) { //calculate crc from first 7 bytes and compare with received crc (bytes 7 & 8)
|
sdmarr[2] == SDM_REPLY_BYTE_COUNT) {
|
||||||
((uint8_t*)&res)[3]= sdmarr[3];
|
if (!validChecksum(sdmarr, FRAMESIZE)) {
|
||||||
((uint8_t*)&res)[2]= sdmarr[4];
|
|
||||||
((uint8_t*)&res)[1]= sdmarr[5];
|
|
||||||
((uint8_t*)&res)[0]= sdmarr[6];
|
|
||||||
} else {
|
|
||||||
readErr = SDM_ERR_CRC_ERROR; //err debug (1)
|
readErr = SDM_ERR_CRC_ERROR; //err debug (1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,12 +178,95 @@ float SDM::readVal(uint16_t reg, uint8_t node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if !defined ( USE_HARDWARESERIAL )
|
#if !defined ( USE_HARDWARESERIAL )
|
||||||
sdmSer.stopListening(); //disable softserial rx interrupt
|
// sdmSer.stopListening(); //disable softserial rx interrupt
|
||||||
#endif
|
#endif
|
||||||
|
return readErr;
|
||||||
|
}
|
||||||
|
|
||||||
|
float SDM::decodeFloatValue() const {
|
||||||
|
if (validChecksum(sdmarr, FRAMESIZE)) {
|
||||||
|
float res{};
|
||||||
|
((uint8_t*)&res)[3]= sdmarr[3];
|
||||||
|
((uint8_t*)&res)[2]= sdmarr[4];
|
||||||
|
((uint8_t*)&res)[1]= sdmarr[5];
|
||||||
|
((uint8_t*)&res)[0]= sdmarr[6];
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
constexpr float res = NAN;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
float SDM::readHoldingRegister(uint16_t reg, uint8_t node) {
|
||||||
|
startReadVal(reg, node, SDM_READ_HOLDING_REGISTER);
|
||||||
|
|
||||||
|
uint16_t readErr = SDM_ERR_STILL_WAITING;
|
||||||
|
|
||||||
|
while (readErr == SDM_ERR_STILL_WAITING) {
|
||||||
|
delay(1);
|
||||||
|
readErr = readValReady(node, SDM_READ_HOLDING_REGISTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (readErr != SDM_ERR_NO_ERROR) { //if error then copy temp error value to global val and increment global error counter
|
||||||
|
readingerrcode = readErr;
|
||||||
|
readingerrcount++;
|
||||||
|
} else {
|
||||||
|
++readingsuccesscount;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (readErr == SDM_ERR_NO_ERROR) {
|
||||||
|
return decodeFloatValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr float res = NAN;
|
||||||
return (res);
|
return (res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SDM::writeHoldingRegister(float value, uint16_t reg, uint8_t node) {
|
||||||
|
{
|
||||||
|
uint8_t data[] = {
|
||||||
|
node, // Address
|
||||||
|
SDM_WRITE_HOLDING_REGISTER, // Function
|
||||||
|
highByte(reg), // Starting Address High
|
||||||
|
lowByte(reg), // Starting Address Low
|
||||||
|
SDM_B_05, // Number of Registers High
|
||||||
|
SDM_B_06, // Number of Registers Low
|
||||||
|
4, // Byte count
|
||||||
|
((uint8_t*)&value)[3],
|
||||||
|
((uint8_t*)&value)[2],
|
||||||
|
((uint8_t*)&value)[1],
|
||||||
|
((uint8_t*)&value)[0],
|
||||||
|
0, 0};
|
||||||
|
|
||||||
|
constexpr size_t messageLength = sizeof(data) / sizeof(data[0]);
|
||||||
|
modbusWrite(data, messageLength);
|
||||||
|
}
|
||||||
|
uint16_t readErr = SDM_ERR_STILL_WAITING;
|
||||||
|
while (readErr == SDM_ERR_STILL_WAITING) {
|
||||||
|
delay(1);
|
||||||
|
readErr = readValReady(node, SDM_READ_HOLDING_REGISTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (readErr != SDM_ERR_NO_ERROR) { //if error then copy temp error value to global val and increment global error counter
|
||||||
|
readingerrcode = readErr;
|
||||||
|
readingerrcount++;
|
||||||
|
} else {
|
||||||
|
++readingsuccesscount;
|
||||||
|
}
|
||||||
|
|
||||||
|
return readErr == SDM_ERR_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t SDM::getSerialNumber(uint8_t node) {
|
||||||
|
uint32_t res{};
|
||||||
|
readHoldingRegister(SDM_HOLDING_SERIAL_NUMBER, node);
|
||||||
|
// if (getErrCode() == SDM_ERR_NO_ERROR) {
|
||||||
|
for (size_t i = 0; i < 4; ++i) {
|
||||||
|
res = (res << 8) + sdmarr[3 + i];
|
||||||
|
}
|
||||||
|
// }
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
uint16_t SDM::getErrCode(bool _clear) {
|
uint16_t SDM::getErrCode(bool _clear) {
|
||||||
uint16_t _tmp = readingerrcode;
|
uint16_t _tmp = readingerrcode;
|
||||||
if (_clear == true)
|
if (_clear == true)
|
||||||
@ -224,7 +326,7 @@ uint16_t SDM::getMsTimeout() {
|
|||||||
return (mstimeout);
|
return (mstimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t SDM::calculateCRC(uint8_t *array, uint8_t len) {
|
uint16_t SDM::calculateCRC(const uint8_t *array, uint8_t len) const {
|
||||||
uint16_t _crc, _flag;
|
uint16_t _crc, _flag;
|
||||||
_crc = 0xFFFF;
|
_crc = 0xFFFF;
|
||||||
for (uint8_t i = 0; i < len; i++) {
|
for (uint8_t i = 0; i < len; i++) {
|
||||||
@ -241,10 +343,17 @@ uint16_t SDM::calculateCRC(uint8_t *array, uint8_t len) {
|
|||||||
|
|
||||||
void SDM::flush(unsigned long _flushtime) {
|
void SDM::flush(unsigned long _flushtime) {
|
||||||
unsigned long flushstart = millis();
|
unsigned long flushstart = millis();
|
||||||
while (sdmSer.available() || (millis() - flushstart < _flushtime)) {
|
sdmSer.flush();
|
||||||
if (sdmSer.available()) //read serial if any old data is available
|
int available = sdmSer.available();
|
||||||
|
while (available > 0 || ((millis() - flushstart) < _flushtime)) {
|
||||||
|
while (available > 0) {
|
||||||
|
--available;
|
||||||
|
flushstart = millis();
|
||||||
|
//read serial if any old data is available
|
||||||
sdmSer.read();
|
sdmSer.read();
|
||||||
|
}
|
||||||
delay(1);
|
delay(1);
|
||||||
|
available = sdmSer.available();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -252,3 +361,48 @@ void SDM::dereSet(bool _state) {
|
|||||||
if (_dere_pin != NOT_A_PIN)
|
if (_dere_pin != NOT_A_PIN)
|
||||||
digitalWrite(_dere_pin, _state); //receive from SDM -> DE Disable, /RE Enable (for control MAX485)
|
digitalWrite(_dere_pin, _state); //receive from SDM -> DE Disable, /RE Enable (for control MAX485)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SDM::validChecksum(const uint8_t* data, size_t messageLength) const {
|
||||||
|
const uint16_t temp = calculateCRC(data, messageLength - 2); //calculate out crc only from first 6 bytes
|
||||||
|
|
||||||
|
return data[messageLength - 2] == lowByte(temp) &&
|
||||||
|
data[messageLength - 1] == highByte(temp);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDM::modbusWrite(uint8_t* data, size_t messageLength) {
|
||||||
|
const uint16_t temp = calculateCRC(data, messageLength - 2); //calculate out crc only from first 6 bytes
|
||||||
|
|
||||||
|
data[messageLength - 2] = lowByte(temp);
|
||||||
|
data[messageLength - 1] = highByte(temp);
|
||||||
|
|
||||||
|
#if !defined ( USE_HARDWARESERIAL )
|
||||||
|
sdmSer.listen(); //enable softserial rx interrupt
|
||||||
|
#endif
|
||||||
|
|
||||||
|
flush(); //read serial if any old data is available
|
||||||
|
|
||||||
|
if (_dere_pin != NOT_A_PIN) {
|
||||||
|
dereSet(HIGH); //transmit to SDM -> DE Enable, /RE Disable (for control MAX485)
|
||||||
|
|
||||||
|
delay(1); //fix for issue (nan reading) by sjfaustino: https://github.com/reaper7/SDM_Energy_Meter/issues/7#issuecomment-272111524
|
||||||
|
|
||||||
|
// Need to wait for all bytes in TX buffer are sent.
|
||||||
|
// N.B. flush() on serial port does often only clear the send buffer, not wait till all is sent.
|
||||||
|
const unsigned long waitForBytesSent_ms = (messageLength * 11000) / _baud + 1;
|
||||||
|
resptime = millis() + waitForBytesSent_ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
sdmSer.write(data, messageLength); //send 8 bytes
|
||||||
|
|
||||||
|
if (_dere_pin != NOT_A_PIN) {
|
||||||
|
const int32_t timeleft = (int32_t) (resptime - millis());
|
||||||
|
if (timeleft > 0) {
|
||||||
|
delay(timeleft); //clear out tx buffer
|
||||||
|
}
|
||||||
|
dereSet(LOW); //receive from SDM -> DE Disable, /RE Enable (for control MAX485)
|
||||||
|
flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
resptime = millis();
|
||||||
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
/* Library for reading SDM 72/120/220/230/630 Modbus Energy meters.
|
/* Library for reading SDM 72/120/220/230/630 Modbus Energy meters.
|
||||||
* Reading via Hardware or Software Serial library & rs232<->rs485 converter
|
* Reading via Hardware or Software Serial library & rs232<->rs485 converter
|
||||||
* 2016-2022 Reaper7 (tested on wemos d1 mini->ESP8266 with Arduino 1.8.10 & 2.5.2 esp8266 core)
|
* 2016-2023 Reaper7 (tested on wemos d1 mini->ESP8266 with Arduino 1.8.10 & 2.5.2 esp8266 core)
|
||||||
* crc calculation by Jaime García (https://github.com/peninquen/Modbus-Energy-Monitor-Arduino/)
|
* crc calculation by Jaime García (https://github.com/peninquen/Modbus-Energy-Monitor-Arduino/)
|
||||||
*/
|
*/
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@ -66,36 +66,47 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined ( WAITING_TURNAROUND_DELAY )
|
#if !defined ( WAITING_TURNAROUND_DELAY )
|
||||||
#define WAITING_TURNAROUND_DELAY 200 // time in ms to wait for process current request
|
#define WAITING_TURNAROUND_DELAY 500 // time in ms to wait for process current request
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined ( RESPONSE_TIMEOUT )
|
#if !defined ( RESPONSE_TIMEOUT )
|
||||||
#define RESPONSE_TIMEOUT 500 // time in ms to wait for return response from all devices before next request
|
#define RESPONSE_TIMEOUT 10 // time in ms to wait for return response from all devices before next request
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined ( SDM_MIN_DELAY )
|
#if !defined ( SDM_MIN_DELAY )
|
||||||
#define SDM_MIN_DELAY 20 // minimum value (in ms) for WAITING_TURNAROUND_DELAY and RESPONSE_TIMEOUT
|
#define SDM_MIN_DELAY 1 // minimum value (in ms) for WAITING_TURNAROUND_DELAY and RESPONSE_TIMEOUT
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined ( SDM_MAX_DELAY )
|
#if !defined ( SDM_MAX_DELAY )
|
||||||
#define SDM_MAX_DELAY 5000 // maximum value (in ms) for WAITING_TURNAROUND_DELAY and RESPONSE_TIMEOUT
|
#define SDM_MAX_DELAY 20 // maximum value (in ms) for WAITING_TURNAROUND_DELAY and RESPONSE_TIMEOUT
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
#define SDM_ERR_NO_ERROR 0 // no error
|
#define SDM_ERR_NO_ERROR 0 // no error
|
||||||
#define SDM_ERR_CRC_ERROR 1 // crc error
|
#define SDM_ERR_ILLEGAL_FUNCTION 1
|
||||||
#define SDM_ERR_WRONG_BYTES 2 // bytes b0,b1 or b2 wrong
|
#define SDM_ERR_ILLEGAL_DATA_ADDRESS 2
|
||||||
#define SDM_ERR_NOT_ENOUGHT_BYTES 3 // not enough bytes from sdm
|
#define SDM_ERR_ILLEGAL_DATA_VALUE 3
|
||||||
#define SDM_ERR_TIMEOUT 4 // timeout
|
#define SDM_ERR_SLAVE_DEVICE_FAILURE 5
|
||||||
|
|
||||||
|
#define SDM_ERR_CRC_ERROR 11 // crc error
|
||||||
|
#define SDM_ERR_WRONG_BYTES 12 // bytes b0,b1 or b2 wrong
|
||||||
|
#define SDM_ERR_NOT_ENOUGHT_BYTES 13 // not enough bytes from sdm
|
||||||
|
#define SDM_ERR_TIMEOUT 14 // timeout
|
||||||
|
#define SDM_ERR_EXCEPTION 15
|
||||||
|
#define SDM_ERR_STILL_WAITING 16
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#define SDM_READ_HOLDING_REGISTER 0x03
|
||||||
|
#define SDM_READ_INPUT_REGISTER 0x04
|
||||||
|
#define SDM_WRITE_HOLDING_REGISTER 0x10
|
||||||
|
|
||||||
#define FRAMESIZE 9 // size of out/in array
|
#define FRAMESIZE 9 // size of out/in array
|
||||||
#define SDM_REPLY_BYTE_COUNT 0x04 // number of bytes with data
|
#define SDM_REPLY_BYTE_COUNT 0x04 // number of bytes with data
|
||||||
|
|
||||||
#define SDM_B_01 0x01 // BYTE 1 -> slave address (default value 1 read from node 1)
|
#define SDM_B_01 0x01 // BYTE 1 -> slave address (default value 1 read from node 1)
|
||||||
#define SDM_B_02 0x04 // BYTE 2 -> function code (default value 0x04 read from 3X input registers)
|
#define SDM_B_02 SDM_READ_INPUT_REGISTER // BYTE 2 -> function code (default value 0x04 read from 3X input registers)
|
||||||
#define SDM_B_05 0x00 // BYTE 5
|
#define SDM_B_05 0x00 // BYTE 5
|
||||||
#define SDM_B_06 0x02 // BYTE 6
|
#define SDM_B_06 0x02 // BYTE 6
|
||||||
// BYTES 3 & 4 (BELOW)
|
// BYTES 3 & 4 (BELOW)
|
||||||
@ -151,6 +162,8 @@
|
|||||||
#define SDM_MAXIMUM_TOTAL_SYSTEM_VA_DEMAND 0x0066 // VA | 1 | | | | | | |
|
#define SDM_MAXIMUM_TOTAL_SYSTEM_VA_DEMAND 0x0066 // VA | 1 | | | | | | |
|
||||||
#define SDM_NEUTRAL_CURRENT_DEMAND 0x0068 // A | 1 | | | | | | |
|
#define SDM_NEUTRAL_CURRENT_DEMAND 0x0068 // A | 1 | | | | | | |
|
||||||
#define SDM_MAXIMUM_NEUTRAL_CURRENT 0x006A // A | 1 | | | | | | |
|
#define SDM_MAXIMUM_NEUTRAL_CURRENT 0x006A // A | 1 | | | | | | |
|
||||||
|
#define SDM_REACTIVE_POWER_DEMAND 0x006C // VAr | 1 | | | | | | |
|
||||||
|
#define SDM_MAXIMUM_REACTIVE_POWER_DEMAND 0x006E // VAr | 1 | | | | | | |
|
||||||
#define SDM_LINE_1_TO_LINE_2_VOLTS 0x00C8 // V | 1 | | | | | | 1 |
|
#define SDM_LINE_1_TO_LINE_2_VOLTS 0x00C8 // V | 1 | | | | | | 1 |
|
||||||
#define SDM_LINE_2_TO_LINE_3_VOLTS 0x00CA // V | 1 | | | | | | 1 |
|
#define SDM_LINE_2_TO_LINE_3_VOLTS 0x00CA // V | 1 | | | | | | 1 |
|
||||||
#define SDM_LINE_3_TO_LINE_1_VOLTS 0x00CC // V | 1 | | | | | | 1 |
|
#define SDM_LINE_3_TO_LINE_1_VOLTS 0x00CC // V | 1 | | | | | | 1 |
|
||||||
@ -199,7 +212,10 @@
|
|||||||
#define SDM_CURRENT_RESETTABLE_TOTAL_REACTIVE_ENERGY 0x0182 // kVArh | | 1 | | | | | |
|
#define SDM_CURRENT_RESETTABLE_TOTAL_REACTIVE_ENERGY 0x0182 // kVArh | | 1 | | | | | |
|
||||||
#define SDM_CURRENT_RESETTABLE_IMPORT_ENERGY 0x0184 // kWh | | | | | | 1 | 1 |
|
#define SDM_CURRENT_RESETTABLE_IMPORT_ENERGY 0x0184 // kWh | | | | | | 1 | 1 |
|
||||||
#define SDM_CURRENT_RESETTABLE_EXPORT_ENERGY 0x0186 // kWh | | | | | | 1 | 1 |
|
#define SDM_CURRENT_RESETTABLE_EXPORT_ENERGY 0x0186 // kWh | | | | | | 1 | 1 |
|
||||||
|
#define SDM_CURRENT_RESETTABLE_IMPORT_REACTIVE_ENERGY 0x0188 // kVArh | | | | | | 1 | 1 |
|
||||||
|
#define SDM_CURRENT_RESETTABLE_EXPORT_REACTIVE_ENERGY 0x018A // kVArh | | | | | | 1 | 1 |
|
||||||
#define SDM_NET_KWH 0x018C // kWh | | | | | | | 1 |
|
#define SDM_NET_KWH 0x018C // kWh | | | | | | | 1 |
|
||||||
|
#define SDM_NET_KVARH 0x018E // kVArh | | | | | | | 1 |
|
||||||
#define SDM_IMPORT_POWER 0x0500 // W | | | | | | 1 | 1 |
|
#define SDM_IMPORT_POWER 0x0500 // W | | | | | | 1 | 1 |
|
||||||
#define SDM_EXPORT_POWER 0x0502 // W | | | | | | 1 | 1 |
|
#define SDM_EXPORT_POWER 0x0502 // W | | | | | | 1 | 1 |
|
||||||
//---------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
@ -229,6 +245,78 @@
|
|||||||
//#define DEVNAME_POWER 0x0004 // W | 1 |
|
//#define DEVNAME_POWER 0x0004 // W | 1 |
|
||||||
//---------------------------------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------
|
||||||
|
// REGISTERS LIST FOR DEVICE SETTINGS |
|
||||||
|
//---------------------------------------------------------------------------------------------------------
|
||||||
|
// REGISTER NAME REGISTER ADDRESS UNIT | DEVNAME |
|
||||||
|
//---------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Read minutes into first demand calculation.
|
||||||
|
// When the Demand Time reaches the Demand Period
|
||||||
|
// then the demand values are valid.
|
||||||
|
#define SDM_HOLDING_DEMAND_TIME 0x0000
|
||||||
|
|
||||||
|
// Write demand period: 0~60 minutes.
|
||||||
|
// Default 60.
|
||||||
|
// Range: 0~60, 0 means function disabled
|
||||||
|
#define SDM_HOLDING_DEMAND_PERIOD 0x0002
|
||||||
|
|
||||||
|
// Write relay on period in milliseconds:
|
||||||
|
// 60, 100 or 200 ms.
|
||||||
|
// default: 100 ms
|
||||||
|
#define SDM_HOLDING_RELAY_PULSE_WIDTH 0x000C
|
||||||
|
|
||||||
|
// Parity / stop bit settings:
|
||||||
|
// 0 = One stop bit and no parity, default.
|
||||||
|
// 1 = One stop bit and even parity.
|
||||||
|
// 2 = One s top bit and odd parity.
|
||||||
|
// 3 = Two stop bits and no parity.
|
||||||
|
// Requires a restart to become effective.
|
||||||
|
#define SDM_HOLDING_NETWORK_PARITY_STOP 0x0012
|
||||||
|
|
||||||
|
// Ranges from 1 to 247. Default ID is 1.
|
||||||
|
#define SDM_HOLDING_METER_ID 0x0014
|
||||||
|
|
||||||
|
// Write the network port baud rate for MODBUS Protocol, where:
|
||||||
|
/*
|
||||||
|
SDM120 / SDM230:
|
||||||
|
0 = 2400 baud (default)
|
||||||
|
1 = 4800 baud
|
||||||
|
2 = 9600 baud
|
||||||
|
5 = 1200 baud
|
||||||
|
|
||||||
|
SDM320 / SDM530Y:
|
||||||
|
0 = 2400 baud
|
||||||
|
1 = 4800 baud
|
||||||
|
2 = 9600 baud (default)
|
||||||
|
5 = 1200 band
|
||||||
|
|
||||||
|
SDM630 / SDM72 / SDM72V2:
|
||||||
|
0 = 2400 baud
|
||||||
|
1 = 4800 baud
|
||||||
|
2 = 9600 baud (default)
|
||||||
|
3 = 19200 baud
|
||||||
|
4 = 38400 baud
|
||||||
|
*/
|
||||||
|
#define SDM_HOLDING_BAUD_RATE 0x001C
|
||||||
|
|
||||||
|
// Write MODBUS Protocol input parameter for pulse out 1:
|
||||||
|
// 1: Import active energy
|
||||||
|
// 2: Import + export (total) active energy
|
||||||
|
// 4: Export active energy (default).
|
||||||
|
// 5: Import reactive energy
|
||||||
|
// 6: Import + export (total) reactive energy
|
||||||
|
// 8: Export reactive energy
|
||||||
|
#define SDM_HOLDING_PULSE_1_OUTPUT_MODE 0x0056
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define SDM_HOLDING_SERIAL_NUMBER 0xFC00
|
||||||
|
#define SDM_HOLDING_SOFTWARE_VERSION 0xFC03
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------------------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
class SDM {
|
class SDM {
|
||||||
@ -252,6 +340,16 @@ class SDM {
|
|||||||
|
|
||||||
void begin(void);
|
void begin(void);
|
||||||
float readVal(uint16_t reg, uint8_t node = SDM_B_01); // read value from register = reg and from deviceId = node
|
float readVal(uint16_t reg, uint8_t node = SDM_B_01); // read value from register = reg and from deviceId = node
|
||||||
|
void startReadVal(uint16_t reg, uint8_t node = SDM_B_01, uint8_t functionCode = SDM_B_02); // Start sending out the request to read a register from a specific node (allows for async access)
|
||||||
|
uint16_t readValReady(uint8_t node = SDM_B_01, uint8_t functionCode = SDM_B_02); // Check to see if a reply is ready reading from a node (allow for async access)
|
||||||
|
float decodeFloatValue() const;
|
||||||
|
|
||||||
|
float readHoldingRegister(uint16_t reg, uint8_t node = SDM_B_01);
|
||||||
|
bool writeHoldingRegister(float value, uint16_t reg, uint8_t node = SDM_B_01);
|
||||||
|
|
||||||
|
uint32_t getSerialNumber(uint8_t node = SDM_B_01);
|
||||||
|
|
||||||
|
|
||||||
uint16_t getErrCode(bool _clear = false); // return last errorcode (optional clear this value, default flase)
|
uint16_t getErrCode(bool _clear = false); // return last errorcode (optional clear this value, default flase)
|
||||||
uint32_t getErrCount(bool _clear = false); // return total errors count (optional clear this value, default flase)
|
uint32_t getErrCount(bool _clear = false); // return total errors count (optional clear this value, default flase)
|
||||||
uint32_t getSuccCount(bool _clear = false); // return total success count (optional clear this value, default false)
|
uint32_t getSuccCount(bool _clear = false); // return total success count (optional clear this value, default false)
|
||||||
@ -264,6 +362,11 @@ class SDM {
|
|||||||
uint16_t getMsTimeout(); // get current value of RESPONSE_TIMEOUT (ms)
|
uint16_t getMsTimeout(); // get current value of RESPONSE_TIMEOUT (ms)
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
bool validChecksum(const uint8_t* data, size_t messageLength) const;
|
||||||
|
|
||||||
|
void modbusWrite(uint8_t* data, size_t messageLength);
|
||||||
|
|
||||||
#if defined ( USE_HARDWARESERIAL )
|
#if defined ( USE_HARDWARESERIAL )
|
||||||
HardwareSerial& sdmSer;
|
HardwareSerial& sdmSer;
|
||||||
#else
|
#else
|
||||||
@ -292,7 +395,9 @@ class SDM {
|
|||||||
uint16_t mstimeout = RESPONSE_TIMEOUT;
|
uint16_t mstimeout = RESPONSE_TIMEOUT;
|
||||||
uint32_t readingerrcount = 0; // total errors counter
|
uint32_t readingerrcount = 0; // total errors counter
|
||||||
uint32_t readingsuccesscount = 0; // total success counter
|
uint32_t readingsuccesscount = 0; // total success counter
|
||||||
uint16_t calculateCRC(uint8_t *array, uint8_t len);
|
unsigned long resptime = 0;
|
||||||
|
uint8_t sdmarr[FRAMESIZE] = {};
|
||||||
|
uint16_t calculateCRC(const uint8_t *array, uint8_t len) const;
|
||||||
void flush(unsigned long _flushtime = 0); // read serial if any old data is available or for a given time in ms
|
void flush(unsigned long _flushtime = 0); // read serial if any old data is available or for a given time in ms
|
||||||
void dereSet(bool _state = LOW); // for control MAX485 DE/RE pins, LOW receive from SDM, HIGH transmit to SDM
|
void dereSet(bool _state = LOW); // for control MAX485 DE/RE pins, LOW receive from SDM, HIGH transmit to SDM
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
/* Library for reading SDM 72/120/220/230/630 Modbus Energy meters.
|
/* Library for reading SDM 72/120/220/230/630 Modbus Energy meters.
|
||||||
* Reading via Hardware or Software Serial library & rs232<->rs485 converter
|
* Reading via Hardware or Software Serial library & rs232<->rs485 converter
|
||||||
* 2016-2022 Reaper7 (tested on wemos d1 mini->ESP8266 with Arduino 1.8.10 & 2.5.2 esp8266 core)
|
* 2016-2023 Reaper7 (tested on wemos d1 mini->ESP8266 with Arduino 1.8.10 & 2.5.2 esp8266 core)
|
||||||
* crc calculation by Jaime García (https://github.com/peninquen/Modbus-Energy-Monitor-Arduino/)
|
* crc calculation by Jaime García (https://github.com/peninquen/Modbus-Energy-Monitor-Arduino/)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -32,7 +32,7 @@
|
|||||||
#if defined ( USE_HARDWARESERIAL )
|
#if defined ( USE_HARDWARESERIAL )
|
||||||
#if defined ( ESP32 )
|
#if defined ( ESP32 )
|
||||||
#define SDM_RX_PIN 13
|
#define SDM_RX_PIN 13
|
||||||
#define SDM_TX_PIN 32
|
#define SDM_TX_PIN 15
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
#if defined ( ESP8266 ) || defined ( ESP32 )
|
#if defined ( ESP8266 ) || defined ( ESP32 )
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user