Monday, September 15, 2014

How to make Simple ModBus RTU Communication for PLC




Modbus RTU Communication is used for communication between PLC and other devices with supporting modbus communication. Example modbus communication between PLC and Computer, PLC and Android, PLC and Arduino, PLC and PLC, PLC and CNC, PLC and Robot, and others.

In this article, I give an example: a simple way the use modbus communication between PLC and Computer/PC by using Microsoft Visual C# (C Sharp).

A. Modbus Master and Modbus Slave
In modbus communication, must first determine modbus master and modbus slave.
See the image below:
modbus master and modbus slave for plc

1. PC/Computer, CNC defined as Modbus Master
2. PLC defined as Modbus Slave
Modbus Master is a device Request the Data and write Data to the Modbus Slaves.
Modbus Slave is some devices Response Data to Modbus Master.
One Modbus Master can be connected up to 247 Modbus Slaves.
Each Modbus Slaves has a Unique Address/ID from 1 to 247.
Some PLCs that can be used as a Modbus Slave: Modicon PLC,Siemens PLC, Allen Bradley PLC, and Others.
For testing, I use Siemens PLC S7-200.

B. Modbus Function Code
For communicate between modbus master and modbus slave using modbus protocol, modbus protocol have some code and its function.
The listing below shows the modbus codes supported by Modicon:
modbus function codes

I use function code 03 and function code 16 for modbus testing and this function code that is most commonly used in general. For another function code please try yourself, download the complete modbus protocol, click here

C. Function Code 03 of ModBus
Function Code 03 is used for Reads the binary contents of Holding Registers in the address range of 40000 to 49999 and usually called 4x.

Parameters of Function Code 03 / Read Holding Registers:
Request/Query of Modbus Master:
Example: I want to read registers from starting address 0 in modbus slave with address 1, and the number of registers (number of points) read as 5 registers.
The request code is:
Modbus Function Code 03 Read Holding Registers Request Query

Request/Query in C# Programming:
//Function 3 request is always 8 bytes= index0 to index7
byte[] message = new byte[8];
byte Slave_Address = 1;
byte Function = 3;
ushort Starting_Address = 0;
ushort Number_of_Points = 5;

//index0 = Slave Address
message[0] = Slave_Address;
//index1 = Function
message[1] = Function;
//index2 = Starting Address Hi
message[2] = (byte)(Starting_Address >> 8);
//index3 = Starting Address Lo
message[3] = (byte)Starting_Address;
//index4 = Number of Points Hi
message[4] = (byte)(Number_of_Points >> 8);
//index5 = Number of Points Lo
message[5] = (byte)Number_of_Points;

// CRC (Cyclical Redundancy Check) Calculation
ushort CRC = 0xFFFF;
byte CRCHi = 0xFF;
byte CRCLo = 0xFF;
ushort CRCLSB;

for (int i = 0; i < (message.Length) - 2; i++)
{
  CRC = (ushort)(CRC ^ message[i]);

  for (int j = 0; j < 8; j++)
  {
    CRCLSB = (ushort)(CRC & 0x0001);
    CRC = (ushort)((CRC >> 1) & 0x7FFF);

    if (CRCLSB == 1)
      CRC = (ushort)(CRC ^ 0xA001);
  }
}
CRCHi = (byte)((CRC >> 8) & 0xFF);
CRCLo = (byte)(CRC & 0xFF);

//index6 = CRC Lo
message[message.Length - 2] = CRCLo;
//index7 = CRC Hi
message[message.Length - 1] = CRCHi;

Supply/Response of Modbus Slave with address 1:
Modbus Function Code 03 Read Holding Registers Supply Response

Read Registers Data from Response in C# Programming:
The registers data starting from index 3.
//Byte Count in index 3 = responseFunc3[2]
//Number of Registers = byte count / 2 = responseFunc3[2] / 2
byte registers = (byte)(responseFunc3[2] / 2);
short[] values = new short[registers];
for (int i = 0; i < registers; i++)
{
//Data Hi of Registers1 from Index3
values[i] = responseFunc3[2 * i + 3];
//Move to Hi
values[i] <<= 8;
//Data Lo of Registers1 from Index4
//Registers data is Data Hi + Data Lo
values[i] += responseFunc3[2 * i + 4];
}


