Connecting to Modbus slave

One of the most common thing todo in industrial automation, is setting up the communication via Modbus.

Unipi 1.1

Let's assume you have a basic project in Full mode. You are attached to the controller, you have created Executable project with one FBD program and this program is set in PLC's Tasks. You also did a Set Autogen on the UniPi controller, and the Build and Deploy works without any problem.

If you have done so, your workspace should look like this:

To set the communication via ModbusRTU, you need to create appropriate channel. Right click on PLC and in the context menu, click on Add Channel.

A new channel called Channel will appear under the PLC on the Left panel. Select it and in the Properties panel, change the name to something more descriptive. Since this channel will be for communication via ModbusRTU, the ModbusRTU is a good name.

On the same panel, select Modbus protocol from the dropdown menu.

The default Link Protocol is set to Serial, so all you need to do, is to set the correct Serial Line Parameters. Pick the correct port from the Port Number dropdown.

The rest of the Serial Line Parameters need to by exactly the same, as is configured on all the devices you have on the serial bus.

The ModbusRTU channel is configured and now we can add devices with which we want to communicate. Right click on the channel in the Left panel and in the context menu, select the Add Device.

A new device will appear under the channel. Select it and change its name in the Properties panel to something more descriptive. In this properties, you also need to enter the correct Modbus device address.

The name shouldn't be just the manufacturer's name and model, but rather the purpose or location of the device. If you have distribution box full of energy meters, it is better to name each energy meter by the circuit it is measuring, e.g. energyMeterL1.

The basic configuration of the ModbusRTU device is done, now we can dive into much more complicated stuff - the register map. Double click on the name of the newly added device. In the Main window an empty list of Modbus registers will appear.

The values in Modbus slave devices are “shared” via registers (a strictly 16 bit values) or coils (strictly 1 bit statuses). In order to acquire these values from the slaves, we need to define, which registers we want to read and possibly, how to transform them into variables, which we can later use in our program.

It is time to introduce our ModbusRTU device, from which we want to read the data: The Inepro PRO1-Mod energy meter.

It is good thing to start with reading the manual. We already used an information from the manual - the speed and configuration of the serial line - 9600 bps with 8 data bits, even parity and 1 stop bit. The default Modbus ID is according to manual 1, but our meter has 31. In the manual, you can also find out how to get this number from the meter itself.

On the page 25 you can find the complete list of Modbus registers - their addresses, values and sizes. We will start with acquiring current voltage.

Unfortunately, this is where it starts to be really complicated, mostly due to the various ways of how the Modbus protocol is implemented by different vendors.

As you can see, the register's addresses are in hexadecimal format. You can't tell from the Voltage register, because the address of 5000 could be both in hexadecimal and decimal format. But if you take a look on the Current register, the value 500 A clearly shows it is in hexadecimal format.

The Mervis IDE accepts only decimal values for Modbus registers, so you need to manually convert the ones from the manual, e.g. with calculator application in Windows or in MS Excel.

Another tricky part is the register's number vs. register's address. The register numbers start from 1, but register addresses start from 0. The Mervis IDE uses the register's number, but in the Inepro manual, they use register address.

To sum up both problems - the Voltage register's address is 5000 hexadecimal, which is 20480 in decimal and the register's number is 20481 (address + 1).

In many cases, it is hard to distinguish and reading a manual is simply not enough. You will have to resort to trial-and-error approach.

Let's take a look how to add the Voltage register to the Mervis. You should see the empty list of registers on the Main window. If not, double click on the name of the device on the Left panel.

To acquire value of some register, we need to add a Group first. The group is a holder of at least one register, which can be read at once and then parsed into datapoints. This follows the way of how the Modbus works, especially the function code 3. Right click on the Main window and from context menu select Add Group.

A new group called Group will appear and also three other datapoints were created. Click on the row with name Group and in the Properties panel, change the Name to something more descriptive. We picked the range of original addresses according to the manual (5000-5000B). In the Modbus Group Parameters we need to specify the number of the first register, or as it is called here Starting Element. As we calculated above, the Starting Element for register Voltage is 20481. The Modbus function is F03 Read Holding Registers. The Quantity of Elements is a number of registers we want to read from the slave device into this group for later processing into datapoints. Select 12, because we want to read the Voltage, Grid frequency and Current at once.

