C读取Modbus数据

C读取Modbus数据前面连续写了关于 SOCKET 编程的东西 似乎有点高大上 为了学习而学习 因此这里我们来整点实际应用的东西 C 如何读取 Modbus 数据 Modbus 很多人可能一点都不知道 也正常 隔行如隔山嘛 Modbus 在自动化行业就不一样 属于路人皆知的东西 很多设备 程序都与 Modbus 息息相关 Modbus 这个东西 本人也是个二把刀 只有半瓶水 所以在这里晃荡 写点 Mo

        前面连续写了关于SOCKET编程的东西,似乎有点高大上,为了学习而学习。因此这里我们来整点实际应用的东西。C#如何读取Modbus数据,Modbus很多人可能一点都不知道,也正常,隔行如隔山嘛。Modbus在自动化行业就不一样,属于路人皆知的东西,很多设备、程序都与Modbus息息相关。

        Modbus这个东西,本人也是个二把刀,只有半瓶水,所以在这里晃荡,写点Modbus东西,也是让自己能理解得更深一点,入门级别的东西,希望能帮助到那些像我一样不太了解Modbus,但是又想了解Modbus的同学。

        至于高手,可以吐槽,当然最好是直接绕过。

        闲话少说,书归正传。何谓Modbus

        Modbus通讯协议,ModBus网络是一个工业通信系统,由带智能终端的可编程序控制器和计算机通过公用线路或局部专用线路连接而成。其系统结构既包括硬件、亦包括软件。它可应用于各种数据采集和过程监控。

      Modbus通讯协议是施耐德电气公司……

        Modbus 协议是应用于电子控制器上的一种通用语言。通过此协议,控制器相互之间、控制器经由网络(例如以太网)和其它设备之间可以通信。它已经成为一通用工业标准。有了它,不同厂商生产的控制设备可以连成工业网络,进行集中监控……

      这些都是百度来的,呵呵,别吐槽。网上资料很多,有兴趣的可以自己撸,看多了感觉好像都差不多。

      个人认为所谓的通讯协议,机器、设备或者程序之间相互通讯的一种方式。人与人交流不也有不同的语言或者文字嘛,机器之间当然可以相互发送信息,只要定好规则即可。而Modbus就是与自动化设备用来交流的语言。

      这些理解了也好,不明白其实也不要紧。因为Modbus对于我们码农来说,我们可以大大的缩小理解范围,我们只需要关心与编码有关系东西,对于硬件的那些什么针脚、电缆、信号位都不用太关心,当然如果想成为为一个Modbus方面的专家,那就不同了。

     Modbus分两种模式,一种串口模式,一种是TCP/IP模式。串口模式感觉越来越少,现在大多都是TCP/IP模式,所以这里就暂时写TCP/IP模式

     首先要做就是SOCKET客户端与设备建立连接,因为前面的文章中,关于SOCKET,我们已经说过了,那么下面的代码就非常easy了。说简单点,先不要去想什么Modbus,就认为有一台服务器,开了SOCKET服务在哪里。所以如下代码就水到渠成了。

   

private TcpClient tcpClient; public bool Open(string ip,int port) { try { tcpClient = new TcpClient(); tcpClient.Connect(IPAddress.Parse(ip), port); return true; }catch(SocketException e){ //LogHelper.WriteLog(e.Message); return false; } }

         LogHelper代码这里就不写,与主题无关,个人感觉这样的代码也没必要去运行一下,看看能明白就行了。去运行这个事情,有时会耽误太多的时间。这里IP和端口号都是由设备方提供的。真实程序一般都把这两个参数写配置文件中。

       设备连上以后,下一步当然就是读取数据。Modbus的基本原理就是程序向设备请求,需要读取哪个数据,设备就会返回相应的数据。我们知道机器或者说是电脑是只认识01001这样的字符串的。所以所谓的Modbus协议,说得简单一点,就是规定这样一个0101字符各代表什么含义。

    

///  /// 读取数据 Modbus ///  /// 结果 /// 设备号 /// 设备地址 /// 长度-多少个设备 /// 
      
        数据读取结果 是否成功 
       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 
      
        data = new List 
       
         (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; } } 
        
      

这个其实更多的是处理数据异常,LogHelper与前面一样,核心好像还不在了,就是那个Receive方法。

 ///  /// 读取 Modbus ///00 00 00 00 00 0d 01 03 0A 14 00 14 00 14 00 14 00 14 00 ///  /// 标示 /// 设备码 /// 开始地址 /// 设备数量 /// 
       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 ///  /// 发送字节数 ///  ///  ///  ///  ///  /// 
       private byte[] GetSrcData(short m, short id, short add, short len) { List 
      
        data = new List 
       
         (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(); } 
        
      

 好,到这里基本上搞定了。其实很多逻辑都在代码中,说简单的就是某个ID设备,从哪个地址开始,读几个设备的值,这里需要注意是short 不要用32位的int去替换,结果会不一样的。仔细看看估计大家都能明白,也没有什么神秘的东西。

哦,对了还ValueHelper代码

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; } } } 