D. Function Code 16 of ModBus

Parameters of Function Code 16 / Preset Multiple Registers:
Request/Query of Modbus Master:
Example: I want to write values to registers from starting address 5 in modbus slave with address 1, and the number of registers is written as 2 registers.
The request code is:
Modbus Function Code 16 Preset Multiple Registers Request Query

Request/Query in C# Programming:
//index0 = Slave Address
message[0] = Slave_Address;
//index1 = Function
message[1] = Function;
//index2 = Starting Address Hi
message[2] = (byte)(Starting_Address >> 8);
//index3 = Starting Address Lo
message[3] = (byte)Starting_Address;
//index4 = Number of Registers Hi
message[4] = (byte)(NumberofRegisters >> 8);
//index5 = Number of Registers Lo
message[5] = (byte)NumberofRegisters;
//index6 = Byte Count
message[6] = Byte_Count;
for (int i = 0; i < NumberofRegisters; i++)
{
//Data Hi, index7 and index9
message[7 + 2 * i] = (byte)(values[i] >> 8);
//Data Lo, index8 and index10
message[8 + 2 * i] = (byte)(values[i]);
}

// CRC (Cyclical Redundancy Check) Calculation
ushort CRC = 0xFFFF;
byte CRCHi = 0xFF;
byte CRCLo = 0xFF;
ushort CRCLSB;

for (int i = 0; i < (message.Length) - 2; i++)
{
  CRC = (ushort)(CRC ^ message[i]);

  for (int j = 0; j < 8; j++)
  {
    CRCLSB = (ushort)(CRC & 0x0001);
    CRC = (ushort)((CRC >> 1) & 0x7FFF);

    if (CRCLSB == 1)
      CRC = (ushort)(CRC ^ 0xA001);
  }
}
CRCHi = (byte)((CRC >> 8) & 0xFF);
CRCLo = (byte)(CRC & 0xFF);

//index11= CRC Lo
message[message.Length - 2] = CRCLo;
//index12 = CRC Hi
message[message.Length - 1] = CRCHi;


Supply/Response of Modbus Slave with address 1:
Modbus Function Code 16 Preset Multiple Registers Supply Response

For Response at the Modbus Function Code 16, should use the CRC Checker.
CRC (Cyclical Redundancy Check) Checker in C# Programming:
private bool CRCResponseCheck(byte[] message)
{

//CRC Response Check:
byte[] CRC = new byte[2];
ushort CRCFull = 0xFFFF;
byte CRCHigh = 0xFF, CRCLow = 0xFF;
ushort CRCLSB;

for (int i = 0; i < (message.Length) - 2; i++)
{
  CRCFull = (ushort)(CRCFull ^ message[i]);

  for (int j = 0; j < 8; j++)
  {
    CRCLSB = (ushort)(CRCFull & 0x0001);
    CRCFull = (ushort)((CRCFull >> 1) & 0x7FFF);

    if (CRCLSB == 1)
      CRCFull = (ushort)(CRCFull ^ 0xA001);
  }
}
CRCHigh = (byte)((CRCFull >> 8) & 0xFF);
CRCLow = (byte)(CRCFull & 0xFF);

if (CRCLow == message[message.Length - 2] && CRCHigh == message[message.Length - 1])
  return true;
else
  return false;

}


E. Read/Write Registers in PLC Siemens S7-200 with Modbus Function Code 03 and 16
In PLC S7-200, I use Registers VB800 as Starting Address in Modbus.
See Ladder programming, and a list of tables registers:

Siemens S7-200 Modbus
Siemens S7-200 Modbus

ModBus Registers in Siemens PLC S7-200
ModBus Registers in Siemens PLC S7-200


F. Project File
1. Download project file for Microsoft Visual C#, click here
2. Download PLC Ladder Programming for Siemens PLC S7-200, click here

See video about Testing of Modbus: Function Code 03


See video about Testing of Modbus: Function Code 16


Thank you for reading my article and have been watching my videos, and always visit my blog in the next day.




Labels:






Newer Post Older Post Home

You may also like these ebook:

Get Free PLC eBook directly sent to your email,
and email subscription to program-plc.blogspot.com




We hate SPAM. Your information is never sold or shared with anyone.

Your Email Will Be 100% Secured !

Your email is stored safely on Google FeedBurner