bertmelis / esp32ModbusRTU

modbus RTU client for ESP32
MIT License
70 stars 44 forks source link

Write single register example? #22

Closed zekageri closed 4 years ago

zekageri commented 4 years ago

Can this be done just like this?

In ModbusMessage.cpp :

ModbusRequest06::ModbusRequest06(uint8_t slaveAddress, uint16_t address, uint16_t value) :
  ModbusRequest(8) {
  _slaveAddress = slaveAddress;
  _functionCode = esp32Modbus::WRITE_HOLD_REGISTER;
  _address = address;
  _byteCount = value * 2;  // register is 2 bytes wide
  add(_slaveAddress);
  add(_functionCode);
  add(high(_address));
  add(low(_address));
  add(high(value));
  add(low(value));
  uint16_t CRC = CRC16(_buffer, 6);
  add(low(CRC));
  add(high(CRC));
}

size_t ModbusRequest06::responseLength() {
  return 6;
}

In ModbusMessage.h :

// write single holding registers
class ModbusRequest06 : public ModbusRequest {
 public:
  explicit ModbusRequest06(uint8_t slaveAddress, uint16_t address, uint16_t value);
  size_t responseLength();
};

In esp32ModbusRTU.cpp :

bool esp32ModbusRTU::writeSingleHoldingRegisters(uint8_t slaveAddress, uint16_t address, uint16_t value) {
  ModbusRequest* request = new ModbusRequest06(slaveAddress, address, value);
  return _addToQueue(request);
}
bertmelis commented 4 years ago

Isn't the response 8 bytes long? slaveAddress (1) + functionCode (1) + address (2) + data (2) + CRC (2)

size_t ModbusRequest06::responseLength() {
  return 8;
}
bertmelis commented 4 years ago

Oh, and I would drop the s and the end of writeSingleHoldingRegisters.

Am I autistic?

zekageri commented 4 years ago

Oh, and I would drop the s and the end of writeSingleHoldingRegisters.

Am I autistic?

Thats true. It's just one register. :'D But can it work? Oh and whats up with the multi registers? I tought that i have to write the low and the high bytes to the data. Like this:

// multireg       addr  funkc regH  regL  regDH regDL byD  adatH adatL  CRCH  CRCL */
byte message[] = {0x0A, 0x10, 0x40, 0x32, 0x00, 0x01, 0x02, 0xFF, 0xFF, 0x91, 0x06};

I have a modbus io expander, and if i use the multi register like this:

uint8_t   Slave_Address = 0xA;
uint16_t  Start_Reg_Address = 0x4032;
uint16_t  Reg_Count = 0x0001;
uint8_t   Data_to_Write = 0x00;
 modbus.writeMultHoldingRegisters(Slave_Address,Start_Reg_Address,Reg_Count,&Data_to_Write);

I want to write a 255 to all the output pins in a register but if i use it like this, i get half of the outputs on. How i supposed to write a low and a high byte with multi regs?

bertmelis commented 4 years ago

You're writing 1 register. One register is 2 bytes wide. So your Data_to_Write should be 2 bytes long.

Try this:

uint8_t   Slave_Address = 0xA;
uint16_t  Start_Reg_Address = 0x4032;
uint16_t  Reg_Count = 0x0001;
uint8_t   Data_to_Write[2] = {0x00, 0x00};
 modbus.writeMultHoldingRegisters(Slave_Address,Start_Reg_Address,Reg_Count,Data_to_Write);

So your data is an array of bytes (uint8_t). The array length has to be the number of bytes you're going to write. (number of bytes = number of registers x 2)

bertmelis commented 4 years ago

ModbusMessage.h

// write single holding registers
class ModbusRequest06 : public ModbusRequest {
 public:
  explicit ModbusRequest06(uint8_t slaveAddress, uint16_t address, uint16_t data);
  size_t responseLength();
};

ModbusMessage.cpp

ModbusRequest06::ModbusRequest06(uint8_t slaveAddress, uint16_t address, uint16_t data) :
  ModbusRequest(8) {
  _slaveAddress = slaveAddress;
  _functionCode = esp32Modbus::WRITE_HOLD_REGISTER;
  _address = address;
  _byteCount = 2;  // 1 register is 2 bytes wide
  add(_slaveAddress);
  add(_functionCode);
  add(high(_address));
  add(low(_address));
  add(high(data));
  add(low(data));
  uint16_t CRC = CRC16(_buffer, 6);
  add(low(CRC));
  add(high(CRC));
}

size_t ModbusRequest06::responseLength() {
  return 8;
}

esp32ModbusRTU.h ...add declaration...

esp32ModbusRTU.cpp

bool esp32ModbusRTU::writeSingleHoldingRegister(uint8_t slaveAddress, uint16_t address, uint16_t data) {
  ModbusRequest* request = new ModbusRequest06(slaveAddress, address, data);
  return _addToQueue(request);
}

Usage

uint8_t   Slave_Address = 0xA;
uint16_t  Start_Reg_Address = 0x4032;
uint16_t  Reg_Count = 0x0001;
uint8_t   Data_to_Write[2] = {0x00, 0x00};
 modbus.writeMultHoldingRegisters(Slave_Address,Start_Reg_Address,Reg_Count,Data_to_Write);

If it works, feel free to create a PR.

zekageri commented 4 years ago

The multi reg write is working properly like this. Thank you for the suggestion. I don't tried the single register yet.

bertmelis commented 4 years ago

Oh, I mixed up multi and single. Should work both.