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","ModbusRTU通信","轮询","主站读写"和"程序示例",这些关键词涵盖了这个主题的关键技术点: 1. **S7-200PLC**:这是西门子的一款小型PLC,具备编程简单、性价比高的特点,...
SIEMENS S7-1500PLC 实现 Modbus-RTU 通信配置步骤和程序编写详解 Modbus-RTU 通信是一种常见的工业通信协议,广泛应用于工业自动化领域。SIEMENS S7-1500PLC 是一种高性能的工业控制器,可以实现 Modbus-RTU 通信...
本篇文章将深入探讨如何在S7-200SMART PLC上实现Modbus RTU协议的轮询程序,包括读轮询和写优先策略,并提供详细的使用说明。 首先,了解Modbus RTU协议是理解整个程序的基础。Modbus是一种广泛应用的通信协议,...
- 实现方法:在S7-200SMART的编程软件中,使用PDU(协议数据单元)和MB_SERV指令来构建和解析MODBUS RTU帧。 2. **MODBUS TCP通信**: - 与MODBUS RTU的区别:TCP/IP协议栈增加了可靠性,如错误检测和重传机制。 ...
本资源提供了一个C#与PLC进行ModbusRTU通信的源码实例,对于学习或实践此类通信方式的开发者,无论新手还是有经验者,都极具价值。以下将详细介绍该主题的相关知识点: 1. **C#编程语言**:C#是由微软公司开发的一...
Modbus-RTU作为工业设备间通信的通用协议,能够使S7-1500 PLC与其他支持Modbus协议的设备进行数据交换,极大地扩展了系统的应用范围。本指南将详细介绍如何在S7-1500 PLC上配置和使用Modbus-RTU通信。 首先,理解...
该压缩包“西门子PLC程序源码-s7-200 modbus主、从站例子程序.zip”提供了S7-200 PLC进行Modbus通信的源代码示例,这对于理解和实现基于Modbus协议的设备间通信非常有帮助。 **Modbus协议概述** Modbus是一种通用的...
在这个特定的压缩包"西门子PLC例程-MOBUS RTU CRC码 STEP 7 程序.zip.zip"中,包含了与西门子PLC编程相关的实例,特别是关于MODBUS RTU通信协议和CRC校验码的实现,以及使用STEP 7编程软件的相关程序。 1. **MODBUS...
总的来说,S7-200 SMART与MODBUS RTU仪表的轮询通信涉及了PLC编程、MODBUS通信协议、轮询策略和错误处理等多个方面。熟练掌握这些技能,可以有效地实现PLC与多种仪表的交互,提高工业自动化系统的灵活性和可靠性。
4. **数据解析**:根据Modbus RTU协议解析从站返回的数据,将其转化为PLC可理解的格式。 5. **数据同步**:确保主站与从站的数据一致性,避免因通信问题导致系统错误。 综上所述,S7-1200 PLC的Modbus RTU主从通信...
标题 "s7-200 modbus rtu LABVIEW 通讯" 描述的是一个使用 LABVIEW 软件实现与西门子S7-200 PLC(可编程逻辑控制器)进行 Modbus RTU 协议通信的过程。在这个场景中,LABVIEW 作为一个图形化编程环境,用于创建...
然而,该系列PLC并不直接支持Modbus RTU(Remote Terminal Unit)协议,这是一种广泛应用的串行通信协议,主要用于工业设备之间的通信。不过,用户可以通过编写程序来实现S7-1500与支持Modbus RTU设备之间的通信。 ...
通过上述介绍,我们可以了解到西门子S7-200 PLC如何通过MODBUS RTU协议进行RS485通信的基本配置方法及几种常用功能码的具体应用。这为工程师们在设计自动化系统时提供了重要的参考依据。需要注意的是,在实际应用...
4. "西门子PLC200与台达变频器通信程序示例modbus RTU" - 这个文件很可能是具体的示例代码,演示了如何设置PLC200的Modbus RTU通信参数,以及如何发送和接收指令到台达变频器。它可能包括了如何配置PLC的输入/输出...
西门子S7-1200 PLC与V20变频器之间的MODBUS RTU通信是一种常见的工业自动化系统中的通信方式,它允许PLC控制变频器的运行状态...总的来说,理解MODBUS RTU通信协议和熟悉西门子PLC及变频器的编程是实现这种通信的关键。
西门子S7-200系列PLC可以通过其内置的通讯模块支持Modbus RTU协议,该协议是Modbus协议的一种变体,适合于RS-485网络。在S7-200中,使用自由口通信(Free Port Communication)功能来实现Modbus RTU协议。自由口通信...
描述中的“200SMART与1个仪表MODBUS RTU通讯”表明我们将讨论如何使用S7-200SMART PLC与一个支持MODBUS RTU协议的仪表进行通信。这通常涉及到配置PLC的通讯端口,设置MODBUS地址,以及编写通讯程序来读取或写入仪表...
《S7-200SMART标准化程序:MODBUS RTU轮询与子程序的应用解析》 在工业自动化领域,西门子的S7-200SMART系列PLC以其高效、灵活的特点广受青睐。本资源集合了一份针对S7-200SMART的标准化程序,其中包含了MODBUS RTU...
本教程将详细解析如何利用西门子S7-200 PLC进行Modbus RTU通信。 首先,我们要了解Modbus RTU的基本概念。Modbus是一种开放的通信协议,由Modicon(现属于施耐德电气)于1979年推出,主要用于工业设备之间的通信。...