Modbus Example

In addition to this example, I’d suggest reading this excellent document on MODBUS that will explain the protocol in detail.

Ace and Branch PLCs are built to communicate Modbus messages.  Using Modbus, you can plug your PLC into any PC (or any device with a USB port capable of Modbus communication) and communicate with your custom application.

In this example we’ll create a custom application in Visual Studio using C#.  Specifics we’ll cover:

  • Assign Tags Modbus Addresses using vBuilder
  • Check if PLC is already being used by another Velocio application.
  • Connect application to PLC
  • Write Bit
  • Read Bit
  • Write UI16
  • Read UI16
  • Discuss additional commands and how to read/write remaining data types

The Application will look like

Modbus-Example-Screenshot
















You’ll Need:
Visual Studio: Here’s a free link to Windows Desktop Version.  I think this one requires at least Windows 7.  Feel free to download an older version if you need, there isn’t anything in this example that requires the newest version.
vBuilder: Here’s the link to our vBuilder page where you can download it for free.

Example Code:
Click to download the code used in this example

Other Important Documents:
Modbus Application Protocol:  This describes the full Modbus Protocol.  Velocio PLCs support the 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x0F, 0x10 and 0x17 commands.

Code added after video was made:

We added a subroutine to handle the CRC needed for Modbus Communication.  It is called both in the send and the receive routine.

The following code builds on the Example Project above.

Requesting 32Bit Value (I32 or Float) 
This is just like the Read16BitMessage in the Example Project, except for the ‘Quantity of 16 Bit words to read’ is set to 2 instead of 1

public void Read32BitMessage()
{
     ArrayList alReturn = new ArrayList();
     alReturn.Add((byte)0x01); // PLC ID# in this example we set it to 1
     alReturn.Add((byte)0x03); // Read 16Bit Command (Modbus Read Holding Registers)
     //In this example we're just sending this to address 0 (called Address 1 in vBuilder).
     // **Note: these are offset by -1 from the # you setup in vBuilder.
     alReturn.Add((byte)0x00); // Starting Address Hi
     alReturn.Add((byte)0x00); // Starting Address Lo. 

     //you can set the quantity to read more than 1 contiguous bits
     alReturn.Add((byte)0x00); // Quantity of 16 Bit words to read
     alReturn.Add((byte)0x02); // Quantity of 16 Bit words to read

     sendMessage(alReturn);
}

 

How to Decode a Float
You may have noticed with the UI16 that the we used the Lower byte as the most significant byte. We’ll need to do that with Float (and all non-bit data types). Just in this case we’ve got 2 16bit words. So we’ll flip the order of bytes in each word. It’ll look like the following. This could be plugged into the si_DataReceivedEventArgs function in the example code.

case 0x03: // Read 16Bit Command (Modbus Read Holding Registers)
case 0x04: // (Modbus Read Input Registers)
     byte[] myFloatArray = new byte[4];
     myFloatArray[0] = readVal[4];
     myFloatArray[1] = readVal[3];
     myFloatArray[2] = readVal[6];
     myFloatArray[3] = readVal[5];
     float myFloat = System.BitConverter.ToSingle(myFloatArray, 0);
     break;

 

I32 Decode Example

case 0x03: // Read 16Bit Command (Modbus Read Holding Registers)
case 0x04: // (Modbus Read Input Registers)
     byte[] myI32Array = new byte[4];
     myI32Array[0] = readVal[4];
     myI32Array[1] = readVal[3];
     myI32Array[2] = readVal[6];
     myI32Array[3] = readVal[5];
     Int32 myI32 = System.BitConverter.ToInt32(myI32Array, 0);
     break;

 

I16 Decode Example 
This is just a simpler version of the I32 Example

case 0x03: // Read 16Bit Command (Modbus Read Holding Registers)
case 0x04: // (Modbus Read Input Registers)
     byte[] myI16Array = new byte[2];
     myI16Array[0] = readVal[4];
     myI16Array[1] = readVal[3];
     Int16 myI16 = System.BitConverter.ToInt16(myI16Array, 0);
     break;

 Creating Float Message to Send to PLC
With a little modification you can use this to send I32values

public void WriteFloatMessage(Single fValue)
{
     ArrayList alReturn = new ArrayList();
     alReturn.Add((byte)0x01); // PLC ID# in this example we set it to 1
     alReturn.Add((byte)0x10); // Write multiple 16Bit values (Modbus Write Multiple Registers)

     //In this example we're just sending this to address 0.
     // **Note: these are offset by -1 from the # you setup in vBuilder.
     alReturn.Add((byte)0x00); // Starting Address Hi
     alReturn.Add((byte)0x00); // Starting Address Lo. 

     alReturn.Add((byte)0x00); // Quantity of Registers Hi
     alReturn.Add((byte)0x02); // Quantity of Registers Lo. 

     alReturn.Add((byte)0x04); // ByteCount in this case we're sending 4 bytes 

      Byte[] myFloatBytes = new Byte[4];
      myFloatBytes = BitConverter.GetBytes(fValue);

      alReturn.Add(myFloatBytes[1]); // Quantity of Outputs Hi of Least Significant Word
      alReturn.Add(myFloatBytes[0]); // Quantity of Outputs Lo of Least Significant Word
      alReturn.Add(myFloatBytes[3]); // Quantity of Outputs Hi of Most Significant Word
      alReturn.Add(myFloatBytes[2]); // Quantity of Outputs Lo of Most Significant Word

      sendMessage(alReturn);
}

As mentioned above Velocio PLCs support several additional messages not described in this tutorial.  Check out the Modbus Protocol ( linked above) and using these examples, it should be easy to implement those features.