前面连续写了关于SOCKET编程的东西,似乎有点高大上,为了学习而学习。因此这里我们来整点实际应用的东西。C#如何读取Modbus数据,Modbus很多人可能一点都不知道,也正常,隔行如隔山嘛。Modbus在自动化行业就不一样,属于路人皆知的东西,很多设备、程序都与Modbus息息相关。
Modbus这个东西,本人也是个二把刀,只有半瓶水,所以在这里晃荡,写点Modbus东西,也是让自己能理解得更深一点,入门级别的东西,希望能帮助到那些像一些不太了解Modbus,但是又想了解Modbus的同志。至于高手,可以吐槽,当然也可以绕过。
Modbus 协议是应用于电子控制器上的一种通用语言。通过此协议,控制器相互之间、控制器经由网络(例如以太网)和其它设备之间可以通信。它已经成为一通用工业标准。有了它,不同厂商生产的控制设备可以连成工业网络,进行集中监控......
public bool Open(string ip,int port) {
try {
tcpClient = new TcpClient();
tcpClient.Connect(IPAddress.Parse(ip), port);
return true;
}catch(SocketException e){
string m = string.Format("modbus Client服务器连接错误:{0},ip:{1},port:{2}", e.Message, ip, port);
LogHelper.WriteLog(m);
return false;
}
}/// <summary>
/// 读取数据 Modbus
/// </summary>
/// <param name="rData">结果</param>
/// <param name="id">设备号</param>
/// <param name="address">设备地址</param>
/// <param name="len">长度-多少个设备</param>
/// <returns>数据读取结果 是否成功</returns>
public bool ReceiveData(ref short[] rData, short id, short address, short len)
{
try
{
short m = Convert.ToInt16(new Random().Next(2, 20));
rData = null;
byte[] bs = Receive(m, id, address, len);
byte[] b = TrimModbus(bs, m, id, len);
if (b==null) { return false; }
List<short> data = new List<short>(255);
for (int i = 0; i < b.Length-1; i++)
{
if (!Convert.ToBoolean(i & 1))
{
byte[] temp = new byte[] { b[i+1], b[i] };
data.Add(BitConverter.ToInt16(temp, 0));
}
}
rData = data.ToArray();
return true;
}
catch (Exception e) {
LogHelper.WriteLog("返回Modbus数据错误"+ e.Message);
return false;
}
} /// <summary>
/// 读取 Modbus
///00 00 00 00 00 0d 01 03 0A 14 00 14 00 14 00 14 00 14 00
/// </summary>
/// <param name="m">标示</param>
/// <param name="id">设备码</param>
/// <param name="address">开始地址</param>
/// <param name="len">设备数量</param>
/// <returns></returns>
private byte[] Receive(short m, short id, short address, short len)
{
try
{
if (tcpClient == null || !tcpClient.Connected) { return null; }
byte[] data = GetSrcData(m, id, address, len);
//00 00 00 00 00 06 01 03 00 00 00 05
tcpClient.Client.Send(data, data.Length, SocketFlags.None);
int size = len * 2 + 9;
byte[] rData = new byte[size];
tcpClient.Client.Receive(rData, size, SocketFlags.None);
//string t1 = TranBytes(rData);
return rData;
}catch(SocketException e){
if (e.ErrorCode != 10004)
{
LogHelper.WriteLog(e.Message);
}
if (tcpClient != null) {
tcpClient.Close();
tcpClient = null;
}
return null;
}
}
#endregion上面的代码可以说是Modbus协议核心,其实就是SOCKET发送数据和接受数据,发送是告诉主机需要取那些的数据。接受就是把主机返回来的数据接受过来。//发送
//00 00 00 00 00 06 01 03 00 00 00 05
/// <summary>
/// 发送字节数
/// </summary>
/// <param name="m"></param>
/// <param name="len"></param>
/// <param name="id"></param>
/// <param name="address"></param>
/// <returns></returns>
private byte[] GetSrcData(short m, short id, short add, short len)
{
List<byte> data = new List<byte>(255);
data.AddRange(ValueHelper.Instance.GetBytes(m)); // 00 01
data.AddRange(new byte[] { 0x00, 0x00 }); // 00 00
data.AddRange(ValueHelper.Instance.GetBytes(Convert.ToInt16(6))); //字节数 00 06
data.Add(Convert.ToByte(id)); //路由码 01
data.Add(Convert.ToByte(3)); //功能码 3-读 03
data.AddRange(ValueHelper.Instance.GetBytes(add)); //开始地址 00 00
data.AddRange(ValueHelper.Instance.GetBytes(len)); //设备数量 00 05
return data.ToArray();
}using System;
using System.Collections.Generic;
using System.Text;
namespace Modbus {
public class ValueHelper
{
#region 大小端判断
public static bool LittleEndian = false;
static ValueHelper()
{
unsafe
{
int tester = 1;
LittleEndian = (*(byte*)(&tester)) == (byte)1;
}
}
#endregion
#region Factory
public static ValueHelper _Instance = null;
internal static ValueHelper Instance
{
get
{
if (_Instance == null)
{
_Instance = LittleEndian ? new LittleEndianValueHelper() : new ValueHelper();
//_Instance = new ValueHelper();
}
return _Instance;
}
}
#endregion
protected ValueHelper()
{
}
public virtual Byte[] GetBytes(short value)
{
return BitConverter.GetBytes(value);
}
public virtual Byte[] GetBytes(int value)
{
return BitConverter.GetBytes(value);
}
public virtual Byte[] GetBytes(float value)
{
return BitConverter.GetBytes(value);
}
public virtual Byte[] GetBytes(double value)
{
return BitConverter.GetBytes(value);
}
public virtual short GetShort(byte[] data)
{
return BitConverter.ToInt16(data, 0);
}
public virtual int GetInt(byte[] data)
{
return BitConverter.ToInt32(data, 0);
}
public virtual float GetFloat(byte[] data)
{
return BitConverter.ToSingle(data, 0);
}
public virtual double GetDouble(byte[] data)
{
return BitConverter.ToDouble(data, 0);
}
}
internal class LittleEndianValueHelper : ValueHelper
{
public override Byte[] GetBytes(short value)
{
return this.Reverse(BitConverter.GetBytes(value));
}
public override Byte[] GetBytes(int value)
{
return this.Reverse(BitConverter.GetBytes(value));
}
public override Byte[] GetBytes(float value)
{
return this.Reverse(BitConverter.GetBytes(value));
}
public override Byte[] GetBytes(double value)
{
return this.Reverse(BitConverter.GetBytes(value));
}
public virtual short GetShort(byte[] data)
{
return BitConverter.ToInt16(this.Reverse(data), 0);
}
public virtual int GetInt(byte[] data)
{
return BitConverter.ToInt32(this.Reverse(data), 0);
}
public virtual float GetFloat(byte[] data)
{
return BitConverter.ToSingle(this.Reverse(data), 0);
}
public virtual double GetDouble(byte[] data)
{
return BitConverter.ToDouble(this.Reverse(data), 0);
}
private Byte[] Reverse(Byte[] data)
{
Array.Reverse(data);
return data;
}
}
}
代码都贴大概都贴出来,但是如果实在想运行的,也是需要简单整理的。原文:http://blog.csdn.net/kongxiangli/article/details/40393739