MODBus - register usage

Usually the MODBUS protocoll only supports registers based on 16-bit values. If you want to transfer custom datatypes like double, float etc. via the modbus a simple trick can be used.

My solution for variable datatypes is simple.

  1. Define a c-type
  2. Initialize the modbus using this datatype

Below you can find sample code for the client as well as for the master side.

Define datatype

#ifndef _MB_SlaveData3_H
#define _MB_SlaveData3_H
typedef struct {
  double       waterTemp;
  unsigned int waterLevel;
  unsigned int waterLevelRaw;
  unsigned int chipVcc;
  unsigned int chipTemp;
}
t_MB_SlaveData3;
#endif

Initialize MODBUS

Slave side

#include <MB_SlaveData3.h>
t_MB_SlaveData3 modBusRegisters;

void setup() {
modbus_configure(MODBUS_BAUD, MODBUS_SLAVE_ID, MODBUS_TXENABLEPIN, sizeof modBusRegisters / sizeof (unsigned int) );

Master side

#include <MB_SlaveData3.h>

// This is the easiest way to create new packets
// Add as many as you want. TOTAL_NO_OF_PACKETS
// is automatically updated.
enum
{
  PACKET1,
  // leave this last entry
  TOTAL_NO_OF_PACKETS,
};
// this is my custom datatype transfered via modbus
t_MB_SlaveData3 modbusSlave1;

// Create an array of Packets for modbus_update()
Packet packets[TOTAL_NO_OF_PACKETS];
// Create a packetPointer to access each packet
// individually. This is not required you can access
// the array explicitly. E.g. packets[PACKET1].id = 2;
// This does become tedious though...
packetPointer packet1 = &packets[PACKET1];

void modbus_setup(void) {
  packet1->id = 1;
  packet1->function = READ_HOLDING_REGISTERS;
  packet1->address = 0;
  packet1->no_of_registers = sizeof (modbusSlave1) / sizeof (unsigned int);
  packet1->register_array = (unsigned int*) &modbusSlave1;
  packet1->packetReceived = 0;

  // Initialize communication settings etc...
  modbus_configure(MODBUS_BAUD, MODBUS_TIMEOUT, MODBUS_POLLING, MODBUS_RETRYCOUNT, MODBUS_TXENABLEPIN, packets, TOTAL_NO_OF_PACKETS);
}