西门子通讯协议-S7COMM报文

news/2024/9/28 9:23:22

     - (1)建立TCP连接      Socket.Connect

     - (2)发送访问请求     COTP

     - (3)交换通信信息     Setup Communication

     - (4)执行相关操作     读、写、PLC启停、时间、上传下载

一、CTOP请求连接

static void Main(string[] args)
{Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//socket.Connect("192.168.2.1", 102);      // 200Smartsocket.Connect("192.168.151.200", 102);// 1500
}COTP(socket);// 如果需要判断是否连接成功:通过异常捕获static void COTP(Socket socket)
{List<byte> bytes = new List<byte>();// TPKTbytes.Add(0x03);bytes.Add(0x00);bytes.Add(0x00);bytes.Add(0x16);// COTPbytes.Add(0x11);//   10#17bytes.Add(0xe0);bytes.Add(0x00);bytes.Add(0x00);bytes.Add(0x00);bytes.Add(0x00);bytes.Add(0x00);bytes.Add(0xc0);bytes.Add(0x01);bytes.Add(0x0a);bytes.Add(0xc1);   // 源设备(上位机PC)通信配置      S7协议   西门子设备之间也是要使用bytes.Add(0x02);bytes.Add(0x01);   //[17]bytes.Add(0x00);   //[18]bytes.Add(0xc2);   // PLC   bytes.Add(0x02);bytes.Add(0x03);   // [21]bytes.Add(0x01);   // [22] 机架号0  插槽号1socket.Send(bytes.ToArray(), 0, bytes.Count, SocketFlags.None);
}

TCP为Socket对象的三次握手,发送COTP连接请求后收到PLC的响应报文。

二、SetupCommunication通讯数据交换

 

PLC响应数据:S7-Parameter-PDU length  240,表示PLC最大处理数据能力为240个字节

static void SetupCommunication(Socket socket)
{List<byte> reqBytes = new List<byte>();// TPKTreqBytes.Add(0x03);reqBytes.Add(0x00);reqBytes.Add(0x00);reqBytes.Add(0x19);// COTPreqBytes.Add(0x02);reqBytes.Add(0xf0);reqBytes.Add(0x80);   // 1000 0000// S7-HeaderreqBytes.Add(0x32);reqBytes.Add(0x01);reqBytes.Add(0x00);reqBytes.Add(0x00);reqBytes.Add(0x00);reqBytes.Add(0x00);reqBytes.Add(0x00);reqBytes.Add(0x08);// Paremeter部分字节长度reqBytes.Add(0x00);reqBytes.Add(0x00);// Data部分字节长度// S7-ParameterreqBytes.Add(0xf0);// FunctionreqBytes.Add(0x00);reqBytes.Add(0x00);reqBytes.Add(0x03);// CallingreqBytes.Add(0x00);reqBytes.Add(0x03);// CalledreqBytes.Add(0x03);reqBytes.Add(0xc0);// PDUsocket.Send(reqBytes.ToArray(), 0, reqBytes.Count, SocketFlags.None);
}

三、S7COMM-Read报文

TPKT-整个请求字节数:后台会自动修改

Item[*]-数据块编号:请求数据地址为DB数据块时为DB数据块编号,请求其他数据时写0;

Item[*]-数据地址:举例M100.3的位置100.3表示为

单次读响应报文