不好意思,有个方法给忘记了

 private byte[] TrimModbus(byte[] d, short m, short id, short len) { int size = Convert.ToInt32(len) * 2; int dLen = size + 9; if (d == null || d.Length != dLen || m != Convert.ToInt16(d[1]) || id != Convert.ToInt16(d[6])) { return null; } byte[] n = new byte[size]; Array.Copy(d, 9, n, 0, size); return n; }

所有代码都贴出来了,但是如果实在想运行的,也是需要简单整理的。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/222294.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月17日 下午4:06
下一篇 2026年3月17日 下午4:07


相关推荐

  • EOS是什么_电脑EOS是什么

    EOS是什么_电脑EOS是什么EOS是什么

    2022年4月21日
    53
  • 从零开始学习EasyDarwin(概述篇)

    EasyDarin是什么  EasyDarwin是由国内开源流媒体团队维护的一款开源流媒体平台框架,从2012年12月创建并发展至今,从原有的单服务的流媒体服务器形式,扩展成现在的云平台架构的开源项目,更好地帮助广大流媒体开发者和创业型企业快速构建流媒体服务平台。EasyDarwin适合做什么  安防视频监控,移动互联网(安卓、IOS、微信)流媒体直播与点播,流媒体视

    2022年4月5日
    47
  • PhotoShop中画圆角矩形最简单方法(图文并茂)!

    PhotoShop中画圆角矩形最简单方法(图文并茂)!

    2022年2月4日
    66
  • C#操作XML的完整例子——XmlDocument篇「建议收藏」

    C#操作XML的完整例子——XmlDocument篇「建议收藏」这是一个用c#控制台程序下, 用XmlDocument进行XML操作的的例子,包含了查询、增加、修改、删除、保存的基本操作。较完整的描述了一个XML的整个操作流程。适合刚入门.netXML操作的朋友参考和学习。假设有XML文件:books.xmlxml version=”1.0″ encoding=”UTF-8″?>books> book>  name>哈里波特name>  pr

    2022年6月19日
    37
  • C语言的return用法

    C语言的return用法C 语言 return 的用法详解 C 语言函数返回值详解摘自 C 语言中文网 http c biancheng net view 1855 html 我觉得对 return 讲得不错 终于把 return 弄明白了 函数的返回值是指函数被调用之后 执行函数体中的代码所得到的结果 这个结果通过 return 语句返回 return 语句的一般形式为 return 表达式 或者 r

    2026年3月19日
    1
  • 分享一份软件测试项目实战(web+app+h5+小程序)

    分享一份软件测试项目实战(web+app+h5+小程序)大家好,我是谭叔。本次,谭叔再度出马,给大家找了一个非常适合练手的软件测试项目,此项目涵盖web端、app端、h5端、小程序端,可以说非常之全面。缘起在这之前,谭叔已经推出了九套实战教程。但是,这些教程以web测试和接口测试为主,没有app等项目。为了让实战项目更加全面、涵盖到各端,同时也为了满足读者粉丝们对项目的高需求,我决定再给大家找一个项目。(实力宠粉,求个赞不过分吧~)说实话,在找项目的过程中,我下载过(甚至付费下载过)N多个项目、联系过很多项目的作者,但是绝大部分项目,在我看来,并不

    2022年6月22日
    41

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号