Once you understand how the PLC's memory is structured and how the variable addresses work to store their values in a desired place (see previous article), you can try to use the MODBUS protocol. It is an industry standard for a communication between various systems. It can be used for connecting a HMI panel to your PLC, connecting a 1-wire module or connecting the PLC to your PC...
WARNING! All that you find here is an amateur attempt to cover a complex subject with a simple mind. I ask the experts to have understanding. Unfortunately none of the 'professional' descriptions of the protocol was understandable to me. What you see below is a composition of bits an pieces found on random sites.
The MODBUS communication is done by executing 'functions'. They can be split into two main categories: 1st for bit (BOOL) variables and the 2nd for WORD. Then that distinction can be split again into variables, which are read-only and those which can be overwritten.
Here is a table which shows the split of the main MODBUS functions:
Read/Write | Read only | |
BIT/BOOL |
FC1 - Read Coil |
FC2 - Read Discrete Input |
WORD |
FC3 - Read Holding Register |
FC4 - Read Input Registers |
To be honest, I do not like those function names. I do not know why a 'coil' or a 'discrete input'. What matters is that in order to read a single bit I can use FC1 or FC2, to write it - FC5 or FC15; for WORD values the functions are: FC3, FC4 for reading and FC6, FC16 or FC23 to write. That's all.
To clarify - MODBUS can let you read or modify some areas of your PLC's memory. It does not accept commands like "turn on the lights" or "show me the temperature". To do that you need to reach for a specific part of the PLC's memory and interpret it.
Now it is time to understand how the addresses of MODBUS protocol fit the map of addresses in PLC's memory. In the PLC manual one can find a whole chapter titled "MODBUS Register Mapping". You can find there tables showing the link between MODBUS and WAGO controllers.
In case of reading/writing single bits (functions FC1, FC2 and FC5) the following values need to be used. In case of digital ins or outs (DI or DO) one need to know their consecutive number, not their address in PLC's memory:
Address MODBUS [dec] | Memory range | Description |
0...511 |
Physical inputs |
First 512 digital inputs |
512...1023 |
Physical outputs |
First 512 digital outputs |
12288...32767 |
%MX0...%MX1279.15 |
NOVRAM |
For WORD variables (functions FC3 i FC4):
Adres MODBUS [dec] | Memory range | Description |
0...255 |
%IW0...%IW255 |
Physical input area |
512...767 |
%QW0...%QW255 |
Physical output area |
12288...24575 |
%MW0...%MW12287 |
NOVRAM |
So, let's look at some examples:
Writing values is very similar. One just has to remember that PLC's inputs are read-only.
Now it is time for a specific example from my PLC:
The input IN4 is the 4th physical input in my PLC, while the OUT 3 is the third. Quite distant addresses in the memory (%IX11.2 i QX3.2) are the consequence of additional modules using the first areas of the memory - in my case the analog sensors and RS232 communication module.
Example MODBUS commands:
MODBUS | equivalent to WAGO WebServer | Reply |
FC2 3 (to get the 4th input) |
READPI?ADR=IX11.3&FORMAT=%x |
TRUE |
FC1 514 (to get the 3rd output) |
READPI?ADR=QX3.2&FORMAT=%x |
TRUE |
FC4 11 |
READPI?ADR1=IW11&FORMAT=%d |
8 |
FC5 515 |
READPI?ADR1=QW3&FORMAT=%d |
204 |
How to check it all? One possibility is to use a phpmodbus library available at https://code.google.com/p/phpmodbus/. It integrates MODBUS functionality into PHP.
Here is an example of reading values of the 4th word of output table (address 515, the last example in the table above):
<?php require_once dirname(__FILE__) . '/Phpmodbus/ModbusMaster.php'; // Create Modbus object $modbus = new ModbusMaster("192.168.1.3", "UDP"); try { // FC 1 $recData = $modbus->readMultipleRegisters(0, 515, 1); } catch (Exception $e) { // Print error information if any echo $modbus; echo $e; exit; } // Print read data echo "Data:"; var_dump($recData);
The script returns the following on execution:
Data: array(2) { [0]=> int(0) [1]=> int(204) }
What do those number mean? We read a WORD built of 2 bytes. The first is 0, the second is 204. 204 in binary system is 11001100. Reading from the end we have two first bits = false, two following bits = true (those are %QX3.2 and %QX3.3), 2 further bits = false and 2 final bits = true. All fits the screenshot shown at the beginning of this article.
All I need now is to find a device which will let me use the protocol, prepare PHP scripts, which would be an intermediation between that device and the PLC.... ...or maybe talking directly from the PLC via ethernet or RS485 module?