static void Read(Socket socket)
{List<byte> reqBytes = new List<byte>();// TPKTreqBytes.Add(0x03);reqBytes.Add(0x00);// 初始化无意义,只做点位,后续做修改  ,注意第161行reqBytes.Add(0x00);reqBytes.Add(0x19);// 注意下后台再修改---// COTPreqBytes.Add(0x02);reqBytes.Add(0xf0);reqBytes.Add(0x80);   // 1000 0000// S7-HeaderreqBytes.Add(0x32);reqBytes.Add(0x01);// ROSCTRreqBytes.Add(0x00);reqBytes.Add(0x00);reqBytes.Add(0x00);reqBytes.Add(0x00);reqBytes.Add(0x00);reqBytes.Add(0x0e);// Paremeter部分字节长度。注意后面修改reqBytes.Add(0x00);reqBytes.Add(0x00);// Data部分字节长度// S7-ParameterreqBytes.Add(0x04);// FunctionreqBytes.Add(0x01);// Item的个数reqBytes.AddRange(ItemQ0_4());// 组装请求Q0.4的Itemushort len = (ushort)reqBytes.Count;byte[] lenBytes = BitConverter.GetBytes(len);// 小端reqBytes[2] = lenBytes[1];reqBytes[3] = lenBytes[0];// socket.Send(reqBytes.ToArray(), 0, reqBytes.Count, SocketFlags.None);
}// Q0.4  位  Q区0号字节中的4号位
static List<byte> ItemQ0_4()
{List<byte> items = new List<byte>();items.Add(0x12);items.Add(0x0a);items.Add(0x10);items.Add(0x01);items.Add(0x00);items.Add(0x01);//请求一个items.Add(0x00);items.Add(0x00);items.Add(0x82);// 地址计算int byteAddr = 0;byte bitAddr = 4;byteAddr = (byteAddr << 3) + bitAddr;//BitConverter.GetBytes(byteAddr);  // [0][1][2][]//  /256  进行计算items.Add((byte)(byteAddr / 256 / 256 % 256));items.Add((byte)(byteAddr / 256 % 256));items.Add((byte)(byteAddr % 256));return items;
}
static List<byte> ItemMB10()
{List<byte> items = new List<byte>();items.Add(0x12);items.Add(0x0a);items.Add(0x10);items.Add(0x02);// Byte  - 0x02items.Add(0x00);items.Add(0x03);//请求三个   MB0  MB1  MB2items.Add(0x00);items.Add(0x00);items.Add(0x83);  //Q区// 地址计算int byteAddr = 10;byte bitAddr = 0;byteAddr = (byteAddr << 3) + bitAddr;//BitConverter.GetBytes(byteAddr);  // [0][1][2][]//  /256  进行计算items.Add((byte)(byteAddr / 256 / 256 % 256));items.Add((byte)(byteAddr / 256 % 256));items.Add((byte)(byteAddr % 256));return items;
}
static List<byte> ItemDBD2()
{List<byte> items = new List<byte>();items.Add(0x12);items.Add(0x0a);items.Add(0x10);items.Add(0x06);// DWord  - 0x06items.Add(0x00);items.Add(0x01);//请求一个items.Add(0x00);items.Add(0x01);// DB编号items.Add(0x84);  //DB区// 地址计算int byteAddr = 2;byte bitAddr = 0;byteAddr = (byteAddr << 3) + bitAddr;//BitConverter.GetBytes(byteAddr);  // [0][1][2][]//  /256  进行计算items.Add((byte)(byteAddr / 256 / 256 % 256));items.Add((byte)(byteAddr / 256 % 256));items.Add((byte)(byteAddr % 256));return items;
}

请求地址MB10读取一个B返回的数据长度为一个字节时,PLC响应的数据长度为0x08,数据长度位数。

 

连续读响应报文

连续请求返回的数据不为最后一个且位奇数字节时,会出现占位字节

下图位连续请求两个Q区单位数据时PLC的响应报文

请求的即将返回长度<PDU(PLC最大处理数据量,通过数据交换通讯获取)

/// 关于Fill Byte:
/// 明确:读请求的时候   可以进行多个Item的分组  
///     比如:第一个Item  Q0.4(1)     返回Data中一个字节
///           第二个Item  MW10(1)     返回Data中二个字节  ,不管请求多少都是偶数个
///           第三个Item  MB5(3)      返回Data中一个字节 , 
///           第四个Item  MB1(1)      返回Data中一个字节
///           Parameter中请求三个Item   Data中分别响应三个Item
/// Item[1]   1Byte     奇数个   需要填充
/// Item[2]   2Byte     偶数个   不需要填充
/// Item[3]   3Byte     奇数个   需要填充
/// Item[4]   1Byte     奇数个   不需要填充
/// 结论:
/// 1、返回的Data中的Item是否在最后一个
/// 2、返回的Data中的Item中的数据字节数是否奇数个
/// 如果前两条件满足,则添加Fill Byte

