`

Simens PLC200 -modbusRTU 协议解析

    博客分类:
  • C#
c# 
阅读更多
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TCPCLIENT
{
 public   class Siemens200_modbusRTU
    {
        static String HEXES = "0123456789ABCDEF";
        byte uchCRCHi = (byte)0xFF;
        byte uchCRCLo = (byte)0xFF;
         private String address;
       private CRC16 _crc = new CRC16();
      #region "ModbusRTU协议说明"

        /**Modbus 地址
        通常 Modbus 地址由 5 位数字组成,包括起始的数据类型代号,以及后面的偏移地址。Modbus Master 协议库把标
        准的 Modbus 地址映射为所谓 Modbus 功能号,读写从站的数据。Modbus Master 协议库支持如下地址:
        · 00001 - 09999:数字量输出(线圈)
        · 10001 - 19999:数字量输入(触点)
        · 30001 - 39999:输入数据寄存器(通常为模拟量输入)
        · 40001 - 49999:数据保持寄存器
         
       * Modbus 地址 S7-200 数据区
         00001 ~ 00128 Q0.0 ~ Q15.7
         10001 ~ 10128 I0.0 ~ I15.7
         30001 ~ 30032 AIW0 ~ AIW62
         40001 ~ 4xxxx T ~ T + 2 * (xxxx -1)
         其中T 为S7-200 中的缓冲区起始地址,即 HoldStart。
         如果已知S7-200 中的V 存储区地址,推算Modbus 地址的公式如下:
         Modbus 地址 = 40000 + (T/2+1) ; T 为偶数
         * 
         *功能码
            主站使用相应功能码作用于此从站的效用
            1 读取单个/多个线圈(离散量输出点)状态。 功能 1 返回任意个数输出点(Q)的 ON/OFF 状态。
            2 读取单个/多个触点(离散量输入点)状态。 功能 2 返回任意个数输入点(I)的 ON/OFF 状态。
            3 读取单个/多个保持寄存器。功能 3 返回 V 存储区的内容。在 Modbus 协议下保持寄存器都是“字”值,在一次请求中可以读取最
              多 120 个字的数据。
            4 读取单个/多个输入寄存器。
              功能 4 返回 S7-200 的模拟量数据值。
            5 写单个线圈(离散量输出点)。
              功能 5 用于将离散量输出点设置为指定的值。这个点不是被强制的,用户程序可以覆盖 Modbus 通
                    信请求写入的值。
            6 写单个保持寄存器。
           功能 6 写一个值到 S7-200 的 V 存储区的保持寄存器中。
           15 写多个线圈(离散量输出点)。功能 15 把多个离散量输出点的值写到 S7-200 的输出映像寄存器(Q 区)。输出点的地址必须
                以字节边界起始(如 Q0.0 或 Q2.0),并且输出点的数目必须是 8 的整数倍。这是此 Modbus RTU 从站指令库的限制。些点不
                是被强制的,用户程序可以覆盖 Modbus 通信请求写入的值。
           16 些多个保持寄存器。
         *    功能 16 写多个值到 S7-200 的 V 存储区的保持寄存器中。在一次请求中可以写最多 120 个字的数据。
       */
      #endregion
    
      /// <summary>
      /// 地址码
      /// </summary>
      /// <param name="_address"></param>
     
      public void  SetAddress(String _address)
          {
          this.address = _address;
          }


      /// <summary>
      /// 功能码
      /// </summary>
      public enum modbusRTU_Func
      { 
          FUNC_READ_I=0x2, //读数字输入I
          FUNC_READ_V=0X3,  //读V寄存器
          FUNC_READ_AI=0X4, //读模拟AI寄存器
          FUNC_WRITE_1Q=0X5, //写单个数字输出寄存器Q
          FUNC_WRITE_1V=0X6, //写单个数据保存寄存器V
          FUNC_WRITE_NQ=0XF, //写多个数字输出寄存器Q
          FUNC_WRITE_NV=0X10 //写多个数据保存寄存器V
      }
      public struct strType
      {
          public byte HighType;
          public byte LowType;    
      }

      private static  byte byteLength = 8;   // 字节位长 
      /*
            整型32bit转换成字节型8bit数组
            @param number 待求数值
            @param length 数值所占字节数
         */
      private static byte[] intToByteArray(int number, int length)
          {
          byte[] byteArray = new byte[length];

          int shiftNum = 0;	// 移位数
          for (int i = 0; i < length; i++)
              {
              shiftNum = (length - i - 1) * byteLength;
              byteArray[i] = (byte)((number >> shiftNum) & 0xFF);
              }
          return byteArray;
          }

      /// <summary>
      /// 获取读命令字节数组
      /// </summary>
      /// <param name="Address">设备地址</param>
      /// <param name="Func">功能码</param>
      /// <param name="Type">寄存器类型</param>
      /// <param name="BeginAddr">起始地址</param>
      /// <param name="Count">读取点数</param>
      /// <returns>返回读取命令字节数组</returns>
      public byte[] GetReadCmd(byte Address,byte Func ,String Type, String BeginAddr,int Count)
      {
          List<strType> HL_Type = new List<strType>();
          byte[] buf = new byte[8];
          buf[0] = Address;
          buf[1] = Func;
          HL_Type=getRealAddrArray(Type, new String[] {BeginAddr});
          buf[2] = HL_Type[0].LowType;
          buf[3] = HL_Type[0].HighType;

          byte[] Len_Type = intToByteArray(Count, 2);
          buf[4] = Len_Type[0];
          buf[5] = Len_Type[1];

          buf = CRC16.GetCRC16Full(new byte[] { buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]}, true);
          return buf;
      }

     /// <summary>
      ///获取写命令字节数组
     /// </summary>
     /// <param name="Address"></param>
     /// <param name="Func"></param>
     /// <param name="Type"></param>
     /// <param name="Addr"></param>
     /// <param name="value"></param>
     /// <returns></returns>
      public byte[] GetWriteCmd(byte Address, byte Func, String Type, String Addr, byte HighType, byte Lowtype)
      {
          List<strType> HL_Type = new List<strType>();
          byte[] buf = new byte[8];
          buf[0] = Address;
          buf[1] = Func;
          HL_Type = getRealAddrArray(Type, new String[] { Addr });
          buf[2] = HL_Type[0].LowType;
          buf[3] = HL_Type[0].HighType;


          buf[4] = HighType;
          buf[5] = Lowtype;

          buf = CRC16.GetCRC16Full(new byte[] { buf[0], buf[1], buf[2], buf[3], buf[4], buf[5] }, true);
          return buf;
      }





      public  List<strType> getRealAddrArray(String Type, String[] loc)
      {
      List<strType> typeList = new System.Collections.Generic.List<strType>();
      switch (Type)
          {
          case "Q":
              Dictionary<String, Int32> Q_Map = new System.Collections.Generic.Dictionary<String, Int32>();
              //输出寄存器数量:00001 ~ 00128  共128个
              int Index = 0;
              Int32 Val = 0;
              for (int j = 0; j < 128; j++)
                  {
                  //0  7   8  17 25  
                  Index=j/8;
                  if (Val == 8 )
                      {
                       Val = 0;
                      }
                  Q_Map.Add("Q"+Index+"."+Val, j);
                  Val+=1;
                  }
              for (int i = 0; i < loc.Length; i++)
                  {
                  if (Q_Map.ContainsKey(loc[i])==true)
                      {

                      int buf = Q_Map[loc[i]];
                      byte[] bytes = BitConverter.GetBytes(buf);
                      strType type = new strType();
                      if (bytes.Length == 4)
                          {
                          type.HighType = bytes[1];
                          type.LowType =bytes[0];
                          }
                      typeList.Add(type);
                      }
                  }
              break;

          case "I":
               Dictionary<String, Int32> I_Map = new System.Collections.Generic.Dictionary<String, Int32>();
              //输入寄存器数量:00001 ~ 00128  共128个
              Index = 0;
               Val = 0;
              for (int j = 0; j < 128; j++)
                  {
                  //0  7   8  17 25  
                  Index=j/8;
                  if (Val == 8 )
                      {
                       Val = 0;
                      }
                  I_Map.Add("I"+Index+"."+Val, j);
                  Val+=1;
                  }
              for (int i = 0; i < loc.Length; i++)
                  {
                  if (I_Map.ContainsKey(loc[i])==true)
                      {

                      int buf = I_Map[loc[i]];
                      byte[] bytes = BitConverter.GetBytes(buf);
                      strType type = new strType();
                      if (bytes.Length == 4)
                          {
                          type.HighType = bytes[1];
                          type.LowType =bytes[0];
                          }
                      typeList.Add(type);
                      }
                  }
              break;
          case "AI":
              break;

          case "VW":
                Dictionary<String, Int32> V_Map = new System.Collections.Generic.Dictionary<String, Int32>();
                //数据保持寄存器数量:40001 ~ 4XXXX   40000 + (T/2+1) ; T 为偶数
              Index = 0;
               Val = 0;
              for (int j = 0; j < 9999; j++)
                  {
                  if (j % 2==0)
                      {
                       V_Map.Add("VW"+j, j/2);
                      }
                  }
              for (int i = 0; i < loc.Length; i++)
                  {
                  if (V_Map.ContainsKey(loc[i])==true)
                      {
                      int buf = V_Map[loc[i]];
                      byte[] bytes = BitConverter.GetBytes(buf);
                      strType type = new strType();
                      if (bytes.Length == 4)
                          {
                          type.HighType = bytes[0];
                          type.LowType =bytes[1];
                          }
                      typeList.Add(type);
                      }
                  }
              break;
          default:
              break;
          }
      return typeList;      
     }
 

      public static byte[] ConvertStringToByteArray(string stringToConvert)
      {
          return (new UnicodeEncoding()).GetBytes(stringToConvert);
      }

 
        /// <summary> 
        /// 字节数组转16进制字符串 
        /// </summary> 
        /// <param name="bytes"></param> 
        /// <returns></returns> 
        public  string byteToHexStr(byte[] bytes) 
        { 
        string returnStr = ""; 
        if (bytes != null) 
        { 
        for (int i = 0; i < bytes.Length; i++) 
        { 
        returnStr += bytes[i].ToString("X2"); 
        } 
        } 
        return returnStr; 
        } 


      /// <summary> 
      /// 字符串转16进制字节数组 
      /// </summary> 
      /// <param name="hexString"></param> 
      /// <returns></returns> 
      private static byte[] strToToHexByte(string hexString)
      {
          hexString = hexString.Replace(" ", "");
          if ((hexString.Length % 2) != 0)
              hexString += " ";
          byte[] returnBytes = new byte[hexString.Length / 2];
          for (int i = 0; i < returnBytes.Length; i++)
              returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
          return returnBytes;
      }

        }

    }
分享到:
评论

相关推荐

    S7-200PLC-Modbus RTU通信轮询-主站读写程序示例.rar

    标签中列出的关键词包括"S7-200PLC","ModbusRTU通信","轮询","主站读写"和"程序示例",这些关键词涵盖了这个主题的关键技术点: 1. **S7-200PLC**:这是西门子的一款小型PLC,具备编程简单、性价比高的特点,...

    详解S7-1500PLC 实现 Modbus-RTU 通信.docx

    SIEMENS S7-1500PLC 实现 Modbus-RTU 通信配置步骤和程序编写详解 Modbus-RTU 通信是一种常见的工业通信协议,广泛应用于工业自动化领域。SIEMENS S7-1500PLC 是一种高性能的工业控制器,可以实现 Modbus-RTU 通信...

    S7-200SMART-modbusRTU轮询程序(读轮询+写优先)附使用说明.zip

    本篇文章将深入探讨如何在S7-200SMART PLC上实现Modbus RTU协议的轮询程序,包括读轮询和写优先策略,并提供详细的使用说明。 首先,了解Modbus RTU协议是理解整个程序的基础。Modbus是一种广泛应用的通信协议,...

    S7-200SMART进行MODBUS RTU+TCP通信封装子程序.zip

    - 实现方法:在S7-200SMART的编程软件中,使用PDU(协议数据单元)和MB_SERV指令来构建和解析MODBUS RTU帧。 2. **MODBUS TCP通信**: - 与MODBUS RTU的区别:TCP/IP协议栈增加了可靠性,如错误检测和重传机制。 ...

    C#与PLC进行ModbusRTU通信源码

    本资源提供了一个C#与PLC进行ModbusRTU通信的源码实例,对于学习或实践此类通信方式的开发者,无论新手还是有经验者,都极具价值。以下将详细介绍该主题的相关知识点: 1. **C#编程语言**:C#是由微软公司开发的一...

    S7-1500 Modbus-RTU使用快速入门(更新版).zip

    Modbus-RTU作为工业设备间通信的通用协议,能够使S7-1500 PLC与其他支持Modbus协议的设备进行数据交换,极大地扩展了系统的应用范围。本指南将详细介绍如何在S7-1500 PLC上配置和使用Modbus-RTU通信。 首先,理解...

    西门子PLC程序源码-s7-200 modbus主、从站例子程序.zip

    该压缩包“西门子PLC程序源码-s7-200 modbus主、从站例子程序.zip”提供了S7-200 PLC进行Modbus通信的源代码示例,这对于理解和实现基于Modbus协议的设备间通信非常有帮助。 **Modbus协议概述** Modbus是一种通用的...

    西门子PLC例程-MOBUS RTU CRC码 STEP 7 程序.zip.zip

    在这个特定的压缩包"西门子PLC例程-MOBUS RTU CRC码 STEP 7 程序.zip.zip"中,包含了与西门子PLC编程相关的实例,特别是关于MODBUS RTU通信协议和CRC校验码的实现,以及使用STEP 7编程软件的相关程序。 1. **MODBUS...

    S7-200smart与2个仪表MODBUS RTU轮询

    总的来说,S7-200 SMART与MODBUS RTU仪表的轮询通信涉及了PLC编程、MODBUS通信协议、轮询策略和错误处理等多个方面。熟练掌握这些技能,可以有效地实现PLC与多种仪表的交互,提高工业自动化系统的灵活性和可靠性。

    S7-1200 Modbus RTU 主从通讯例程(主站轮询)

    4. **数据解析**:根据Modbus RTU协议解析从站返回的数据,将其转化为PLC可理解的格式。 5. **数据同步**:确保主站与从站的数据一致性,避免因通信问题导致系统错误。 综上所述,S7-1200 PLC的Modbus RTU主从通信...

    s7-200 modbus rtu LABVIEW 通讯

    标题 "s7-200 modbus rtu LABVIEW 通讯" 描述的是一个使用 LABVIEW 软件实现与西门子S7-200 PLC(可编程逻辑控制器)进行 Modbus RTU 协议通信的过程。在这个场景中,LABVIEW 作为一个图形化编程环境,用于创建...

    S7-1500Modbus-RTU

    然而,该系列PLC并不直接支持Modbus RTU(Remote Terminal Unit)协议,这是一种广泛应用的串行通信协议,主要用于工业设备之间的通信。不过,用户可以通过编写程序来实现S7-1500与支持Modbus RTU设备之间的通信。 ...

    S7200PLC MODBUS RTU协议

    通过上述介绍,我们可以了解到西门子S7-200 PLC如何通过MODBUS RTU协议进行RS485通信的基本配置方法及几种常用功能码的具体应用。这为工程师们在设计自动化系统时提供了重要的参考依据。需要注意的是,在实际应用...

    西门子PLC200与台达变频器通信程序示例modbus RTU.rar

    4. "西门子PLC200与台达变频器通信程序示例modbus RTU" - 这个文件很可能是具体的示例代码,演示了如何设置PLC200的Modbus RTU通信参数,以及如何发送和接收指令到台达变频器。它可能包括了如何配置PLC的输入/输出...

    西门子S7-1200PLC与V20变频器进行MODBUS RTU通信步骤详解.docx

    西门子S7-1200 PLC与V20变频器之间的MODBUS RTU通信是一种常见的工业自动化系统中的通信方式,它允许PLC控制变频器的运行状态...总的来说,理解MODBUS RTU通信协议和熟悉西门子PLC及变频器的编程是实现这种通信的关键。

    西门子PLC例程-S7-200 Modbus从站通讯测试.zip

    西门子S7-200系列PLC可以通过其内置的通讯模块支持Modbus RTU协议,该协议是Modbus协议的一种变体,适合于RS-485网络。在S7-200中,使用自由口通信(Free Port Communication)功能来实现Modbus RTU协议。自由口通信...

    S7-200SMART与1个仪表MODBUS RTU通讯.rar

    描述中的“200SMART与1个仪表MODBUS RTU通讯”表明我们将讨论如何使用S7-200SMART PLC与一个支持MODBUS RTU协议的仪表进行通信。这通常涉及到配置PLC的通讯端口,设置MODBUS地址,以及编写通讯程序来读取或写入仪表...

    S7-200SMART标准化程序(含MODBUS RTU轮询+可重复调用子程序+注释说明使用方法).rar

    《S7-200SMART标准化程序:MODBUS RTU轮询与子程序的应用解析》 在工业自动化领域,西门子的S7-200SMART系列PLC以其高效、灵活的特点广受青睐。本资源集合了一份针对S7-200SMART的标准化程序,其中包含了MODBUS RTU...

    s7-200做Modbus RTU.rar

    本教程将详细解析如何利用西门子S7-200 PLC进行Modbus RTU通信。 首先,我们要了解Modbus RTU的基本概念。Modbus是一种开放的通信协议,由Modicon(现属于施耐德电气)于1979年推出,主要用于工业设备之间的通信。...

Global site tag (gtag.js) - Google Analytics