前面连续写了关于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