连续请求示例:

static void Read(Socket socket)
{List<byte> reqBytes = new List<byte>();// TPKTreqBytes.Add(0x03);reqBytes.Add(0x00);// 初始化无意义,只做点位,后续做修改  ,注意第161行reqBytes.Add(0x00);reqBytes.Add(0x00);// 注意下后台再修改---// COTPreqBytes.Add(0x02);reqBytes.Add(0xf0);reqBytes.Add(0x80);   // 1000 0000// S7-HeaderreqBytes.Add(0x32);reqBytes.Add(0x01);// ROSCTRreqBytes.Add(0x00);reqBytes.Add(0x00);reqBytes.Add(0x00);reqBytes.Add(0x00);reqBytes.Add(0x00);reqBytes.Add(0x26);// Paremeter部分字节长度。注意后面修改    14   26   1A     38  26reqBytes.Add(0x00);reqBytes.Add(0x00);// Data部分字节长度// S7-ParameterreqBytes.Add(0x04);// FunctionreqBytes.Add(0x03);// Item的个数reqBytes.AddRange(ItemQ0_4());// 组装请求Q0.4的Item//reqBytes.AddRange(ItemMB10());// 组装请求MB10的Item//reqBytes.AddRange(ItemVW100());// 组装请求VW100的Item//reqBytes.AddRange(ItemVD0());// 组装请求VD0的Item//reqBytes.AddRange(ItemDBD2());// 组装请求VD0的Itemushort len = (ushort)reqBytes.Count;byte[] lenBytes = BitConverter.GetBytes(len);// 小端reqBytes[2] = lenBytes[1];reqBytes[3] = lenBytes[0];// socket.Send(reqBytes.ToArray(), 0, reqBytes.Count, SocketFlags.None);
}
static List<byte> ItemQ0_4()
{List<byte> items = new List<byte>();#region Q0.4items.Add(0x12);items.Add(0x0a);items.Add(0x10);items.Add(0x01);items.Add(0x00);items.Add(0x01);//请求一个   Q0.4  Q0.5  Q0.6    结果:返回异常。如何一个// 1、按字节、字、双字的方式一个次请求// 2、要求一个Item一个Bit     多个Itemitems.Add(0x00);items.Add(0x00);items.Add(0x82);  //Q区// 地址计算int byteAddr = 0;byte bitAddr = 4;byteAddr = (byteAddr << 3) + bitAddr;// int   [3][2][1][0]//BitConverter.GetBytes(byteAddr);  // [0][1][2][]//  /256  进行计算items.Add((byte)(byteAddr / 256 / 256 % 256));items.Add((byte)(byteAddr / 256 % 256));items.Add((byte)(byteAddr % 256));#endregion#region MW10items.Add(0x12);items.Add(0x0a);items.Add(0x10);items.Add(0x04);items.Add(0x00);items.Add(0x01);//请求一个 items.Add(0x00);items.Add(0x00);items.Add(0x83);  //M区// 地址计算byteAddr = 10;bitAddr = 0;byteAddr = (byteAddr << 3) + bitAddr;//BitConverter.GetBytes(byteAddr);  // [0][1][2][]//  /256  进行计算items.Add((byte)(byteAddr / 256 / 256 % 256));items.Add((byte)(byteAddr / 256 % 256));items.Add((byte)(byteAddr % 256));#endregion#region MB10items.Add(0x12);items.Add(0x0a);items.Add(0x10);items.Add(0x02);items.Add(0x00);items.Add(0x01);//请求一个 items.Add(0x00);items.Add(0x00);items.Add(0x83);  //M区// 地址计算byteAddr = 10;bitAddr = 0;byteAddr = (byteAddr << 3) + bitAddr;//BitConverter.GetBytes(byteAddr);  // [0][1][2][]//  /256  进行计算items.Add((byte)(byteAddr / 256 / 256 % 256));items.Add((byte)(byteAddr / 256 % 256));items.Add((byte)(byteAddr % 256));#endregion#region MB1items.Add(0x12);items.Add(0x0a);items.Add(0x10);items.Add(0x02);items.Add(0x00);items.Add(0x01);//请求一个 items.Add(0x00);items.Add(0x00);items.Add(0x83);  //Q区// 地址计算byteAddr = 1;bitAddr = 0;byteAddr = (byteAddr << 3) + bitAddr;//BitConverter.GetBytes(byteAddr);  // [0][1][2][]//  /256  进行计算items.Add((byte)(byteAddr / 256 / 256 % 256));items.Add((byte)(byteAddr / 256 % 256));items.Add((byte)(byteAddr % 256));#endregionreturn items;
}

字符串读取

static void ReadString(Socket socket)
{List<byte> reqBytes = new List<byte>();// TPKTreqBytes.Add(0x03);reqBytes.Add(0x00);// 初始化无意义,只做点位,后续做修改  ,注意第161行reqBytes.Add(0x00);reqBytes.Add(0x00);// 注意下后台再修改---// COTPreqBytes.Add(0x02);reqBytes.Add(0xf0);reqBytes.Add(0x80);   // 1000 0000// S7-HeaderreqBytes.Add(0x32);reqBytes.Add(0x01);// ROSCTRreqBytes.Add(0x00);reqBytes.Add(0x00);reqBytes.Add(0x00);reqBytes.Add(0x00);reqBytes.Add(0x00);reqBytes.Add(0x0e);// Paremeter部分字节长度。注意后面修改    14   26   1A   reqBytes.Add(0x00);reqBytes.Add(0x00);// Data部分字节长度// S7-ParameterreqBytes.Add(0x04);// FunctionreqBytes.Add(0x01);// Item的个数reqBytes.AddRange(ParamString());// 组装请求Q0.4的Itemushort len = (ushort)reqBytes.Count;byte[] lenBytes = BitConverter.GetBytes(len);// 小端reqBytes[2] = lenBytes[1];reqBytes[3] = lenBytes[0];// socket.Send(reqBytes.ToArray(), 0, reqBytes.Count, SocketFlags.None);
}
//DB1.DBB6
static List<byte> ParamString()
{List<byte> items = new List<byte>();items.Add(0x12);items.Add(0x0a);items.Add(0x10);items.Add(0x03);// Charitems.Add(0x00);items.Add(0x07);//请求五个items.Add(0x00);items.Add(0x01);// DB编号items.Add(0x84);  //DB区// 地址计算int byteAddr = 6;byte bitAddr = 0;byteAddr = (byteAddr << 3) + bitAddr;//BitConverter.GetBytes(byteAddr);  // [0][1][2][]//  /256  进行计算items.Add((byte)(byteAddr / 256 / 256 % 256));items.Add((byte)(byteAddr / 256 % 256));items.Add((byte)(byteAddr % 256));return items;
}

请求字符串数据时需要加增加两个读取位置;

PLC响应返回的数据中前两个0a代表DB块中分配的控件,05表示当前所存的字符长度;

四、S7COMM-Write报文

单次写响应报文

static void Write(Socket socket)
{List<byte> reqBytes = new List<byte>();// TPKTreqBytes.Add(0x03);reqBytes.Add(0x00);// 初始化无意义,只做点位,后续做修改  ,注意第161行reqBytes.Add(0x00);reqBytes.Add(0x00);// 注意下后台再修改---// COTPreqBytes.Add(0x02);reqBytes.Add(0xf0);reqBytes.Add(0x80);   // 1000 0000// S7-HeaderreqBytes.Add(0x32);reqBytes.Add(0x01);// ROSCTRreqBytes.Add(0x00);reqBytes.Add(0x00);reqBytes.Add(0x00);reqBytes.Add(0x00);//reqBytes.Add(0x00);//reqBytes.Add(0x26);// Paremeter部分字节长度。注意后面修改    14   26   1A     38  26//reqBytes.Add(0x00);//reqBytes.Add(0x00);// Data部分字节长度List<byte> paramList = ParameterItemM0_0();//List<byte> paramList = ParameterItemVW10();ushort pl = (ushort)paramList.Count;byte[] plenBytes = BitConverter.GetBytes(pl);reqBytes.Add(plenBytes[1]);reqBytes.Add(plenBytes[0]);List<byte> dataList = DataItemM0_0();//List<byte> dataList = DataItemVW10();ushort dl = (ushort)dataList.Count;byte[] dlenBytes = BitConverter.GetBytes(dl);reqBytes.Add(dlenBytes[1]);reqBytes.Add(dlenBytes[0]);// reqBytes.AddRange(paramList);reqBytes.AddRange(dataList);ushort len = (ushort)reqBytes.Count;byte[] lenBytes = BitConverter.GetBytes(len);reqBytes[2] = lenBytes[1];reqBytes[3] = lenBytes[0];// socket.Send(reqBytes.ToArray(), 0, reqBytes.Count, SocketFlags.None);
}
static List<byte> ParameterItemM0_0()
{List<byte> items = new List<byte>();items.Add(0x05);//功能码:写入动作items.Add(0x01);// Items的个数  Data的Item个数据与Parameter的Item个数匹配items.Add(0x12);items.Add(0x0a);items.Add(0x10);items.Add(0x01);items.Add(0x00);items.Add(0x01);items.Add(0x00);items.Add(0x00);items.Add(0x83);  //Q区// 地址计算int byteAddr = 0;byte bitAddr = 0;byteAddr = (byteAddr << 3) + bitAddr;items.Add((byte)(byteAddr / 256 / 256 % 256));items.Add((byte)(byteAddr / 256 % 256));items.Add((byte)(byteAddr % 256));return items;
}static List<byte> DataItemM0_0()
{List<byte> items = new List<byte>();items.Add(0x00);items.Add(0x03);items.Add(0x00);items.Add(0x01);items.Add(0x01);// 表示写入数据,Bit(0x00   0x01)return items;
}
static List<byte> ParameterItemVW10()
{List<byte> items = new List<byte>();items.Add(0x05);//功能码:写入动作items.Add(0x01);// Items的个数  Data的Item个数据与Parameter的Item个数匹配items.Add(0x12);items.Add(0x0a);items.Add(0x10);items.Add(0x04);items.Add(0x00);items.Add(0x02);items.Add(0x00);items.Add(0x01);items.Add(0x84);  //Q区// 地址计算int byteAddr = 10;byte bitAddr = 0;byteAddr = (byteAddr << 3) + bitAddr;items.Add((byte)(byteAddr / 256 / 256 % 256));items.Add((byte)(byteAddr / 256 % 256));items.Add((byte)(byteAddr % 256));return items;
}static List<byte> DataItemVW10()
{List<byte> items = new List<byte>();items.Add(0x00);items.Add(0x04);items.Add(0x00);items.Add(0x20);// 写入的位数items.Add(0x00);items.Add(0x7b);// 表示写入数据items.Add(0x00);items.Add(0x7c);// 表示写入数据return items;
}

 连续写响应报文

static void Write(Socket socket)
{List<byte> reqBytes = new List<byte>();// TPKTreqBytes.Add(0x03);reqBytes.Add(0x00);// 初始化无意义,只做点位,后续做修改  ,注意第161行reqBytes.Add(0x00);reqBytes.Add(0x00);// 注意下后台再修改---// COTPreqBytes.Add(0x02);reqBytes.Add(0xf0);reqBytes.Add(0x80);   // 1000 0000// S7-HeaderreqBytes.Add(0x32);reqBytes.Add(0x01);// ROSCTRreqBytes.Add(0x00);reqBytes.Add(0x00);reqBytes.Add(0x00);reqBytes.Add(0x00);//reqBytes.Add(0x00);//reqBytes.Add(0x26);// Paremeter部分字节长度。注意后面修改    14   26   1A     38  26//reqBytes.Add(0x00);//reqBytes.Add(0x00);// Data部分字节长度//List<byte> paramList = ParameterItemM0_0();//List<byte> paramList = ParameterItemVW10();List<byte> paramList = ParameterItemMulit();ushort pl = (ushort)paramList.Count;byte[] plenBytes = BitConverter.GetBytes(pl);reqBytes.Add(plenBytes[1]);reqBytes.Add(plenBytes[0]);//List<byte> dataList = DataItemM0_0();//List<byte> dataList = DataItemVW10();List<byte> dataList = DataItemMulit();ushort dl = (ushort)dataList.Count;byte[] dlenBytes = BitConverter.GetBytes(dl);reqBytes.Add(dlenBytes[1]);reqBytes.Add(dlenBytes[0]);// reqBytes.AddRange(paramList);reqBytes.AddRange(dataList);ushort len = (ushort)reqBytes.Count;byte[] lenBytes = BitConverter.GetBytes(len);reqBytes[2] = lenBytes[1];reqBytes[3] = lenBytes[0];// socket.Send(reqBytes.ToArray(), 0, reqBytes.Count, SocketFlags.None);
}
static List<byte> ParameterItemMulit()
{List<byte> items = new List<byte>();items.Add(0x05);//功能码:写入动作items.Add(0x03);// Items的个数  Data的Item个数据与Parameter的Item个数匹配// VB10items.Add(0x12);items.Add(0x0a);items.Add(0x10);items.Add(0x02);// 类型 02 Byte   03  Char   04 Word   06  DWorditems.Add(0x00);items.Add(0x01);// 写一个值items.Add(0x00);items.Add(0x01);items.Add(0x84);  //V// 地址计算int byteAddr = 10;byte bitAddr = 0;byteAddr = (byteAddr << 3) + bitAddr;items.Add((byte)(byteAddr / 256 / 256 % 256));items.Add((byte)(byteAddr / 256 % 256));items.Add((byte)(byteAddr % 256));// VB100 VB101   VB102 VB103// VW100         VW102//items = new List<byte>();items.Add(0x12);items.Add(0x0a);items.Add(0x10);items.Add(0x04);// 类型 02 Byte   03  Char   04 Word   06  DWorditems.Add(0x00);items.Add(0x02);// 写一个值items.Add(0x00);items.Add(0x01);items.Add(0x84);  //V// 地址计算byteAddr = 100;bitAddr = 0;byteAddr = (byteAddr << 3) + bitAddr;items.Add((byte)(byteAddr / 256 / 256 % 256));items.Add((byte)(byteAddr / 256 % 256));items.Add((byte)(byteAddr % 256));// VD110//items = new List<byte>();items.Add(0x12);items.Add(0x0a);items.Add(0x10);items.Add(0x06);// 类型 02 Byte   03  Char   04 Word   06  DWorditems.Add(0x00);items.Add(0x01);// 写一个值items.Add(0x00);items.Add(0x01);items.Add(0x84);  //V// 地址计算byteAddr = 110;bitAddr = 0;byteAddr = (byteAddr << 3) + bitAddr;items.Add((byte)(byteAddr / 256 / 256 % 256));items.Add((byte)(byteAddr / 256 % 256));items.Add((byte)(byteAddr % 256));return items;
}static List<byte> DataItemMulit()
{// VB10   Byte  List<byte> items = new List<byte>();items.Add(0x00);items.Add(0x04);//Byte/Word/DWorditems.Add(0x00);items.Add(0x08);// 写入的位数items.Add(0x0a);//10#10items.Add(0x00);// Fill byte  当出现奇数个字节   需要填充// VW100  VW102    123   7B   124   7Citems.Add(0x00);items.Add(0x04);//Byte/Word/DWorditems.Add(0x00);items.Add(0x20);// 写入的位数    2个字   4个字节   10#32位   16#20items.Add(0x00);//items.Add(0x7b);//10#123items.Add(0x00);//items.Add(0x7c);//10#124// VD110   4.5     40 90 00 00items.Add(0x00);items.Add(0x04);items.Add(0x00);items.Add(0x20);items.Add(0x40);items.Add(0x90);items.Add(0x00);items.Add(0x00);return items;
}

与对于奇数字节的数据需要手动调整占位字节

 字符串写入

测试PLC为西门子200,西门子1200/1500写入,需要再字符Byte前必须添加两个字节:

1.0x00 空间  一般大于等于字符数即可,小于不行

2.0x00 字符数 

static void S7String(Socket socket)
{// // 针对Byte数据进行处理List<byte> reqBytes = new List<byte>();// TPKTreqBytes.Add(0x03);reqBytes.Add(0x00);// 初始化无意义,只做点位,后续做修改  ,注意第161行reqBytes.Add(0x00);reqBytes.Add(0x00);// 注意下后台再修改---// COTPreqBytes.Add(0x02);reqBytes.Add(0xf0);reqBytes.Add(0x80);   // 1000 0000// S7-HeaderreqBytes.Add(0x32);reqBytes.Add(0x01);// ROSCTRreqBytes.Add(0x00);reqBytes.Add(0x00);reqBytes.Add(0x00);reqBytes.Add(0x00);// ParameterList<byte> paramList = ParameterItemString();ushort pl = (ushort)paramList.Count;byte[] plenBytes = BitConverter.GetBytes(pl);reqBytes.Add(plenBytes[1]);reqBytes.Add(plenBytes[0]);// DataList<byte> dataList = DataItemString();ushort dl = (ushort)dataList.Count;byte[] dlenBytes = BitConverter.GetBytes(dl);reqBytes.Add(dlenBytes[1]);reqBytes.Add(dlenBytes[0]);// reqBytes.AddRange(paramList);reqBytes.AddRange(dataList);ushort len = (ushort)reqBytes.Count;byte[] lenBytes = BitConverter.GetBytes(len);reqBytes[2] = lenBytes[1];reqBytes[3] = lenBytes[0];// socket.Send(reqBytes.ToArray(), 0, reqBytes.Count, SocketFlags.None);
}static List<byte> ParameterItemString()
{List<byte> items = new List<byte>();items.Add(0x05);//功能码:写入动作items.Add(0x01);// Items的个数  Data的Item个数据与Parameter的Item个数匹配// VB20items.Add(0x12);items.Add(0x0a);items.Add(0x10);items.Add(0x03);// 类型 02 Byte   03  Char   04 Word   06  DWorditems.Add(0x00);items.Add(0x05);// 写一个值items.Add(0x00);items.Add(0x01);items.Add(0x84);  //V// 地址计算int byteAddr = 20;byte bitAddr = 0;byteAddr = (byteAddr << 3) + bitAddr;items.Add((byte)(byteAddr / 256 / 256 % 256));items.Add((byte)(byteAddr / 256 % 256));items.Add((byte)(byteAddr % 256));return items;
}
static List<byte> DataItemString()
{string str = "Hello";byte[] strBytes = Encoding.UTF8.GetBytes(str);List<byte> items = new List<byte>();items.Add(0x00);items.Add(0x09);// Stringint bitCount = strBytes.Length;items.Add(BitConverter.GetBytes(bitCount)[1]);items.Add(BitConverter.GetBytes(bitCount)[0]);// 写入的位数items.AddRange(strBytes);return items;
}

五、S7COMM-其他功能报文

PLC   200Smart      并不对所有PLC有效    1200  1500 无法操作
 Step7    s7   0x32标准协议   对200Smart进行操作
博途     S7   0x72标准协议   对1200   1500
区别:结构变化很大    72 包含的内容更多

S7COMM通讯限制:

PLC  Run 请求与响应

static void Run(Socket socket)
{string s = "P_PROGRAM";byte[] sb = Encoding.ASCII.GetBytes(s);byte[] runBytes = new byte[] {// TPKT0x03,0x00,0x00,0x25,// COTP0x02,0xf0,0x80,// Header0x32,0x01,0x00,0x00,0x00,0x00,// PL0x00,0x14,// DL0x00,0x00,// Parameter0x28,  // 启动标识0x00,0x00,0x00,0x00,0x00,0x00,0xfd,0x00, 0x00,0x09,// P_PROGRAM  9个字符对应的16进制Ascii值0x50,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d};try{socket.Send(runBytes);int count = socket.Receive(new byte[20]);}catch (Exception ex){}
}

PLC  Stop请求与响应

static void Stop(Socket socket)
{byte[] stopBytes = new byte[] {// TPKT0x03,0x00,0x00,0x21,// COTP0x02,0xf0,0x80,// Header0x32,0x01,0x00,0x00,0x00,0x00,// PL0x00,0x10,// DL0x00,0x00,// Parameter0x29,// Stop标识0x00,0x00,0x00,0x00,0x00,0x09,// P_PROGRAM  9个字符对应的16进制Ascii值0x50,0x5f,0x50,0x52,0x4f,0x47,0x52,0x41,0x4d};socket.Send(stopBytes);
}

时间获取与设置请求与响应

static void ReadTime(Socket socket)
{byte[] readTimeBytes = new byte[] {// TPKT0x03,0x00,0x00,0x1d,// COTP0x02,0xf0,0x80,// Header0x32,0x07, // UserData0x00,0x00,0x00,0x00,// PL0x00,0x08,// DL0x00,0x04,// Parameter0x00,0x01,0x12,0x04,// Parameter中当前字节后的字节数0x11, 0x47,0x01,// SubFunction  Read Clock0x00,// Data0x0a,0x00,0x00,0x00};socket.Send(readTimeBytes);
}

PLC响应数据:

Year 1:值为90-99时表示19XX年,否则表示20XX年;

获取的数据是16进制,需要直接转成10进制,例如Year2表示22年数据是16#22需要直接转为10#22而不是10#34;

六、附录:

附录1:COTP->PDU type已知枚举值

附录2:S7Header->ROSCTR已知枚举值

附录3:S7Header->Error class已知枚举值

附录4:S7Parameter->Error code已知枚举值

附录5:S7Parameter->Function已知枚举值

附录6:S7Parameter->Item->Syntax Id已知枚举值

附录7:S7Parameter->Item->Transport size常见值

附录8:S7Parameter->Item->Area常见值

附录9:S7Data->Item->Return code已知枚举值

附录10:Userdata已知枚举值

附录11:PI service names已知枚举值

附录14:SZL-ID 类型

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/30302.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

专业商用远程控制软件,低至10元每月

如今不论工作还是生活,远程控制软件已成为我们的必备工具。说到远程软件,市面上有很多款。但“个人免费版”,往往会有限速、卡顿、不清晰等问题;商业版很强大,但普遍价格昂贵。那么有没有既便宜又专业的商业级远控软件呢? 现在,它来了,它来了! Splashtop 家族的商业版…

应用模式启动

与单作业模式类似,直接执行flink run-application命令$ bin/flink run-application -t yarn-application -c com.huft.flk117.demo.StreamSocketCnt job_jar/original-fk117-1.0-SNAPSHOT.jar 查看 web及yarn id 2.在命令行中查看或取消作业。 $ bin/flink list -t yarn-appli…

通义灵码企业版正式发布,满足企业私域知识检索、数据合规、统一管理等需求

5 月 9 日阿里云 AI 峰会,阿里云智能集团首席技术官周靖人宣布,通义灵码企业版正式发布,满足企业用户的定制化需求,帮助企业提升研发效率。5 月 9 日阿里云 AI 峰会,阿里云智能集团首席技术官周靖人宣布,通义灵码企业版正式发布,满足企业用户的定制化需求,帮助企业提升…

三分钟分享自定义表单系统开源的优势

利用低代码技术平台、自定义表单系统开源的优势特点,可以助力企业实现高效办公,降低人工成本。在数字化转型浪潮下,利用低代码技术平台、自定义表单系统开源的优势特点,可以助力企业实现高效办公,降低人工成本,从而进入流程化办公新时代。为了帮助大家了解相关信息,流辰…

Fastjson反序列化漏洞3:JdbcRowSetImpl利用链-JNDI注入

顺势找到setDataSourceName,有setter方法,可以使用fastjson为其添值第二条链 Fastjson的三条链,现在我们来讲第二条com.sun.rowset.JdbcRowSetImplcom.sun.rowset.JdbcRowSetImpl org.apache.tomcat.dbcp.dbcp2.BasicDataSourceFastjson的三条链,现在我们来看第二条com.sun…

Sychronized的锁升级过程是怎样的

`synchronized`关键字的锁升级过程是Java为了提高锁的性能,减少在无竞争或多线程轻度竞争情况下的开销而设计的一套机制。这一过程主要涉及以下四个阶段:1. 无锁状态:当一个对象刚创建时,并没有锁与其关联,处于无锁状态。 2. 偏向锁(Biased Locking):-初始化:当第一个…