To process the group of acquired registers into variables, we need to define a datapoint. Right click on the empty space in Main window and in the context menu select the Add Data Point.

A new datapoint called IO will appear in the list. Select it and change its name to Voltage in the Properties panel.

Next thing you need to specify is the Group into which this datapoint belongs to. Select our group 5000-500B from the dropdown menu of the Group parameter.

Datapoint will be represented by a variable and the variable needs to have some type. Since voltage is usually a real number, select the Builtin option from the Comm. Value Mapped Type dropdown.

And from the ST Type dropdown select the real option.

To skip some complicated explanations, just fill the number 4 into the Multibyte Length (Parser). We will get to this later.

Now we that we defined new datapoint, we need to generate the variables by Set Autogen functionality. Right click on the device in the Left panel and in the context menu, select the Set Autogen.

A Set Autogen dialog will appear and you can confirm it as is by clickin on OK.

Now you can Build and Deploy the solution. If everything goes well and the program is running, turn on the Debugging. Then switch to the Variable Browser tab in the Main window and under the name, search for the voltage. The only variable that should show up should be our datapoint with up-to-date information about the line's voltage.

To be able to continue with the tutorial, you need to fully understand, what we did with the Voltage and how to represent different data types in Modbus.

The Modbus knows only 16 bit registers (forget about the “coils” for now). Therefor in one register, we can store only 65536 values. Those values can represent different types of numbers. It can represent unsigned integer number from 0-65535. It can represent signed integer from -32768 to 32767. Or we don't need to use all the possible values and covert it directly to “char” number with values 0-255. But if you need to exchange data type with slave, which needs more then 16 bit of space, you need to use more than 1 Modbus register and then do the transformation of data in the Mervis. This is what we did with the Voltage. The Voltage is a real number which needs 32 bit space. In the Inepro manual, you can see the data type is “float” and the register's length is 2. This doesn't mean the register has different size other than 16 bit, but rather tells us the Voltage is stored in 2 registers - on address 5000H and 5001H. In order to recreate the value in Mervis, we had to read 2 registers and put them together into one variable.

This parsing of multiple registers into datapoint (variable) is done on two levels. First, we need to tell the Mervis to read more registers at once. This is done on the Group level. We specified the first register number we want to read (the Starting Element) and the number of registers we want to read from this number (the Quantity of Elements). As you can check above, we started reading from the register number 20481 and we read 12 consecutive 16 bit registers = 24 bytes.

Next thing we did, is that we specified the Voltage datapoint. We pointed this datapoint to the group, so it will be taking data from this group and transform it to some variable. To tell exactly, which data from the group the datapoint should use, we configured the Modbus Data Point Parameters. For reading data from group to datapoint, you need to set the Data Offset (Parser) and the Multibyte Length (Parser).

The Data Offset (Parser) indicates the first byte (not register!) from the group, and the Multibyte Length (Parser) is a number of bytes to parse into this variable. As you can check, we selected first 4 bytes from the group (Data Offset = 0, Multibyte Length = 4), which corresponds with 2 registers (4*8 bit = 2*16 bit). And by setting the ST Type, we set the transformation of this 32 bit data space into a real number. It sounds a quite complicated, but with next datapoint, it will be a bit clearer hopefully.

So let's add another datapoint - Grid frequency. As you can see from the Modbus register's map, the Grid frequency is on the address 5008 and the register's length (more like value length) is 2. We know, we already have the group 5000-500B configured to cover these registers as well, therefor we can define the datapoint directly. Right click on the free space on the tab energyMeterL1 on the Main window and from the context menu select Add Data Point. A new datapoint will appear and you can change its properties. The result should look like this:

  • We named the datapoint GridFrequency
  • We specified to take data from group 5000-500B
  • The Comm. Value Mapped Type is Builtin and the ST Type is real
  • The Data Offset (Parser) = (address of the register - address of the first register in group) * 2 = (5008H-5000H) * 2 = 16
  • The MultiByte Length (Parser) is 4 (4 bytes = 2 16 bit registers)

Because we added new datapoint, you need to run the Set Autogen on the device. Then Deploy the solution, turn on the Debugging mode and switch to Variable Browser tab in Main window. In the browser, search for the energyMeterL1. You should see this: