Introduction
I was required to connect a small touch screen to a delta PLC and used ModBus as the protocol. This caused me to want to know more about protocols. The project is written using ASCII not RTU as I do not know how to format the code to RTU yet, but be assured I will get there soon.
Background
For a more in depth view of ModBus, there are numerous sites and they will give you more in depth description of modbus. I am only going to explain my code and the functions available. I used the Delta DVP Series PLC communication protocol ver 1.0 as a reference. This is downloadable from their website.
Using the Code
The two main classes that we use here are clsComms
and clsInputValidation
.
Any ModBus transmit word consists of the following:
: + Controller Address + Register Address +
ModBus Operation + Data Sent + Check Bit + Carriage return + line feed
When data is entered, it needs to be hex. clsInputValidation.validHex()
will make sure of this:
public static void ValidHex(string register)
{
Regex rx = new Regex("[^A-F|^0-9|^ |^\t]");
if (rx.IsMatch(register))
throw new Exception("Enter a valid HEX number");
}
The checkbit is the 2's compliment of the total of all the words. clsComms.checkSum()
will do this for you:
public static string checkSum(string writeUncheck)
{
char[] hexArray = new char[writeUncheck.Length];
hexArray = writeUncheck.ToCharArray();
int decNum = 0, decNumMSB= 0, decNumLSB = 0;
int decByte, decByteTotal = 0;
bool msb = true;
for( int t = 0; t <= hexArray.GetUpperBound(0); t++)
{
if((hexArray[t]>= 48) && (hexArray[t] <= 57))
decNum = (hexArray[t] - 48);
else if ( (hexArray[t] >= 65) & (hexArray[t] <= 70))
decNum = 10 + (hexArray[t] - 65);
if (msb)
{
decNumMSB = decNum * 16;
msb = false;
}
else
{
decNumLSB = decNum;
msb = true;
}
if (msb)
{
decByte = decNumMSB + decNumLSB;
decByteTotal += decByte;
}
}
decByteTotal = (255 - decByteTotal) + 1;
decByteTotal = decByteTotal & 255;
int a, b = 0;
string hexByte = "", hexTotal = "";
double i;
for (i = 0; decByteTotal > 0; i++)
{
b = Convert.ToInt32(System.Math.Pow(16.0, i));
a = decByteTotal % 16;
decByteTotal /= 16;
if (a <= 9)
hexByte = a.ToString();
else
{
switch (a)
{
case 10:
hexByte = "A";
break;
case 11:
hexByte = "B";
break;
case 12:
hexByte = "C";
break;
case 13:
hexByte = "D";
break;
case 14:
hexByte = "E";
break;
case 15:
hexByte = "F";
break;
}
}
hexTotal = String.Concat(hexByte, hexTotal);
}
return hexTotal;
}
The clsComms.Read()
will take the transmit string
and send it to the PLC returning either a response from the PLC or an error message, such as time out.
Other features in clsComms
include code that will convert string
s to a double
, in this way you can convert the part of code of interest to you into a decimal value, making it easier to read for the end user and code which converts an integer into a valid HEX number, again making user interfacing easier.
Points of Interest
This project was an excellent learning curve for me as I learned C# as well as the protocol in the process. My intention is to later develop a ModBus IO server which I can use to update tags in a mini SCADA system. I hope there are people out there who have similar projects and can share information with me.
History
- 31st March, 2009: Initial version